Table of Contents
ToggleStage 1: Foundation
Format: Hands-On Live Project A–Z | aiseojournal.net | May 2026 Store: shopifystore1.co.uk | Platform: Shopify
SECTION 0 — PROJECT BRIEF & FOUNDATION FRAMEWORK
The Mistake That Makes Every Other Shopify SEO Investment Worthless
Most Shopify store owners start with content. They publish blog posts, write new product descriptions, and wonder why nothing ranks after six months.
The reason is almost always the same. The technical foundation is broken.
Google cannot confidently rank a store that has 400 duplicate product URLs from collection paths that lack canonical tags. It will not prioritise a store where Googlebot is spending 60% of its crawl budget on /collections/all, tag pages, and filter parameter URLs instead of the actual products. A store with a 4.8-second LCP on mobile is not going to appear in the top 10 for any competitive query regardless of how good the copy is — Core Web Vitals are a confirmed Google ranking signal.
Stage 1 fixes all of that. Before a single blog post is written. Before a single backlink is pursued.
Pro Tip: The Foundation stage is the only stage where the ROI is guaranteed. A fixed canonical conflict recovers suppressed ranking immediately. A noindexed /collections/all page reclaims crawl budget within days. A preloaded hero image moves a page from Needs Improvement to Good on LCP within one deployment. These fixes are deterministic — not probabilistic. Content and links are probabilistic. Technical fixes are certainties.
0.1 — Store Profile at Stage 1 Start
| Dimension | Value |
|---|---|
| Domain | https://www.shopifystore1.co.uk |
| Platform | Shopify (plan to be confirmed) |
| Theme | To be confirmed — run: /admin/themes |
| Installed apps | To be confirmed — Shopify Admin → Apps |
| Indexed pages (GSC) | To be confirmed — GSC → Coverage → Indexed |
| Monthly organic sessions | To be confirmed — GA4 baseline before any changes |
| Domain Rating | To be confirmed — Ahrefs |
| Primary product categories | [CONFIRM — e.g. 3 main categories, 12 collections, 180 products] |
| Blog posts published | To be confirmed |
| Reviews app | To be confirmed — Judge.me / Okendo / Yotpo / Shopify Reviews |
0.2 — Stage 1 Scope
Stage 1 does not create any new content. It does not pursue any backlinks. It does not touch conversion rate optimisation.
Stage 1 covers exactly six areas:
- Technical audit — every crawlability and indexability issue on the store
- Crawl budget optimisation — remove every URL that wastes Googlebot’s time
- Core Web Vitals remediation — all three metrics across all critical templates
- Schema deployment — Product, BreadcrumbList, Organization, and FAQPage
- GA4 + GSC setup — tracking confirmed before any optimisation begins
- On-page baseline — title tags, meta descriptions, H1s, and image alt text
0.3 — Stage 1 Delivery Timeline
| Section | Task | Estimated Hours |
|---|---|---|
| S0 | Project brief + store profile | 1 |
| S1 | Full technical audit | 6–8 |
| S2 | Crawl budget analysis + robots.txt | 2–3 |
| S3 | Core Web Vitals remediation plan | 4–6 |
| S4 | Schema library — all page types | 3–4 |
| S5 | GA4 + GSC setup + Key Event tracking | 2–3 |
| S6 | On-page baseline audit + fixes | 4–6 |
| S7 | 30-day action plan | 1 |
| Total | Stage 1 Foundation | ~23–32 hours |
✅ CHECKPOINT — SECTION 0
- [ ] Store profile confirmed — plan, theme, app list, indexed page count
- [ ] GA4 baseline recorded before any changes
- [ ] GSC domain property verified (domain, not URL prefix)
- [ ] Screaming Frog crawl scheduled (JS-disabled first pass, JS-enabled second)
- [ ] Lighthouse baseline run on: homepage / best-selling collection / best-selling product page
SECTION 1 — TECHNICAL SEO AUDIT
Why Shopify Technical SEO Has Unique Failure Modes
Shopify is not WordPress. The failure modes are different, the fixes are different, and the implementation path is entirely different.
The most common Shopify technical SEO mistake made by practitioners who come from a WordPress background: attempting to edit robots.txt as a flat file. Shopify does not support this. Any manually edited robots.txt file is overwritten by Shopify’s system on the next theme publish. The only way to customise Shopify’s robots.txt is via the Liquid API in the theme — a robots.txt.liquid template file.
Pro Tip: Run the Screaming Frog crawl with the user agent set to Googlebot, not the Screaming Frog default. Shopify serves different content to different user agents in some configurations — particularly when store password protection or geo-restrictions are active. A Googlebot-impersonated crawl shows exactly what Google sees, not what a browser or generic crawler sees.
1.1 — Crawl Configuration for shopifystore1.co.uk
Before running the technical audit, configure Screaming Frog correctly.
Screaming Frog settings:
- User agent: Googlebot
- JavaScript rendering: disabled for pass 1 (confirms server-side rendered content)
- JavaScript rendering: enabled for pass 2 (confirms dynamically rendered content matches)
- Custom extraction rules:
- Canonical URL: XPath
//link[@rel='canonical']/@href - hreflang (if multilingual): XPath
//link[@rel='alternate']/@hreflang - Schema types: XPath
//@type[parent::script[@type='application/ld+json']] - og:locale: XPath
//meta[@property='og:locale']/@content
- Canonical URL: XPath
- Crawl limit: set above expected total URL count (products + collections + blogs + pages + variants)
- Exclude: /cart, /account, /checkout, /search, /password (already in Shopify robots.txt)
1.2 — Technical Findings by Category
Category 1 — Indexability (Shopify-Specific)
Finding 1.2.1 — /collections/all: confirmed indexed or needs verification
Scale: 1 URL (but with potentially thousands of products populating it) Root cause: Shopify automatically creates /collections/all as a catch-all collection containing every product in the store. It is indexed by default. It competes directly with your best-structured collection pages for category-level queries and dilutes authority across the site.
Fix: Noindex /collections/all via Shopify robots.txt API. Add to robots.txt.liquid (create this file in Shopify Admin → Online Store → Themes → Edit Code):
Disallow: /collections/all
Alternatively, noindex at the page level via the collection’s SEO settings in Shopify Admin → Products → Collections → All → Edit website SEO → uncheck “Allow search engines to index this page” (if using a SEO app that supports this).
Owner: Developer or SEO Effort: Quick Win — 15 minutes Priority: 🔴 P1 — /collections/all actively competes with and dilutes your collection pages Dependency: Confirm /collections/all is currently indexed in GSC Coverage before acting Validation: GSC Coverage → Excluded → Blocked by robots.txt should show this URL within 7–14 days
Finding 1.2.2 — /collections/[handle]/[tag] tag pages: estimated X pages, all thin
Scale: Every tag applied to a product within a collection creates a /collections/[handle]/[tag] URL automatically. On a store with 12 collections and 20 product tags, this generates up to 240 tag-filter URLs — all thin (they contain only the subset of products that share the tag + collection combination).
Root cause: Shopify auto-generates tag pages. They cannot be deleted. They must be blocked or noindexed.
Fix: Block all tag pages via robots.txt.liquid:
Disallow: /collections/*/
Note: the trailing slash with wildcard blocks all tag-filtered collection URLs while allowing /collections/[handle]/ (without trailing wildcard path) to remain crawlable.
Confirm the syntax is correct by testing at: Google Search Central robots.txt tester.
Owner: Developer Effort: Quick Win — 15 minutes Priority: 🔴 P1 — tag pages consume crawl budget and create thin duplicate content Dependency: robots.txt.liquid file created in theme Validation: GSC Coverage → Excluded → Blocked by robots.txt count should increase by approximately the number of tag pages previously indexed
Finding 1.2.3 — Filter and sort parameter URLs: indexed or present in crawl
Scale: Every filter interaction on a collection page (/collections/[handle]?filter.p.m.colour=black, /collections/[handle]?sort_by=price-ascending) creates a unique URL. These are near-identical to the parent collection page but with a subset of products displayed. Google may index them as duplicate content.
Root cause: Shopify filter app (Search & Discovery, or third-party faceted search apps) creates these URLs. Default Shopify search & discovery filter URLs use the format ?filter.p.m.[attribute]=[value].
Fix: Block via robots.txt.liquid:
Disallow: /collections/*?sort_by=
Disallow: /collections/*?filter.
Additionally: confirm the canonical tag on all filtered collection pages points to the unfiltered /collections/[handle]/ URL. Most Shopify themes handle this automatically — verify via view source on a filtered URL.
Owner: Developer Effort: Quick Win — 20 minutes Priority: 🔴 P1 Dependency: robots.txt.liquid file in place Validation: Screaming Frog recrawl — filter/sort URLs should not appear in crawl output
Finding 1.2.4 — Product canonical tags: collection path vs canonical URL
Scale: Every product in the store is accessible via two URL patterns:
/products/[handle]— the canonical URL/collections/[handle]/products/[handle]— the collection path URL
Root cause: Shopify serves products via both paths. The canonical tag should always point to /products/[handle] regardless of which path was used to access the page. Most current Shopify themes (Dawn and later) handle this correctly — but some legacy or heavily customised themes do not.
Fix: View source on any product accessed via a collection URL (/collections/[handle]/products/[handle]). Confirm the canonical tag in the <head> reads:
<link rel="canonical" href="https://www.shopifystore1.co.uk/products/[handle]">
NOT:
<link rel="canonical" href="https://www.shopifystore1.co.uk/collections/[handle]/products/[handle]">
If the canonical is incorrect: fix in the theme’s product.liquid or product-template.liquid template:
<link rel="canonical" href="{{ canonical_url }}">
Shopify’s {{ canonical_url }} Liquid object always returns the /products/[handle] path — using it directly resolves the issue.
Owner: Developer Effort: Quick Win — 30 minutes (verify + fix if needed) Priority: 🔴 P1 — incorrect canonicals suppress product page rankings Dependency: Theme code access Validation: View source on 5 random products accessed via collection paths — all canonicals should read /products/[handle]
Finding 1.2.5 — Out-of-stock product strategy: undefined
Scale: Varies — confirm count of out-of-stock products in GSC Root cause: No defined strategy for what happens when a product goes out of stock on Shopify.
Three options — one must be chosen and applied consistently:
Option A: Keep indexed, allow backorder or pre-order Best for: core range products that regularly restock SEO impact: preserves all accumulated link equity and ranking history Shopify implementation: keep product published, add “Sold Out” message, enable backorder via Shopify inventory settings or a waitlist app
Option B: Keep indexed, add “notify me” CTA Best for: seasonal products or products with uncertain restock dates SEO impact: preserves ranking history, zero conversion loss (capture demand) Shopify implementation: use Klaviyo back-in-stock, Back in Stock app, or Shopify native notification
Option C: Noindex + 301 redirect to closest collection Only for: permanently discontinued products SEO impact: loses all accumulated link equity for that URL — only acceptable if the product will never return Shopify implementation: Products → [product] → uncheck “This product is available” → add redirect in Shopify Admin → Online Store → Navigation → URL Redirects
RULE: Never delete a product URL that has inbound backlinks. Check Ahrefs or Semrush for referring domains before any product deletion.
Owner: SEO + Operations Effort: Medium — 2–3 hours to audit and classify all out-of-stock products Priority: 🟡 P2 Dependency: Ahrefs/Semrush export of referring domains per product URL
Category 2 — On-Page (Shopify-Specific)
Finding 1.2.6 — Title tags: product titles used as-is without SEO optimisation
Scale: Potentially all product pages — confirm count via Screaming Frog Page Titles report Root cause: Shopify’s default behaviour uses the product title as the page title tag. A product titled “Navy Wool Coat” generates the title tag: Navy Wool Coat | shopifystore1.co.uk — missing the primary keyword modifier (“women’s”, “UK”, “size 8–20”) and any commercial signal.
Fix template per page type:
Product pages: [Colour] [Material] [Product Type] [Gender (if applicable)] | shopifystore1.co.uk Example: “Navy Wool Overcoat Women’s UK | shopifystore1.co.uk” (55 chars ✅)
Collection pages: [Primary Keyword] — [Differentiator] | shopifystore1.co.uk Example: “Women’s Wool Coats UK — Free Delivery | shopifystore1.co.uk” (59 chars ✅)
Blog posts: [Question or Benefit — Primary Keyword] | shopifystore1.co.uk Example: “Best Wool Coats for Winter UK 2026 | shopifystore1.co.uk” (55 chars ✅)
Homepage: [Brand Name] — [Primary Category] | UK [Key USP] Example: “shopifystore1 — Women’s Wool Coats | UK Next-Day Delivery” (57 chars ✅)
Implementation: Shopify Admin → Products / Collections / Blog Posts → [item] → Search engine listing preview → Edit website SEO → Title field. This field overrides the auto-generated title tag without changing the displayed product/collection title.
Owner: SEO + Content Effort: Medium — 1–2 minutes per page once template is confirmed Priority: 🟡 P2 — title tags are the highest-impact on-page ranking signal Dependency: Keyword research (Stage 2) finalises optimal title formulas. Do homepage and best-selling 10 products first.
Finding 1.2.7 — Meta descriptions: auto-generated from product description first 160 chars
Scale: All product pages without manually set meta descriptions Root cause: Shopify auto-generates meta descriptions from the first paragraph of the product description field. This is almost always a description of the product, not a conversion-oriented SERP snippet.
Fix: Manually set meta descriptions for all Tier 1 priority pages (best-selling products + all collection pages + homepage) before Stage 1 is complete.
Meta description formula: [Primary benefit] + [Key specification or differentiator] + [UK signal] + [CTA with price anchor] Example: “Luxuriously warm navy wool overcoat in UK sizes 8–20. GOTS-certified British wool. Free UK delivery on orders over £75. Shop from £[price].” (149 chars ✅)
Implementation: Shopify Admin → [product/collection/page] → Search engine listing preview → Edit website SEO → Description field.
Owner: SEO + Content Effort: Medium — 2–3 minutes per page Priority: 🟡 P2 Dependency: None — implement for top 20 pages immediately
Finding 1.2.8 — H1 tags: Shopify uses product title as H1 — confirm no duplication
Scale: Confirm via Screaming Frog H1 report Root cause: Shopify themes output the product title as the H1 by default. Some themes also output the page <title> as an additional H1 element via Liquid template errors. This creates duplicate H1s on the same page — a minor signal but worth confirming.
Fix: View source on product and collection pages. Search for <h1 — there should be exactly one H1 per page. If two H1 elements appear, identify which Liquid template is generating the duplicate and remove the <h1> tag from the errant section, replacing with <h2> or <p> as appropriate.
Owner: Developer Effort: Quick Win — 30 minutes to audit and fix Priority: 🟢 P3
Finding 1.2.9 — Image alt text: blank or using file names across product images
Scale: Confirm count via Screaming Frog → Images → Filter: Missing Alt Text Root cause: Shopify does not auto-populate alt text. When a product image is uploaded, the alt text field is blank by default unless the store owner manually enters it. Most stores have 0% alt text completion.
Fix priority: product images on Tier 1 products first, then collection banner images, then blog post featured images.
Alt text formula for product images: [Colour] [Material] [Product Name] [Brand] — [Use case or context] Example: “Navy blue GOTS-certified merino wool overcoat shopifystore1 — worn with jeans, perfect for winter commuting”
Alt text formula for collection banner images: [Collection name] collection by shopifystore1 — [key product examples]
Alt text formula for lifestyle/model images: [Product name] styled on model — [colour], size [X] shown
Implementation: Shopify Admin → Products → [product] → Media section → click image → Alt text field. One image at a time — no bulk alt text tool in Shopify Admin natively (some SEO apps provide bulk editing).
Owner: Content team Effort: Medium — 3–5 minutes per product Priority: 🟡 P2 — image search drives significant Shopify traffic; alt text is the primary image ranking signal
Category 3 — Shopify-Specific Duplicate Content
Finding 1.2.10 — Shopify search result pages: confirm blocked
Scale: Confirm at /robots.txt — Shopify’s default should include Disallow: /search Root cause: Shopify’s internal search results at /search?q=[query] generate unique URLs per search term. Google indexes them as near-duplicate thin pages with varying content depending on the query.
Fix: Confirm /robots.txt includes:
Disallow: /search
This is Shopify’s default — verify it has not been accidentally removed in a robots.txt.liquid customisation.
Owner: Developer Effort: Quick Win — 5 minutes Priority: 🔴 P1 if not blocked Validation: Visit https://www.shopifystore1.co.uk/robots.txt — confirm Disallow: /search is present
Finding 1.2.11 — Pagination strategy: /collections/[handle]?page=2 and beyond
Scale: Any collection with more than [products per page setting] products generates pagination URLs Root cause: Shopify uses ?page=2, ?page=3 etc. for collection pagination. These are indexable by default and create near-duplicate pages.
Fix: Two approaches — choose one based on theme support:
Approach A (recommended for large collections): Ensure each paginated page has a <link rel="canonical"> pointing to itself (not to page 1). Google should index and rank the most relevant paginated page independently. Shopify’s default themes implement this correctly.
Approach B (for small catalogues): Use Shopify’s infinite scroll or “Load more” button approach — this loads products without creating new indexable URLs. Products below the fold are loaded via JavaScript, not via new URLs.
Do NOT use rel="next" / rel="prev" — Google deprecated these in 2019 and they no longer affect ranking.
Owner: Developer Effort: Quick Win — 30 minutes to verify approach and confirm canonical behaviour Priority: 🟡 P2 Validation: View source on /collections/[handle]?page=2 — confirm canonical points to itself
1.3 — Technical Audit Findings Summary Table
| # | Finding | Pages Affected | Priority | Owner | Effort |
|---|---|---|---|---|---|
| 1 | /collections/all indexed | 1 (high impact) | 🔴 P1 | Dev | 15 min |
| 2 | Tag pages /collections/[h]/[tag] | Varies | 🔴 P1 | Dev | 15 min |
| 3 | Filter/sort parameter URLs | Varies | 🔴 P1 | Dev | 20 min |
| 4 | Product canonical: collection path | All products | 🔴 P1 | Dev | 30 min |
| 5 | Out-of-stock product strategy | Varies | 🟡 P2 | SEO + Ops | 2–3h |
| 6 | Title tags: product titles used as-is | All pages | 🟡 P2 | SEO | Medium |
| 7 | Meta descriptions: auto-generated | All pages | 🟡 P2 | SEO | Medium |
| 8 | H1 duplication check | All pages | 🟢 P3 | Dev | 30 min |
| 9 | Image alt text: blank | All products | 🟡 P2 | Content | Medium |
| 10 | /search: confirm blocked | 1 rule | 🔴 P1 if missing | Dev | 5 min |
| 11 | Pagination canonical strategy | Paginated collections | 🟡 P2 | Dev | 30 min |
Total P1 Critical issues: 5 Estimated fixes time for all P1s: under 2 hours
✅ CHECKPOINT — SECTION 1
- [ ] Screaming Frog crawl: JS-disabled pass complete, all URLs exported
- [ ] /robots.txt: live URL confirmed — Disallow rules for /search, /cart, /account, /checkout present
- [ ] /collections/all: indexed status confirmed in GSC — P1 fix applied
- [ ] Tag pages: count confirmed, robots.txt disallow applied
- [ ] Filter URLs: blocked via robots.txt
- [ ] Canonical tags: product page canonicals verified — all pointing to /products/[handle]
- [ ] Title tag audit: all pages exported, P1 pages (homepage + top 10 products + all collections) queued for rewrite
- [ ] Image alt text: missing alt text count confirmed
SECTION 2 — CRAWL BUDGET ANALYSIS
Shopify Crawl Budget: The Hidden Efficiency Problem
Shopify stores generate far more URLs than most store owners realise. A store with 200 products and 12 collections does not have 212 URLs. It has 212 product URLs, 12 collection URLs, up to 240 tag-filter URLs (if 20 tags are applied across all collections), 200 collection-path product URLs (/collections/[h]/products/[p]), potentially 400 pagination URLs, plus /collections/all, plus search result URLs, plus any app-generated URLs.
The realistic crawlable URL count for a 200-product Shopify store is often 1,500–3,000 URLs — of which perhaps 400 are genuinely valuable.
Pro Tip: The fastest crawl budget win on any Shopify store is always the same: noindex /collections/all and block tag pages. These two actions alone can reclaim 20–40% of daily Googlebot crawl requests on a typical mid-size store. This redirects Googlebot’s attention to the products and collections that actually drive revenue.
2.1 — Shopify-Specific Crawl Waste Categories
| URL Pattern | Why It Exists | Why It Wastes Budget | Fix |
|---|---|---|---|
| /collections/all | Shopify auto-creates | Thin, competes with real collection pages | Disallow in robots.txt |
| /collections/[h]/[tag] | Tag filter auto-generation | Thin subset pages | Disallow /collections/*/ |
| /collections/[h]?sort_by= | Sort URL parameters | Duplicate content, near-identical to parent | Disallow in robots.txt |
| /collections/[h]?filter. | Filter URL parameters | Thin filtered subset | Disallow in robots.txt |
| /collections/[h]/products/[p] | Shopify collection path | Duplicates /products/[p] (canonical handles it but wastes budget) | Disallow /collections/*/products/ |
| /search?q= | Internal site search | Thin, no commercial value | Already blocked by default — verify |
| /cart | Cart page | No SEO value | Already blocked by default — verify |
| /account | Customer accounts | Private, no SEO value | Already blocked by default — verify |
| /blogs/[name]?page=2 and beyond | Blog pagination | Low-value navigation pages | Disallow /blogs/*?page= |
2.2 — Recommended robots.txt.liquid for shopifystore1.co.uk
This is the production-ready robots.txt.liquid template. Create or replace the existing file in Shopify Admin → Online Store → Themes → Edit Code → Create new template → robots.txt.
{% comment %}
shopifystore1.co.uk — robots.txt.liquid
Customised: March 2026
SEO Lead: [NAME]
Next review: September 2026
{% endcomment %}
User-agent: *
Disallow: /admin
Disallow: /cart
Disallow: /orders
Disallow: /checkouts/
Disallow: /checkout
Disallow: /26361985/checkouts
Disallow: /26361985/orders
Disallow: /carts
Disallow: /account
Disallow: /collections/vendors
Disallow: /collections/types
Disallow: /collections/all
Disallow: /collections/*/
Disallow: /collections/*?sort_by=
Disallow: /collections/*?filter.
Disallow: /blogs/*?page=
Disallow: /search
Disallow: /password
Disallow: /policies/
Allow: /collections/*/products/
User-agent: AhrefsBot
Crawl-delay: 10
User-agent: SemrushBot
Crawl-delay: 10
User-agent: GPTBot
Disallow: /
User-agent: Google-Extended
Disallow: /
Sitemap: https://www.shopifystore1.co.uk/sitemap.xml
CRITICAL NOTES:
- The
Allow: /collections/*/products/line is required because theDisallow: /collections/*/rule would otherwise block collection-path product URLs entirely — blocking Googlebot from discovering products via collection pages in the Shopify sitemap Disallow: /collections/vendorsandDisallow: /collections/typesblock Shopify’s auto-generated vendor and product-type collection pages — these are always thin and should never be indexedCrawl-delay: 10for Ahrefs and Semrush bots reduces server load from SEO tool crawls without affecting Googlebot (which ignores crawl-delay in robots.txt since 2019)- GPTBot and Google-Extended blocks are content licensing decisions — confirm with store owner before deploying
2.3 — Shopify Sitemap Assessment
Shopify auto-generates a sitemap index at /sitemap.xml with sub-sitemaps for products, collections, pages, and blog posts.
What Shopify includes in the sitemap:
- All published products (including out-of-stock)
- All published collections (including /collections/all — needs blocking)
- All published pages
- All published blog posts
What Shopify does NOT include:
- Tag-filtered collection URLs (not in sitemap — correct)
- Filter/sort parameter URLs (not in sitemap — correct)
- Variant-specific URLs (not applicable — variants share the product URL)
Shopify sitemap actions required:
Submit all sub-sitemaps to GSC separately:
- https://www.shopifystore1.co.uk/sitemap_products_1.xml
- https://www.shopifystore1.co.uk/sitemap_collections_1.xml
- https://www.shopifystore1.co.uk/sitemap_pages_1.xml
- https://www.shopifystore1.co.uk/sitemap_blogs_1.xml
Confirm out-of-stock products in sitemap match the agreed strategy from Section 1 (Finding 1.2.5). Out-of-stock products remain in the sitemap under Options A and B. Under Option C (permanently discontinued), they should be removed from Shopify by unpublishing the product — Shopify auto-removes unpublished items from the sitemap.
Confirm /collections/all is NOT in sitemap after robots.txt blocks it. Shopify’s sitemap respects robots.txt exclusions — once blocked, /collections/all should be absent from the collections sub-sitemap within 7–14 days.
2.4 — Crawl Efficiency Target
| Metric | Before Stage 1 | After Stage 1 Target |
|---|---|---|
| Waste URLs in crawl | Estimated 40–60% of total | Target <15% |
| /collections/all | Indexed | Blocked + excluded |
| Tag pages | Indexed | Blocked + excluded |
| Filter/sort URLs | Present in crawl | Blocked |
| Useful URLs crawled per day | ~[X] | Target: all products crawled in ≤7 days |
| GSC: Excluded (blocked by robots.txt) | [baseline] | Should increase significantly |
✅ CHECKPOINT — SECTION 2
- [ ] robots.txt.liquid: created/updated in theme, deployed and accessible at /robots.txt
- [ ] /collections/all: confirmed blocked in live robots.txt
- [ ] Tag pages: confirmed blocked via /collections/*/ rule
- [ ] Filter/sort URLs: confirmed blocked
- [ ] GPTBot/Google-Extended: confirmed disallowed (after owner decision)
- [ ] All 4 Shopify sub-sitemaps: submitted to GSC
- [ ] Crawl Stats baseline: recorded in GSC → Settings → Crawl Stats before changes
- [ ] Crawl Stats: re-check at 14 days — confirm Googlebot crawl rate distribution improving
SECTION 3 — CORE WEB VITALS REMEDIATION
CWV on Shopify: Apps Are the Primary Problem
Shopify’s native themes (Dawn, Craft, Sense, Refresh) are well-optimised for Core Web Vitals. Most Shopify stores that fail CWV do so because of app scripts — not theme code.
The single most common LCP failure pattern on Shopify stores: a third-party app (live chat widget, loyalty programme, abandoned cart popup) adds a large JavaScript bundle that fires on page load, blocking the render of the hero image and pushing LCP from 1.9 seconds to 4.2 seconds.
Before spending any development time on theme code CWV fixes, run this test:
- Open the store homepage in Chrome in incognito mode
- Open DevTools → Performance tab → Record a page load
- In the Waterfall, identify the LCP element
- Identify which request is blocking the LCP element
- Check if that blocking request is from a theme script or an app script
If the LCP blocker is an app script: the fix is either to delay the app script load or to remove the app.
Pro Tip: Shopify’s Speed Score in the theme dashboard (Admin → Online Store → Themes → Speed) is a Lighthouse score, not a real-user score. It measures a simulated load from a US server. For a UK store targeting UK customers, run PageSpeed Insights directly with the store URL — the real-user data from Chrome User Experience Report (CrUX) is the score Google uses for ranking. A store with a PageSpeed Lighthouse score of 72 may have a CrUX Good LCP because UK users are geographically close to the hosting servers.
3.1 — CWV Audit: App Performance Assessment
Run this before any CWV work begins.
Step 1 — List all installed Shopify apps: Shopify Admin → Apps → All apps
Step 2 — For each app, record:
- Function (what does it do?)
- Is it actively being used? (revenue-generating or has no data)
- Is it loading scripts on the storefront?
Step 3 — Test CWV with each app disabled: Use Shopify’s Preview theme feature to disable one app’s scripts at a time and run PageSpeed Insights. Identify which app, if any, is the primary CWV offender.
Common Shopify apps that most frequently degrade CWV:
| App Type | Common offenders | CWV impact |
|---|---|---|
| Live chat | Tidio, Gorgias, Zendesk | +300–800ms LCP, +40–100ms INP |
| Loyalty/rewards | Smile.io, LoyaltyLion | +200–500ms LCP |
| Exit intent / popups | Privy, Popup Maker | +200–400ms LCP, +50ms INP |
| Review widgets | Some Yotpo plans | +200–600ms depending on configuration |
| Currency converters | Bold Multi-Currency | +300ms+ if not lazy-loaded |
| Social proof widgets | Fomo, Sales Pop | +100–300ms LCP |
3.2 — LCP Remediation (Shopify-Specific)
Most common Shopify LCP fix: preload the hero image
For Dawn and most modern Shopify themes, the hero section image is a CSS background or an <img> tag inside an Elementor-style section. If it is an <img> tag, add fetchpriority="high" to the image tag in the theme code:
In the theme’s sections/image-banner.liquid (or equivalent hero section file):
{% assign hero_image = section.settings.image %}
{% if hero_image %}
<img
src="{{ hero_image | image_url: width: 1200 }}"
srcset="{{ hero_image | image_url: width: 400 }} 400w,
{{ hero_image | image_url: width: 800 }} 800w,
{{ hero_image | image_url: width: 1200 }} 1200w"
sizes="100vw"
alt="{{ hero_image.alt | escape }}"
width="{{ hero_image.width }}"
height="{{ hero_image.height }}"
loading="eager"
fetchpriority="high"
>
{% endif %}
Additionally, add a preload hint in layout/theme.liquid <head> section:
{% if template == 'index' %}
{% assign hero = section.settings.image %}
{% if hero %}
<link rel="preload" as="image" href="{{ hero | image_url: width: 1200 }}" fetchpriority="high">
{% endif %}
{% endif %}
Note: Shopify automatically serves WebP format via its CDN (cdn.shopify.com) when the browser supports it — no separate WebP conversion is needed. Confirm this by inspecting a product image URL in DevTools → Network: the response content-type should show image/webp for modern browsers.
3.3 — CLS Remediation (Shopify-Specific)
Most common Shopify CLS fix: define image dimensions in product grids
Shopify product grid cards frequently cause CLS when product images are loaded without explicit width and height attributes. The browser does not know the image dimensions before they load, so it cannot reserve space — causing layout shift as images load.
Fix in snippets/product-card.liquid (or equivalent):
{% assign img = product.featured_image %}
{{ img | image_url: width: 600 | image_tag:
width: img.width,
height: img.height,
loading: 'lazy',
class: 'product-image'
}}
Always include width and height attributes — even when using CSS to control display size. The aspect ratio hint prevents layout shift.
Second most common Shopify CLS fix: font-display swap
If using custom fonts (Google Fonts or self-hosted), add font-display: swap to prevent invisible text during font load (FOUT/FOIT causes CLS):
In theme assets, find the CSS file containing @font-face declarations and add font-display: swap; to each.
For Google Fonts loaded via URL in theme.liquid, add &display=swap to the Google Fonts URL:
<link href="https://fonts.googleapis.com/css2?family=[FontName]&display=swap" rel="stylesheet">
3.4 — INP Remediation (Shopify-Specific)
INP (Interaction to Next Paint) measures responsiveness — the delay between a user interaction and the browser’s visual response.
Most common Shopify INP issues:
- Cart drawer script blocking interactions Many Shopify stores use an AJAX cart drawer that fires a large JavaScript bundle on every interaction. Users clicking “Add to Cart” experience a 200–500ms delay because the cart JavaScript is synchronously loaded and executed. Fix: Ensure the cart drawer script is deferred until after initial page render. In
layout/theme.liquid, ensure the cart JS file loads withdefer:
<script src="{{ 'cart.js' | asset_url }}" defer></script>
Review app widgets causing interaction delays Apps like Yotpo and certain Judge.me configurations load review widgets as synchronous scripts that block the main thread. Fix: Enable lazy loading on the reviews section — load review widget JavaScript only when the reviews section scrolls into view, using an IntersectionObserver.
Currency or translation app re-rendering on interaction Apps that convert prices or translate content on page load can cause delayed responses to interaction. Fix: Load currency/translation scripts with
deferand ensure they do not re-render the DOM synchronously on interaction.
3.5 — CWV Monitoring Plan
| Metric | Tool | Frequency | Alert threshold |
|---|---|---|---|
| LCP/CLS/INP per URL group | GSC Core Web Vitals report | Weekly | Any group moves from Good → NI |
| LCP on homepage (mobile) | PageSpeed Insights | After every app install | Increase >0.3s = investigate |
| LCP on best-selling product | PageSpeed Insights | Monthly | >2.5s = sprint |
| Real-user data | CrUX in PageSpeed Insights | Monthly | % Good LCP below 75% = escalate |
| App performance audit | Manual (list + disable test) | Quarterly | Any app adding >200ms LCP |
✅ CHECKPOINT — SECTION 3
- [ ] App performance audit: all installed apps listed, CWV impact assessed
- [ ] LCP baseline: PageSpeed Insights scores recorded for homepage, top collection, top product
- [ ] Hero image: fetchpriority=”high” + preload link deployed in theme
- [ ] Product grid images: width + height attributes confirmed on all image_tag calls
- [ ] Font-display: swap: confirmed in CSS / Google Fonts URL
- [ ] Cart drawer: defer attribute confirmed on cart JavaScript
- [ ] Post-fix validation: PageSpeed Insights re-run on all 3 template types
- [ ] GSC Core Web Vitals report: Good% baseline recorded before and after fixes
SECTION 4 — SCHEMA LIBRARY
Why Shopify Schema Is Not a One-Click Fix
Shopify’s Dawn theme auto-generates Product schema. That is the only schema it generates automatically.
BreadcrumbList, Organization, Article, FAQPage, and CollectionPage schema do not exist on a default Shopify store. A store without BreadcrumbList schema is missing the breadcrumb trail in Google SERPs — a click-through rate improvement that is available for free. A store without Organization schema is missing the entity corroboration that supports Knowledge Panel eligibility. A store without FAQPage schema is missing Rich Result eligibility for every collection page with an FAQ section.
Pro Tip: The highest-ROI schema deployment on a Shopify store is almost always FAQPage schema on collection pages. Collection pages are the primary revenue-driving landing pages for most stores. Adding a FAQ section with 3–4 questions (sourced from People Also Ask) and FAQPage schema creates a visual Rich Result in the SERP that can increase the click-through rate on that collection page by 20–30% — with no change to ranking position. That is additional traffic from the same position.
4.1 — Schema Deployment Map
| Page Type | Required Schema | Shopify Auto-Generates | Needs Manual Addition |
|---|---|---|---|
| All pages | BreadcrumbList | ❌ No | ✅ Yes — via theme code |
| Homepage | Organization + WebSite (SearchAction) | ❌ No | ✅ Yes — via theme.liquid |
| Product pages | Product + aggregateRating | ✅ Partial (Dawn) | ✅ Verify fields + add aggregateRating via app |
| Collection pages | CollectionPage/ItemList + FAQPage | ❌ No | ✅ Yes — via collection.liquid |
| Blog posts | Article + FAQPage | ❌ No | ✅ Yes — via article.liquid |
| Pages | WebPage | ❌ No | Recommended — add to page.liquid |
4.2 — Product Schema — Full Template (Shopify Liquid)
Deploy in sections/main-product.liquid or templates/product.json via a schema section.
{% assign current_variant = product.selected_or_first_available_variant %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": {{ product.title | json }},
"url": "{{ shop.url }}/products/{{ product.handle }}",
"image": [
{% for image in product.images limit: 5 %}
"{{ image | image_url: width: 800 }}"{% unless forloop.last %},{% endunless %}
{% endfor %}
],
"description": {{ product.description | strip_html | truncate: 300 | json }},
"sku": {{ current_variant.sku | json }},
"brand": {
"@type": "Brand",
"name": {{ shop.name | json }}
},
"offers": {
"@type": "Offer",
"url": "{{ shop.url }}/products/{{ product.handle }}",
"priceCurrency": "GBP",
"price": "{{ current_variant.price | money_without_currency | remove: ',' }}",
"availability": "{% if current_variant.available %}https://schema.org/InStock{% else %}https://schema.org/OutOfStock{% endif %}",
"priceValidUntil": "{{ 'now' | date: '%Y' | plus: 1 }}-12-31",
"itemCondition": "https://schema.org/NewCondition",
"seller": {
"@type": "Organization",
"name": {{ shop.name | json }}
}
}{% if product.metafields.reviews.rating_count and product.metafields.reviews.rating_count != '0' %},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "{{ product.metafields.reviews.rating }}",
"reviewCount": "{{ product.metafields.reviews.rating_count }}",
"bestRating": "5",
"worstRating": "1"
}{% endif %}
}
</script>
Important notes:
- The
aggregateRatingblock only outputs ifproduct.metafields.reviews.rating_countexists and is non-zero. This requires the reviews app (Judge.me, Okendo, or Shopify Product Reviews) to write rating data to product metafields. - Confirm the metafield namespace and key match your reviews app — Judge.me uses
reviews.ratingandreviews.rating_count; Okendo may use a different namespace. Check with the app documentation. - Never hardcode rating values — only output aggregateRating from verified review data.
- VAT: Shopify UK stores typically show prices inclusive of VAT. The price in
money_without_currencyLiquid filter includes VAT. NovalueAddedTaxIncludedfield is required unless your store is displaying ex-VAT prices.
4.3 — BreadcrumbList Schema — All Pages
Deploy in layout/theme.liquid just before the closing </head> tag, using conditional logic to generate the correct breadcrumb path per page type.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{ shop.url }}"
}{% if template == 'product' %},
{
"@type": "ListItem",
"position": 2,
"name": {{ collection.title | json }},
"item": "{{ shop.url }}/collections/{{ collection.handle }}"
},
{
"@type": "ListItem",
"position": 3,
"name": {{ product.title | json }},
"item": "{{ shop.url }}/products/{{ product.handle }}"
}{% elsif template == 'collection' %},
{
"@type": "ListItem",
"position": 2,
"name": {{ collection.title | json }},
"item": "{{ shop.url }}/collections/{{ collection.handle }}"
}{% elsif template contains 'article' %},
{
"@type": "ListItem",
"position": 2,
"name": {{ blog.title | json }},
"item": "{{ shop.url }}/blogs/{{ blog.handle }}"
},
{
"@type": "ListItem",
"position": 3,
"name": {{ article.title | json }},
"item": "{{ shop.url }}/blogs/{{ blog.handle }}/{{ article.handle }}"
}{% endif %}
]
}
</script>
4.4 — Organization Schema — Homepage (theme.liquid)
Deploy once in layout/theme.liquid inside {% if template == 'index' %} conditional.
{% if template == 'index' %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "{{ shop.url }}/#organization",
"name": {{ shop.name | json }},
"url": {{ shop.url | json }},
"logo": "{{ shop.metafields.global.logo | image_url: width: 400 }}",
"foundingDate": "[YEAR — enter manually]",
"description": {{ shop.metafields.global.description | json }},
"address": {
"@type": "PostalAddress",
"addressCountry": "GB",
"addressRegion": "England",
"addressLocality": "[CITY — enter manually]"
},
"contactPoint": {
"@type": "ContactPoint",
"contactType": "customer service",
"availableLanguage": "English",
"areaServed": "GB"
},
"sameAs": [
"https://www.trustpilot.com/review/shopifystore1.co.uk",
"https://www.instagram.com/[INSTAGRAM_HANDLE]",
"https://www.facebook.com/[FACEBOOK_HANDLE]"
]
}
</script>
{% endif %}
4.5 — Article Schema — Blog Posts (article.liquid)
Deploy in templates/article.liquid or sections/main-article.liquid.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": {{ article.title | json }},
"image": "{{ article.image | image_url: width: 1200 }}",
"datePublished": "{{ article.published_at | date: '%Y-%m-%dT%H:%M:%S' }}",
"dateModified": "{{ article.updated_at | date: '%Y-%m-%dT%H:%M:%S' }}",
"author": {
"@type": "Person",
"name": {{ article.author | json }},
"url": "{{ shop.url }}/blogs/{{ blog.handle }}"
},
"publisher": {
"@type": "Organization",
"name": {{ shop.name | json }},
"logo": {
"@type": "ImageObject",
"url": "{{ shop.metafields.global.logo | image_url: width: 400 }}"
}
},
"description": {{ article.excerpt_or_content | strip_html | truncate: 200 | json }},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "{{ shop.url }}/blogs/{{ blog.handle }}/{{ article.handle }}"
}
}
</script>
4.6 — Schema Validation Protocol
| Step | Tool | Pass Condition |
|---|---|---|
| 1 | validator.schema.org | 0 errors, 0 critical warnings per page type |
| 2 | Google Rich Results Test | Product: eligible · Article: eligible · FAQPage: eligible (when deployed) |
| 3 | GSC Rich Results report | Product and Article types appearing — check after 7 days |
| 4 | Monthly | GSC Rich Results count stable or increasing — any drop = regression |
CRITICAL: Confirm no schema duplication. If using a Shopify SEO app (JSON-LD for SEO, SearchPie, SEO Manager), it may already output Product schema. Adding manual Liquid schema on top creates duplicate blocks. Validate every page type at validator.schema.org to detect duplicates — they appear as two blocks of the same @type on the same URL.
✅ CHECKPOINT — SECTION 4
- [ ] Product schema: deployed and validated — 0 errors on Rich Results Test
- [ ] BreadcrumbList: deployed for product, collection, and article templates
- [ ] Organization schema: deployed on homepage with live sameAs URLs
- [ ] Article schema: deployed on blog post template
- [ ] Schema duplication: confirmed absent — only one schema block per @type per page
- [ ] GSC Rich Results: monitoring weekly — all submitted schema types showing in report
SECTION 5 — GA4 + GSC SETUP
Why Tracking Must Come Before Optimisation
Every change made in Stage 1 needs a baseline to measure against. Without a properly configured GA4 and a verified GSC property, there is no way to know whether the crawl budget optimisation recovered meaningful organic traffic, whether the CWV fix improved real-user scores, or whether the title tag rewrites increased click-through rates.
The single most common Shopify SEO programme failure: teams make months of changes and then try to measure the impact retrospectively — but the GA4 setup was wrong from the start, the organic channel is polluted with direct traffic, and the conversion events were never properly configured.
Tracking setup in Stage 1 means every improvement in Stage 2, 3, and 4 is measured accurately.
Pro Tip: Shopify’s native Google Analytics integration via the “Google & YouTube” channel is server-side for purchase events — meaning ad blockers and browser privacy settings do not suppress purchase tracking. But add_to_cart, begin_checkout, and view_item events are client-side by default and can be suppressed by ad blockers. For accurate funnel data, implement GA4 via Google Tag Manager with a server-side container — or accept that client-side funnel events will be undercounted by approximately 15–25% in 2025 due to increasing ad blocker adoption in the UK.
5.1 — GA4 Setup Checklist for shopifystore1.co.uk
Step 1: Verify GA4 is correctly installed
- Confirm: GA4 measurement ID (G-XXXXXXXXXX) is firing on every page
- Test: Google Tag Assistant → confirm GA4 tag fires on homepage, product page, collection page, and /thank_you order confirmation page
- Confirm: GA4 is installed via Shopify native integration OR via GTM — not both (duplicate tags cause inflated session counts)
Step 2: Confirm e-commerce Key Events are firing
| Event | Expected trigger | Test method |
|---|---|---|
| view_item | Product page load | GA4 Debug View → load a product page |
| add_to_cart | “Add to Cart” button click | GA4 Debug View → click Add to Cart |
| begin_checkout | /checkout URL | GA4 Debug View → click checkout |
| purchase | /thank_you URL | GA4 Debug View → place a test order |
| view_item_list | Collection page load | GA4 Debug View → load a collection page |
| search | Shopify search submit | GA4 Debug View → submit a search |
Step 3: Configure organic channel correctly Confirm: Google Organic appears as a separate channel in GA4 → Reports → Acquisition → Traffic Acquisition. If all Google traffic appears as “Unassigned”: the GA4 Channel Grouping is misconfigured. Fix in GA4 Admin → Property → Channel Groups → confirm “Organic Search” rule includes session_source matches google AND session_medium exactly matches organic.
Step 4: Create custom dimensions for SEO tracking
| Dimension | Scope | Value | Purpose |
|---|---|---|---|
| content_type | Event | “product” / “collection” / “blog” / “page” | Attribute organic sessions to content type |
| product_category | Event | collection.handle | Attribute revenue to collection |
| organic_query_type | Session | “brand” / “non-brand” | Separate brand and non-brand organic traffic |
5.2 — GSC Setup Checklist
Step 1: Verify domain property (not URL prefix) GSC → Add Property → Domain type (not URL prefix). Domain property tracks all subdomains and both HTTP/HTTPS simultaneously. Confirm: DNS TXT record added for verification. Shopify requires this via the domain registrar — not via Shopify Admin.
Step 2: Link GSC to GA4 GA4 Admin → Property → Service Links → Search Console → Link. This enables organic search queries to appear in GA4 → Reports → Acquisition → Traffic Acquisition → Organic Search → Session source/medium + Landing page.
Step 3: Submit all sitemaps GSC → Sitemaps → Add sitemap:
- https://www.shopifystore1.co.uk/sitemap.xml (the index — submits all sub-sitemaps)
- https://www.shopifystore1.co.uk/sitemap_products_1.xml (optional — direct submission for faster indexation of products)
Step 4: Set preferred domain GSC → Settings → Address bar → confirm www vs non-www preference matches Shopify store domain setting.
Step 5: Configure Performance report alerts GSC does not have native email alerts. Monitor manually:
- Weekly: Performance → compare date range → flag >15% drop in clicks or impressions
- Monthly: Coverage → Indexed page count — any significant drop in one week = investigate
5.3 — Monthly Baseline Metrics to Record (Stage 1 Start)
Record all the following BEFORE making any changes. These are the baselines against which Stage 2 improvements are measured.
| Metric | Source | Value (record) |
|---|---|---|
| Organic sessions / month | GA4 | |
| Organic revenue / month | GA4 | |
| Organic conversion rate | GA4 | |
| Total impressions / month | GSC | |
| Total clicks / month | GSC | |
| Average CTR | GSC | |
| Indexed pages | GSC Coverage | |
| Core Web Vitals: Good % | GSC CWV report | |
| LCP (mobile, homepage) | PageSpeed Insights | |
| LCP (mobile, top collection) | PageSpeed Insights | |
| Domain Rating | Ahrefs | |
| Referring domains | Ahrefs | |
| Top 10 rankings count | Semrush / Ahrefs |
✅ CHECKPOINT — SECTION 5
- [ ] GA4: measurement ID confirmed firing on all page types including /thank_you
- [ ] GA4: all e-commerce Key Events confirmed firing via GA4 Debug View
- [ ] GA4: organic channel correctly isolated — not mixed with direct/unassigned
- [ ] GA4: linked to GSC — organic queries visible in GA4 traffic report
- [ ] GSC: domain property verified (not URL prefix)
- [ ] GSC: all sitemaps submitted — no errors in Coverage report
- [ ] GSC: preferred domain set (www / non-www) matches Shopify store setting
- [ ] Baseline metrics: all values recorded in tracking spreadsheet before any fixes deployed
SECTION 6 — ON-PAGE BASELINE AUDIT
On-Page at Foundation Stage: Fix the Framework, Not the Copy
Stage 1 does not rewrite product descriptions. That is Stage 2 work, informed by the keyword research conducted in Stage 2.
What Stage 1 does is fix the structural on-page elements that apply universally — regardless of what the content says. Title tags, meta descriptions, image alt text, and H1 structure are infrastructure. They affect every page on the store and they can be improved immediately with clear, repeatable formulas.
Pro Tip: The highest-ROI on-page fix in Stage 1 is always the collection page title tag. Collection pages are the primary ranking targets for head-term commercial keywords (“women’s wool coats UK”, “sustainable activewear UK”). Their title tags are almost always set to the raw collection name — missing the primary keyword modifier, the UK signal, and any commercial anchor. A single title tag change on a high-priority collection page can produce a ranking movement within 2–4 weeks of Googlebot re-crawling the page.
6.1 — On-Page Audit Priority Order
| Priority | Page Type | Reason |
|---|---|---|
| 1 | Homepage | Highest authority page — sets entity and brand signals |
| 2 | All collection pages | Primary commercial landing pages — head term targets |
| 3 | Top 10 best-selling products | Highest-revenue pages — transactional keyword targets |
| 4 | Blog posts ranking in positions 11–30 | Closest to page 1 — quick wins with title/meta update |
| 5 | Remaining products | Systematic batch update in Stage 2 |
6.2 — On-Page Audit Data Collection
Run the following exports from Screaming Frog before making any changes:
Page titles export: All URLs → Page Titles tab → Export → Flag: over 60 chars, under 30 chars, duplicates, containing “Shopify” (Shopify used to append “Shopify” to titles in some legacy configurations)
Meta descriptions export: All URLs → Meta Description tab → Export → Flag: missing, over 155 chars, auto-generated (truncated product description text)
H1 export: All URLs → H1 tab → Export → Flag: missing, multiple H1s on same page, H1 matches title tag exactly (may indicate a template issue)
Image alt text export: Images tab → Alt Text → Filter: Missing → Export → Count total missing alt texts
Word count export: All URLs → Custom Extraction if configured → Flag: collection pages under 200 words in the description section (thin collection pages are a primary Stage 2 brief target)
6.3 — Title Tag Formulas (Confirmed for Stage 1 Deployment)
These formulas apply to all page types. Replace [VARIABLE] with the actual values for each page.
Homepage: [Brand Name] — [Primary Product Category] | [UK Differentiator] Character target: 50–60 chars Example: “shopifystore1 — Women’s Knitwear | Free UK Delivery” (51 chars ✅)
Collection pages (transactional): [Primary Keyword] — [Volume/Range Signal] | shopifystore1 Character target: 50–60 chars Example: “Women’s Merino Wool Jumpers — 30 Styles | shopifystore1” (55 chars ✅)
Collection pages (ethical/niche angle): [Niche Modifier] [Product Category] UK — [Certification/USP] | shopifystore1 Example: “GOTS Certified Knitwear UK — Sustainable Wool | shopifystore1” (61 chars — trim to 60: “GOTS Certified Knitwear UK — Organic Wool | shopifystore1” ✅)
Product pages (specific): [Colour/Size] [Material] [Product Name] [Gender] UK | shopifystore1 Character target: 50–60 chars Example: “Slate Grey Merino Roll-Neck Jumper Women UK | shopifystore1” (59 chars ✅)
Blog posts (question format): [Question containing primary keyword] | shopifystore1 Character target: 50–60 chars Example: “How to Style a Merino Jumper for Work UK | shopifystore1” (56 chars ✅)
6.4 — Meta Description Formulas
Collection pages: [Benefit statement]. [Product range signal]. [UK delivery or price signal]. [CTA with price anchor]. Character target: 140–155 chars Example: “Shop our range of GOTS-certified merino wool jumpers for women. 30+ styles in UK sizes 8–20. Free UK delivery over £60. From £[price].” (134 chars ✅)
Product pages: [Key specification]. [Material or ingredient detail]. [UK signal]. [Conversion trigger]. Example: “100% GOTS-certified merino wool roll-neck jumper. Ultrasoft, naturally temperature-regulating. UK sizes 8–20. Free returns. Add to bag from £[price].” (150 chars ✅)
Blog posts: [Answer the implied question in 1–2 sentences]. [Related product recommendation]. [Brand signal]. Example: “The best ways to style a merino jumper for work in 2026 — from boardroom to video call. Shop our edit of office-ready knitwear at shopifystore1.” (144 chars ✅)
6.5 — Shopify On-Page Implementation Map
| Element | Implementation path | Time per page |
|---|---|---|
| Title tag | Admin → [product/collection/page/article] → SEO section → Title | 2 min |
| Meta description | Admin → [product/collection/page/article] → SEO section → Description | 2 min |
| H1 (product) | Admin → Products → Title field (this IS the H1 on product pages) | 1 min |
| H1 (collection) | Admin → Collections → Title field (this IS the H1 on collection pages) | 1 min |
| Image alt text | Admin → Products → Media → click image → Alt text | 1–2 min per image |
| Blog post H1 | Admin → Blog Posts → Title field | 1 min |
Bulk editing option: Shopify Admin → Products → Export → Edit in spreadsheet → Import. The exported CSV includes SEO title and SEO description columns — allows bulk editing of all product SEO fields simultaneously. Most efficient for stores with 50+ products.
✅ CHECKPOINT — SECTION 6
- [ ] On-page audit data: all 5 Screaming Frog exports complete
- [ ] Title tag issues: all flagged pages documented with current vs recommended
- [ ] Meta description issues: all missing and auto-generated descriptions flagged
- [ ] H1 audit: duplicates and missing H1s confirmed and fixed
- [ ] Image alt text: missing count recorded, top 20 products updated
- [ ] Homepage: title tag, meta description, H1 all optimised
- [ ] All collection pages: title tags updated using confirmed formula
- [ ] Top 10 best-selling products: title tags and meta descriptions updated
SECTION 7 — 30-DAY ACTION PLAN
Phase 1 — Week 1: Critical Fixes (P1 Items)
These 5 fixes take under 3 hours combined and produce immediate crawl budget improvements.
| Day | Action | Owner | Time | Validation |
|---|---|---|---|---|
| Day 1 | Create robots.txt.liquid with full configuration | Dev | 30 min | Visit /robots.txt — confirm all disallow rules present |
| Day 1 | Confirm /collections/all blocked in live robots.txt | Dev | 5 min | GSC → Inspect URL: /collections/all — should be blocked |
| Day 1 | Confirm /search, /cart, /checkout, /account blocked | Dev | 5 min | robots.txt live — spot check each rule |
| Day 2 | Verify product canonical tags on 10 random products | Dev | 20 min | View source → <link rel="canonical"> = /products/[handle] |
| Day 2 | Hero image: add fetchpriority=”high” + preload in theme.liquid | Dev | 45 min | PageSpeed Insights before + after — LCP should improve |
| Day 3 | Submit all 5 sitemaps to GSC | SEO | 15 min | GSC → Sitemaps → all submitted, no errors |
| Day 3 | GA4 + GSC: verify all Key Events firing | SEO | 60 min | GA4 Debug View — all events confirmed |
| Day 4 | Deploy BreadcrumbList schema in theme.liquid | Dev | 60 min | Rich Results Test — breadcrumbs eligible |
| Day 4 | Deploy Organization schema on homepage | Dev | 30 min | validator.schema.org — 0 errors |
| Day 5 | Product schema: verify Dawn/theme is outputting + validate | Dev | 45 min | Rich Results Test on 3 product pages |
| Day 5 | Homepage title tag + meta description: rewrite and deploy | SEO | 20 min | GSC URL inspection — confirm new title tag after re-crawl |
Phase 2 — Week 2: Collection + Product On-Page
| Day | Action | Owner | Time |
|---|---|---|---|
| Day 8 | Collection pages: rewrite all title tags using confirmed formula | SEO | 2 hours |
| Day 9 | Collection pages: rewrite all meta descriptions | SEO | 2 hours |
| Day 10 | Top 10 products: title tags + meta descriptions updated | SEO | 2 hours |
| Day 11 | Product schema: deploy Article schema on blog posts | Dev | 60 min |
| Day 12 | Image alt text: update all images on top 20 products | Content | 3 hours |
Phase 3 — Week 3–4: CWV Sprint + Out-of-Stock Strategy
| Day | Action | Owner | Time |
|---|---|---|---|
| Day 15 | App performance audit: list all apps, test CWV impact | Dev + SEO | 3 hours |
| Day 16 | Product grid images: confirm width + height attributes in theme | Dev | 60 min |
| Day 17 | Font-display: swap: confirm in all @font-face and Google Fonts URLs | Dev | 30 min |
| Day 18 | Cart drawer: confirm defer attribute on cart JavaScript | Dev | 30 min |
| Day 20 | Out-of-stock product strategy: classify all out-of-stock products | SEO + Ops | 3 hours |
| Day 22 | Apply out-of-stock strategy decisions (keep/notify/redirect) | Dev + Ops | 2 hours |
| Day 25 | Full PageSpeed Insights re-run on all 3 template types | SEO | 30 min |
| Day 28 | 30-day baseline comparison: record all metrics from Section 5.3 | SEO | 60 min |
7.1 — What to Expect After 30 Days
GSC Coverage:
- Excluded (blocked by robots.txt) count increases by the number of tag pages + /collections/all + filter URLs previously indexed
- Indexed page count may decrease slightly — this is normal and desirable (fewer thin pages = better crawl efficiency)
GSC Performance:
- No significant ranking changes expected in Week 1–2 (Googlebot needs time to re-crawl and process changes)
- By Day 28–30: title tag and meta description changes on highest-priority pages may show CTR improvements in GSC Performance report
- Collection pages with new, keyword-rich title tags may show position improvements within 3–4 weeks
Core Web Vitals:
- LCP improvement visible immediately after hero preload fix (confirm via PageSpeed Insights, not GSC CWV — GSC uses 28-day rolling real-user data, which lags)
- GSC CWV Good% improvement should appear within 14–21 days as Chrome users report improved metrics
What will NOT change in 30 days:
- Organic traffic volume (requires Stage 2 content work and Stage 3 authority building)
- Rankings for competitive keywords (Stage 2 and 3)
- Domain Rating (Stage 3)
Stage 1 is infrastructure. The traffic growth comes in Stages 2, 3, and 4 — built on the foundation set here.
SECTION 8 — STAGE 1 COMPLETION CHECKLIST
Pre-Stage 2 Requirements
Stage 2 (Visibility) does not begin until all items below are confirmed. Stage 2 depends on this foundation being structurally sound.
Technical (all must be ✅):
- [ ] robots.txt.liquid: deployed with all disallow rules — confirmed at live /robots.txt URL
- [ ] /collections/all: blocked and removed from GSC Coverage indexed count
- [ ] Tag pages: blocked via robots.txt
- [ ] Filter/sort URLs: blocked via robots.txt
- [ ] Product canonical tags: all confirmed pointing to /products/[handle]
- [ ] Schema: Product + BreadcrumbList + Organization + Article — all validated, 0 errors
- [ ] Schema duplication: none detected across any page type
Performance (all targets met):
- [ ] Homepage LCP (mobile): ≤2.5s
- [ ] Top collection LCP (mobile): ≤2.5s
- [ ] Top product LCP (mobile): ≤2.5s
- [ ] CLS (all critical templates): ≤0.1
- [ ] INP: ≤200ms on homepage and product pages
Tracking (all must be ✅):
- [ ] GA4: all e-commerce Key Events confirmed firing (view_item, add_to_cart, begin_checkout, purchase)
- [ ] GA4: organic channel correctly isolated
- [ ] GA4: linked to GSC
- [ ] GSC: domain property verified
- [ ] GSC: all sitemaps submitted, 0 errors
- [ ] Baseline metrics: all recorded in tracking spreadsheet
On-page (all priority pages done):
- [ ] Homepage: title tag + meta description optimised
- [ ] All collection pages: title tags rewritten using confirmed formula
- [ ] Top 10 products: title tags + meta descriptions updated
- [ ] Image alt text: top 20 products complete
- [ ] Out-of-stock strategy: decided and implemented
CITATIONS & SOURCES
1. Google. Core Web Vitals. web.dev, October 2024. https://web.dev/articles/vitals Supports: LCP ≤2.5s, CLS ≤0.1, INP ≤200ms thresholds throughout Section 3.
2. Google. Understand how structured data works. Google Search Central, 2024. https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data Supports: JSON-LD as recommended structured data format, Rich Result eligibility requirements throughout Section 4.
3. Google. Robots.txt specifications. Google Search Central, 2024. https://developers.google.com/search/docs/crawling-indexing/robots/intro Supports: robots.txt Disallow syntax and crawl budget management recommendations in Section 2.
4. Google. Manage crawl budget for large websites. Google Search Central, 2024. https://developers.google.com/search/docs/crawling-indexing/large-site-managing-crawl-budget Supports: crawl budget framework and waste URL identification in Section 2.
5. Shopify. Robots.txt liquid template. Shopify Help Centre, 2024. https://help.shopify.com/en/manual/online-store/robots-txt Supports: Shopify robots.txt API implementation method (Liquid template, not flat file) throughout Section 2.
6. Shopify. Theme Liquid Reference — canonical_url. Shopify Dev Docs, 2024. https://shopify.dev/docs/api/liquid/objects/canonical_url Supports: Shopify canonical URL Liquid object usage in Section 1 Finding 1.2.4.
7. Schema.org. Product. Schema.org, 2024. https://schema.org/Product Supports: Product schema field definitions and requirements throughout Section 4.
8. Google. Product structured data. Google Search Central, 2024. https://developers.google.com/search/docs/appearance/structured-data/product Supports: Product schema mandatory and recommended fields in Section 4.2.
9. Google. Deprecation of rel=next/prev. Google Search Central Blog, 2019. https://developers.google.com/search/blog/2019/09/the-rel-next-and-prev Supports: Section 1 Finding 1.2.11 — rel=”next”/”prev” deprecated since 2019.
10. Google. Page Experience signals in Google Search. Google Search Central, 2024. https://developers.google.com/search/docs/appearance/page-experience Supports: Core Web Vitals as confirmed Google ranking signals throughout Section 3.
shopifystore1.co.uk — Shopify SEO Live Project Stage 1: Foundation Applied: Shopify SEO Master Prompt v1.0 aiseojournal.net | March 2026 Next stage: Stage 2 — Visibility (keyword architecture, collection briefs, product page optimisation)
SECTION 8B — GSC KEYWORD OPPORTUNITY BASELINE
Why This Belongs in Stage 1, Not Stage 2
Stage 2 builds keyword architecture from scratch using Ahrefs and Semrush. That research takes 10–14 hours and produces a comprehensive keyword universe. But shopifystore1.co.uk already has keyword data that no paid tool can replicate — the actual queries real buyers used to find the store, with real impression and click counts, from Google itself.
The GSC baseline captured in Stage 1 is not a substitute for Stage 2 keyword research. It is a prioritisation signal that tells Stage 2 where to start. A keyword with 1,200 impressions and 8 clicks at position 14 is a confirmed near-miss — Stage 2 should target it first because Google has already decided the store is relevant, it just has not awarded a top-10 position yet.
Pro Tip: The most valuable GSC export for Stage 2 planning is the query list filtered to positions 11–30 with impressions above 50. These are the keywords where shopifystore1.co.uk is closest to page 1. A collection description rewrite and title tag update on the relevant page can move a position-14 keyword to position-7 within 3–4 weeks. That is a faster result than any new content can produce.
8B.1 — GSC Export Protocol
Run all five exports before Stage 2 begins. Store in the master tracking spreadsheet Tab 1 — GSC Baseline.
Export 1 — Near-miss keywords (positions 11–30): GSC → Performance → Search Results → set date range to last 90 days → Queries tab → filter: Position > 10 AND Position < 31 AND Impressions > 50 → Export CSV
These are the highest-priority keyword targets for Stage 2. They confirm genuine Google relevance — the store already shows up, just not on page 1.
Export 2 — Impression-but-no-click queries: GSC → Performance → Queries → filter: Impressions > 100 AND Clicks = 0 → Export CSV
These are title tag and meta description failures. The page ranks — buyers see it — but the title or meta description is not compelling enough to click. Stage 2 fixes these with the formulas from Section 6.
Export 3 — Landing page performance: GSC → Performance → Pages tab → sort by Impressions descending → Export CSV
This shows which Shopify URLs (products, collections, blog posts, pages) earn the most organic visibility. The top 20 pages by impressions are the priority pages for Stage 2 content work.
Export 4 — Query-to-page mapping: GSC → Performance → filter by a specific page URL → view which queries bring traffic to that page → Export per collection and per top product
This reveals two critical insights:
- Queries driving traffic to the wrong page (cannibalisation signal)
- Queries the page ranks for that were never targeted (expansion opportunity)
Export 5 — Device split: GSC → Performance → Devices tab → compare mobile vs desktop clicks and CTR
If mobile CTR is significantly lower than desktop CTR for the same queries, the mobile experience is causing click abandonment — a Stage 3 CRO signal.
8B.2 — GSC Baseline Data Template
Record all values before Stage 2 begins. These become the “before” comparison in every Stage 2 progress report.
| Metric | Value | Date recorded |
|---|---|---|
| Total queries with impressions | ||
| Queries in positions 1–10 | ||
| Queries in positions 11–30 (near-miss) | ||
| Top near-miss keyword #1 | ||
| Top near-miss keyword #2 | ||
| Top near-miss keyword #3 | ||
| Top near-miss keyword #4 | ||
| Top near-miss keyword #5 | ||
| Page with most impressions (non-homepage) | ||
| Collection page with most impressions | ||
| Product page with most impressions | ||
| Blog post with most impressions (if any) | ||
| Total queries with impressions >100 and clicks = 0 | ||
| Mobile CTR vs Desktop CTR gap |
8B.3 — Near-Miss Keyword Prioritisation for Stage 2
After running Export 1, classify every near-miss keyword into one of three categories:
Category A — Collection page opportunity: The keyword is a category-level query (e.g. “women’s wool coats UK”) and the current ranking page is either the homepage, a product page, or a blog post. The correct page (a collection) either does not exist or lacks an optimised description. Action for Stage 2: write a collection page brief targeting this keyword.
Category B — Product page opportunity: The keyword is a specific product query (e.g. “navy merino roll-neck jumper UK size 12”) and the correct product page exists but lacks a keyword-optimised title tag and description. Action for Stage 2: write a product page brief for this specific product.
Category C — Content opportunity: The keyword is informational (e.g. “how to wash merino wool UK”) and no blog post exists targeting it. Action for Stage 2: add to blog content cluster brief.
| Near-miss keyword | Current position | Impressions (90 days) | Current ranking page | Category | Stage 2 action |
|---|---|---|---|---|---|
| [KW 1] | A/B/C | ||||
| [KW 2] | A/B/C | ||||
| [KW 3] | A/B/C | ||||
| [KW 4] | A/B/C | ||||
| [KW 5] | A/B/C | ||||
| [KW 6] | A/B/C | ||||
| [KW 7] | A/B/C | ||||
| [KW 8] | A/B/C | ||||
| [KW 9] | A/B/C | ||||
| [KW 10] | A/B/C |
✅ CHECKPOINT — SECTION 8B
- [ ] Export 1 (near-miss keywords): completed, sorted by impressions descending, top 10 categorised
- [ ] Export 2 (impression-no-click): completed, count recorded, top 10 pages identified for title/meta rewrite
- [ ] Export 3 (landing pages by impressions): completed, top 20 pages identified and listed
- [ ] Export 4 (query-to-page mapping): completed for all collection pages and top 10 product pages
- [ ] Export 5 (device split): completed, mobile vs desktop CTR gap recorded
- [ ] Near-miss classification table: all 10 rows completed before Stage 2 keyword research begins
- [ ] Tracking spreadsheet Tab 1 — GSC Baseline: all values recorded with date
SECTION 8C — COMPETITOR SERP SNAPSHOT PER COLLECTION
Why Competitor Analysis Belongs in Stage 1
Stage 2 writes collection page descriptions that are designed to be content-superior to every existing top-10 result. That superiority has to be specific — not assumed.
The Meridian Cloth Co. International SEO Live Project found that 0 of 5 competitors in the US market had a Quick Answer block, a pricing table, FTC compliance disclaimers, or DDP shipping stated. That finding was not a guess. It was a SERP snapshot taken at the start of the project.
Without the same snapshot for shopifystore1.co.uk, Stage 2 collection briefs cannot state what “content-superior” means for each specific collection keyword. The competitor snapshot makes that concrete.
Pro Tip: Run every SERP snapshot in Google Chrome incognito with the location set to the target city (Chrome → three dots → Settings → Search Engine → Manage Search Engines → or use a browser extension like Location Guard). A SERP checked from the store’s server location will show locally biased results. A buyer in Manchester searching “women’s wool coats UK” sees a different page-1 than a buyer in London. Check from a neutral location — set to your most commercially important UK city.
8C.1 — SERP Snapshot Protocol
Run this for every collection page before Stage 2 begins. One SERP per primary keyword.
Per collection — record these 8 data points for the top 5 organic results:
| Data point | How to check |
|---|---|
| Competitor URL | Copy from SERP |
| Domain | Note the root domain |
| Word count | Paste URL into Ahrefs Site Explorer or count manually |
| Has Quick Answer block | View the page — is there a direct-answer paragraph before the first H2? |
| Has pricing information | Does the page show prices or price ranges? |
| Has FAQPage (PAA expansion) | Does a People Also Ask block appear within/below this result in the SERP? |
| Schema types present | Paste URL into Google Rich Results Test |
| H1 content | View source or browser inspect |
8C.2 — Competitor Gap Table Template
One table per collection. Complete before Stage 2 collection brief is written.
COLLECTION: [Collection Name] | Primary keyword: [TARGET KEYWORD]
| Element | Competitor 1 | Competitor 2 | Competitor 3 | Competitor 4 | Competitor 5 | shopifystore1.co.uk target |
|---|---|---|---|---|---|---|
| Domain | shopifystore1.co.uk | |||||
| Word count | 400–500 words | |||||
| Quick Answer block | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅ Required |
| Pricing table | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅ Required |
| FAQPage schema | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅ Required |
| UK delivery stated | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅ Required |
| UK sizing stated | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅ Required |
| Named certification | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅ Required |
| H2 structure (count) | 3–4 H2s | |||||
| BreadcrumbList schema | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | ✅ Required |
Key finding statement (complete before Stage 2 brief): “X of 5 competitors ranking for [keyword] have a Quick Answer block. X of 5 have a pricing table. X of 5 have FAQPage schema. shopifystore1.co.uk launches as content-superior on [N] of these dimensions from day of publication.”
This statement becomes the opening context of every Stage 2 collection brief.
8C.3 — Collection SERP Snapshot Priority Order
| Priority | Collection | Primary keyword to snapshot | Reason |
|---|---|---|---|
| 1 | Highest-revenue collection | [TARGET KW] | Most commercial — fix first |
| 2 | Highest-impression collection (from GSC 8B) | [TARGET KW] | Already visible — optimise for clicks |
| 3 | Best near-miss collection (positions 11–20) | [TARGET KW] | Closest to page 1 |
| 4 | Remaining collections | [TARGET KW per collection] | Systematic — lower priority |
8C.4 — Top Competitor Domain DR Baseline
Record DR for the top 3 ranking domains per collection keyword. This sets realistic Stage 2 and Stage 3 expectations.
If the top 3 results are all DR 70+ domains (major retailers, editorial sites): the collection page cannot outrank them on domain authority alone. Content superiority + specific long-tail targeting + schema richness + E-E-A-T signals are the path — not expecting to displace a DR 85 site from position 1 within 3 months.
If the top 3 results are DR 20–40 domains with thin content and no Quick Answer blocks: shopifystore1.co.uk can realistically reach top 3 within 4–8 weeks of publishing a properly optimised collection description.
| Collection | Keyword | Rank 1 domain | DR | Rank 2 domain | DR | Rank 3 domain | DR | Assessment |
|---|---|---|---|---|---|---|---|---|
| Realistic top 3 within X weeks | ||||||||
| Realistic top 5 within X months | ||||||||
| Long-term target — 6+ months |
✅ CHECKPOINT — SECTION 8C
- [ ] SERP snapshots: completed for all collection primary keywords — one snapshot per collection
- [ ] Competitor gap tables: all rows completed for each collection
- [ ] Key finding statements: written per collection — “X of 5 competitors have Quick Answer block”
- [ ] Competitor DR baseline: recorded for top 3 results per collection keyword
- [ ] Realistic timeline assessment: documented per collection before Stage 2 brief is written
- [ ] Data saved in tracking spreadsheet Tab 2 — Competitor Snapshots
SECTION 8D — INSTALLED APP AUDIT TABLE
Why App Inventory Belongs in Stage 1
Stage 1 Section 3 addressed Core Web Vitals caused by app scripts. Stage 3 E-E-A-T builds trust signals — some of which come from apps (reviews, loyalty programmes, trust badges). Stage 4 CRO audits the conversion funnel — which is heavily shaped by app functionality (cart drawers, upsell popups, wishlist widgets).
All three later stages need to know what apps are installed, what they do, whether they are actively generating revenue or measurable results, and what their performance cost is.
Without a completed app audit in Stage 1, Stage 2, 3, and 4 make recommendations that might conflict with — or duplicate — existing app functionality.
Pro Tip: The average Shopify store has 6–12 installed apps. At least 2–3 of those apps are almost always inactive — installed for a one-off purpose, never removed, still loading scripts on every page. Each inactive app adds 50–300ms of JavaScript to page load. On a store with 4 inactive apps, removing them can improve LCP by 200–600ms with zero development work. The app audit in Stage 1 is the highest-ROI 30-minute task available to any Shopify store.
8D.1 — App Audit Protocol
Step 1 — List all installed apps: Shopify Admin → Apps → All apps → Screenshot or copy the full list.
Step 2 — For each app, record the following:
| Field | How to find it |
|---|---|
| App name | Shopify Admin → Apps |
| Function | App listing page description |
| Monthly cost | Shopify Admin → Apps → [app] → Billing |
| Actively used? | GA4: does this app’s function generate tracked events? Is the admin dashboard being checked monthly? |
| Loads scripts on storefront? | Shopify Admin → Online Store → Themes → Edit code → Layout/theme.liquid → search for app name |
| JavaScript payload size (KB) | Chrome DevTools → Network tab → filter by app domain → sum KB |
| LCP impact | PageSpeed Insights before and after disabling via Preview theme |
| INP impact | Lighthouse → Performance panel → Main thread activity |
| Revenue or conversion attribution | Is there a GA4 event or revenue metric attributable to this app? |
| Recommendation | Keep / Optimise / Remove |
8D.2 — App Audit Table
Complete this table before Stage 2 begins. Share with developer and store owner — removing any app requires sign-off.
| App name | Function | Cost/mo | Active? | JS on storefront? | JS size (KB) | LCP impact | Recommendation | Dependency |
|---|---|---|---|---|---|---|---|---|
| [App 1] | ✅/❌ | ✅/❌ | +Xms | Keep/Remove | None | |||
| [App 2] | ✅/❌ | ✅/❌ | +Xms | Keep/Remove | None | |||
| [App 3] | ✅/❌ | ✅/❌ | +Xms | Keep/Remove | Stage 3 review programme | |||
| [App 4] | ✅/❌ | ✅/❌ | +Xms | Defer load | Dev | |||
| [App 5] | ✅/❌ | ✅/❌ | +Xms | Keep/Remove | None | |||
| [App 6] | ✅/❌ | ✅/❌ | +Xms | Keep/Remove | None |
8D.3 — App Categories and Stage Dependencies
| Category | Examples | Stage dependency | SEO relevance |
|---|---|---|---|
| Reviews | Judge.me, Okendo, Yotpo | Stage 3 — S16 review programme | Critical — aggregateRating schema |
| Email / CRM | Klaviyo, Omnisend | Stage 3 — S16 review email sequence | Post-purchase review requests |
| SEO app | SearchPie, JSON-LD for SEO, SEO Manager | Stage 1 — S4 schema | Confirm no schema duplication |
| Page speed | Crush.pics, Booster | Stage 1 — S3 CWV | Confirm active and effective |
| Upsell / cross-sell | ReConvert, CartHook | Stage 4 — S21 CRO | Cart value optimisation |
| Loyalty / rewards | Smile.io, LoyaltyLion | Stage 3 — S14 E-E-A-T | Trust signal if visible on product pages |
| Currency converter | Bold, BEST Currency | Stage 4 — S19 international | Required if international expansion proceeds |
| Live chat | Tidio, Gorgias | All stages — performance risk | High INP risk — must be deferred |
| Social proof | Fomo, Sales Pop | Stage 4 — S21 CRO | Moderate LCP risk |
| Subscriptions | Recharge, Bold Subscriptions | Stage 2 — S10 collection briefs | May require separate collection pages |
8D.4 — App Removal Decision Framework
Remove an app immediately if ALL three conditions are met:
- The function it performs is not generating any measurable revenue or conversion event in GA4
- It loads JavaScript on the storefront (even deferred scripts add weight)
- No Stage 2, 3, or 4 action depends on it
Do NOT remove without confirming:
- The app does not store customer data that would be lost on uninstall (loyalty points, subscription records, review data)
- The merchant has been informed and has approved removal
- The equivalent function is not needed in any later stage
8D.5 — SEO App Conflict Check (Critical)
If any SEO app is installed alongside manually deployed schema from Stage 1 Section 4, there is a schema duplication risk. Check for conflicts now.
Conflict check procedure:
- Open any product page
- View source → Ctrl+F:
application/ld+json - Count the number of
<script type="application/ld+json">blocks - If more than one block outputs
"@type": "Product"→ duplication confirmed
Resolution:
- If SEO app outputs Product schema: disable the manual Liquid Product schema from Stage 1 Section 4.2
- If SEO app schema is incomplete (missing fields): keep the manual schema, disable the SEO app’s Product schema output in the app settings.
- Never run both simultaneously — validator.schema.org will show duplicate entity warnings that reduce schema eligibility.
| Page type | SEO app schema found? | Manual Liquid schema deployed? | Conflict? | Resolution |
|---|---|---|---|---|
| Product pages | ✅/❌ | ✅/❌ | ✅/❌ | |
| Collection pages | ✅/❌ | ✅/❌ | ✅/❌ | |
| Blog posts | ✅/❌ | ✅/❌ | ✅/❌ | |
| Homepage | ✅/❌ | ✅/❌ | ✅/❌ |
✅ CHECKPOINT — SECTION 8D
- [ ] App inventory: complete list from Shopify Admin — all apps documented in audit table
- [ ] JavaScript payload: measured per app via Chrome DevTools for all apps loading on storefront
- [ ] LCP impact: PageSpeed Insights tested with each app disabled via Preview theme
- [ ] Inactive apps: all identified — removal approved by store owner and actioned
- [ ] SEO app conflict: schema duplication check run on all 4 page types — 0 duplicates confirmed
- [ ] Stage dependency map: all apps that Stage 2, 3, or 4 depend on are documented
- [ ] App audit table: saved in tracking spreadsheet Tab 3 — App Audit
REVISED STAGE 1 COMPLETION CHECKLIST (UPDATED)
The original Stage 1 completion checklist from Section 8 remains in full. Add these three confirmations before Stage 2 begins:
GSC Baseline (Section 8B) — all must be ✅:
- [ ] Near-miss keywords (positions 11–30): top 10 identified and categorised as A/B/C
- [ ] Impression-no-click queries: all identified — top 10 pages queued for title/meta rewrite
- [ ] Landing pages by impressions: top 20 recorded in tracking spreadsheet
- [ ] Query-to-page mapping: completed for all collections and top 10 products
- [ ] Baseline data table (Section 8B.2): all rows completed with values and date
Competitor Snapshots (Section 8C) — all must be ✅:
- [ ] SERP snapshot: completed for every collection primary keyword
- [ ] Competitor gap tables: all 10 columns completed per collection
- [ ] Key finding statement: written per collection (“X of 5 competitors have…”)
- [ ] Competitor DR baseline: recorded per collection — realistic timeline documented
App Audit (Section 8D) — all must be ✅:
- [ ] App inventory: complete — all apps in audit table
- [ ] Inactive apps: removed (after merchant approval)
- [ ] Schema duplication: 0 conflicts confirmed across all 4 page types
- [ ] Stage dependency map: all apps that later stages depend on documented
- [ ] LCP re-test after app removals: PageSpeed Insights run — improvement recorded
