What an ecommerce SEO audit actually checks
An ecommerce SEO audit is a structured walk through everything that stops a search engine or an AI answer engine from finding, crawling, indexing, and correctly understanding your store. On Shopify specifically, that means checking Search Console coverage, hunting down the duplicate collection and product URLs that faceted navigation creates, verifying canonical tags actually point where you think they do, measuring site speed against Core Web Vitals, confirming structured data matches what a shopper sees, reviewing content depth on collections and product pages, mapping internal linking, and checking whether AI search systems can parse your catalogue at all.
That order matters. A crawl problem upstream masks every downstream signal. You cannot meaningfully audit content quality on a page Google has not indexed, and you cannot meaningfully audit structured data on a URL that is itself a duplicate of another one. Work top to bottom.
This audit is written for stores at $3M–$30M in revenue running Shopify Plus or a comparable paid subscription platform, with product catalogues large enough that faceted navigation and variant handling are doing real work: a five-SKU store does not have this problem. If your catalogue is small and your navigation has no filters, most of this audit is still worth thirty minutes, but the faceted-navigation sections will find nothing to fix, which is itself useful to confirm.
Prerequisites: what you need before you start
Get access to four things before opening a single report:
- Google Search Console, verified on the domain property (not just the
wwworhttpsprefix version) so you see every subdomain and protocol variant in one place. - Shopify admin, with permission to view theme code (Online Store → Themes → Edit code) — you will need to read
theme.liquidand the collection template. - A crawler. Screaming Frog’s free tier covers up to 500 URLs, enough for most collection and navigation checks; a paid crawler or a Search Console-only approach works if your catalogue is larger.
- PageSpeed Insights or a Core Web Vitals report — either the field data in Search Console’s Core Web Vitals report or a fresh PageSpeed Insights run on your three highest-traffic collection and product pages.
Skip any step you cannot access rather than guessing at it. A canonical tag check done from memory instead of the actual theme file is worse than not doing it, because it produces false confidence.
Step 1: Pull crawl and indexation data from Search Console
Open Search Console’s Indexing → Pages report. You are looking for four status buckets specifically:
- Crawled – currently not indexed: Google visited the page and chose not to index it. On ecommerce sites this usually means thin content (a collection with no description, one product image, and nothing else) or a page Google judged near-duplicate to another.
- Discovered – currently not indexed: Google knows the URL exists but has not crawled it yet, often a crawl-budget symptom on catalogues with thousands of SKUs.
- Duplicate without user-selected canonical: Google sees multiple URLs as the same content and you have not told it which one is authoritative.
- Duplicate, Google chose different canonical than user: you set a canonical tag, and Google ignored it. This is a signal, not an error message. It means your canonical choice conflicts with Google’s own read of the content, usually because the “canonical” page and the “duplicate” page are not actually similar enough for Google to treat the tag as trustworthy.
Export the URL list behind each bucket. You will cross-reference it against the crawl in Step 2.
Step 2: Find the duplicate collection and product URLs faceted navigation creates
Crawl your site with the collection and product templates included, then sort the resulting URL list by base path. On a Shopify store using filtered collections, you will see patterns like:
/collections/mens-shoes
/collections/mens-shoes?filter.v.price.gte=5000
/collections/mens-shoes?filter.v.availability=1
/collections/mens-shoes?filter.v.option.color=Black&filter.v.price.gte=5000
Each of those is a distinct, crawlable URL rendering near-identical product grids with a different sort or filter applied. Shopify’s Search & Discovery app and most filter-capable themes generate these parameters automatically the moment a shopper applies a filter. The store owner never types them, and never sees them unless a crawl or Search Console coverage report surfaces them.
Count how many filtered variants of each collection have been indexed (cross-reference against your Step 1 export). A store with a dozen collections and five filter facets can produce hundreds of these combinations if nothing is blocking them, all competing with each other and with the clean collection page for the same ranking signals.
Step 3: Verify canonical tags actually point to the clean URL
Open theme.liquid in the Shopify code editor and confirm the canonical tag in the <head> reads something close to:
<link rel="canonical" href="{{ canonical_url }}">
That part is standard and correct in almost every Shopify theme. Shopify populates canonical_url automatically for product and collection pages. The failure is not usually in this line. It is in what canonical_url resolves to on a filtered URL. Load one of the filtered URLs you found in Step 2 directly in a browser, view source, and check the rendered canonical tag by hand.
Three outcomes are possible:
- It correctly resolves to the base collection URL:
/collections/mens-shoeswith no query string. This is the desired state, with filtered views telling Google “I am a variant of this page, index that one instead.” - It self-references. The canonical tag includes the same filter query string as the page itself. This tells Google each filter combination is its own canonical page, which is precisely what produces the “Duplicate without user-selected canonical” bucket in Search Console.
- It is missing entirely on the filtered view. Some third-party filter apps render results via JavaScript after the initial page load, and the canonical tag present in the server-rendered HTML never updates to reflect the applied filter, or updates to something unrelated.
Outcome 2 is the most common, and it is usually caused by a filter/search app that was installed to improve on-site search and, as a side effect, changed how filtered URLs render their <head>. Check the app’s settings for a “canonicalize filtered pages” or “SEO settings” toggle before assuming you need custom code. Several popular filter apps ship this as an off-by-default option.
Step 4: Audit site speed against Core Web Vitals
Run PageSpeed Insights against your highest-traffic collection page and highest-traffic PDP separately — they usually fail on different metrics.
Collection pages most often fail Largest Contentful Paint (LCP), because the largest visible element is a grid of product images loading simultaneously. Check whether your theme sets loading="eager" and fetchpriority="high" on only the first two or three above-the-fold product images, with loading="lazy" on the rest. A theme that lazy-loads everything, including the first row, delays LCP unnecessarily; a theme that eager-loads everything wastes bandwidth on images the shopper has not scrolled to.
Product pages more often fail Interaction to Next Paint (INP). This measures responsiveness to clicks: variant selection, add-to-cart, quantity changes. The usual cause is not your theme but a third-party app: review widgets, upsell modals, and live chat scripts that each register their own event listeners on the page. Use Chrome DevTools’ Performance panel to record a variant-selector click and check which script is blocking the main thread; it is rarely the theme’s own code.
Shopify’s built-in image CDN can resize and re-compress images on the fly by appending a width parameter to the image URL (?width=800). This is the fastest fix for oversized product images if your theme is not already using it. Check the theme’s image tags for a bare {{ product.featured_image | image_url }} with no width argument, which serves the full-resolution upload to every device.
Step 5: Check structured data on collections and PDPs
Pull up the rendered HTML (not the theme file — the actual page source, since apps can inject or override schema) and search for application/ld+json. On a product page you want:
Productschema withname,image,offers(price andavailability), andaggregateRatingif you display reviews on the page.BreadcrumbListschema matching the visible breadcrumb trail.
The most common failure is not absence but mismatch. The schema block exists, often injected by a reviews or SEO app, but its availability or price value has gone stale relative to the visible page. Usually because the app that renders the schema is not the same one managing inventory sync. Google’s structured data testing does not catch this, because the markup is syntactically valid. It just does not match what the page shows, which is the exact pattern Google’s guidelines call out as spam-schema, whether or not it was intentional.
Collection pages rarely need Product schema on the collection itself — that belongs to each product it links to. A BreadcrumbList and, if the collection functions as a category hub, CollectionPage or ItemList schema is worth adding if your theme does not already include it.
Step 6: Review content depth on collections and PDPs
Open the three collections and three products with the lowest organic sessions relative to their catalogue position. A best-seller with no organic traffic is a stronger signal than a slow-mover with none. Check for:
- A collection description that exists only as a single generic sentence, or is empty. Shopify does not require collection description content to render on the page. Many themes hide it below the fold or omit it from the template entirely, which means the field can be filled in the admin and still contribute nothing to what a crawler or a shopper actually sees.
- Product descriptions that are identical, or near-identical with a single word swapped, across variant-driven product families (the same jacket in five colours, each with its own PDP and the exact same copy). This mirrors the faceted-URL duplication problem in collection pages, except it is a content decision rather than a technical default.
- Missing answers to the questions a shopper actually has at the point of decision: sizing, materials, care, and shipping specifics. These get pushed into a separate policy page instead of being answered on the PDP itself.
Content depth here does not need to be long. It needs to say something a competitor’s identical product page does not.
Step 7: Map internal linking gaps
List every collection and every high-value product, then check two directions: what links to it, and what it links to. The two failure patterns worth fixing:
- Orphaned collections: a seasonal or niche collection that exists and is indexed but has no link pointing to it from the main navigation, another collection, or a blog post. It can only be found by someone who already knows the URL or by search.
- Flat blog-to-catalogue linking: a content programme that never links from an article into the relevant collection or product in prose, relying instead on a generic “shop now” button in the sidebar. A shopper reading an article about running shoe cushioning should reach the running shoes collection through a sentence, not a button. The same link also tells Google what that collection is about, which a sidebar button does not.
Track this over time rather than once. Shopify’s built-in analytics do not report internal link structure, which is a genuine gap worth naming rather than working around with a guess. A dashboard that surfaces organic sessions by landing page over time (see /blog/shopify-dashboards for what Shopify’s native reporting does and does not cover) makes it obvious when a page’s traffic drops off a cliff, which is often the first symptom of a broken internal link rather than a ranking change.
Step 8: Check AI search visibility
Everything above serves Google’s crawler primarily, but the same structural problems: thin content, duplicate URLs, mismatched schema, block AI answer engines too. Most of them draw on the same indexed web rather than crawling your store independently. Two checks specific to this layer:
- Confirm your
Productschema (Step 5) is complete, since several AI shopping surfaces read structured data directly rather than parsing rendered page text. - Check whether an
llms.txtfile exists and lists your key collections and policy pages. It is a proposed convention with partial adoption, not a ranking mechanism, and the detail of what it should and should not contain is covered at /blog/llms-txt.
Tracking whether your brand and products actually surface in AI answers is a separate, ongoing measurement problem from the one-time audit. A tool like /tools/ai-visibility-tracker gives a repeatable way to check that over time rather than guessing from anecdote.
The step most teams get wrong
Most audits stop at Step 3 having checked that theme.liquid contains a canonical tag, and call the canonical question closed. That is checking the template, not the output. The step that actually catches the problem is loading the filtered URLs Google has already indexed: the ones from your Step 1 export. Then read the canonical tag each one renders individually, because Shopify’s filter apps frequently override the theme’s default canonical behaviour on client-rendered filter results without touching theme.liquid at all. A theme file that looks correct and a live page that renders incorrectly are not the same finding, and only one of them is what Google is actually crawling.
How to verify the audit worked
Re-run the Search Console coverage export four to six weeks after making changes — Google needs to recrawl and reprocess before coverage numbers move, and checking sooner just measures the old crawl. Look specifically for the “Duplicate without user-selected canonical” bucket shrinking, and for previously “Crawled – currently not indexed” collection pages moving to indexed once their content or canonical was fixed. A Core Web Vitals re-check needs 28 days of field data in Search Console before the report reflects a change at all. A same-day PageSpeed Insights score improving is a lab-data signal, useful for confirming the fix shipped, not proof the field data has caught up yet.
Rebuilding these exports by hand every audit cycle is exactly the kind of scheduled, repeatable API call — hit the Search Console API, diff the coverage buckets against last quarter’s export, flag what changed — that an automation platform like n8n is built for, run on infrastructure you control rather than a SaaS dashboard reformatting the same numbers. Where that becomes worth setting up rather than doing by hand in a spreadsheet each quarter, and where the judgement calls in Steps 2 through 7 still need someone reading the actual pages, is the AI agents and automation problem behind /services/ai-agents.
Sources
- This article quotes no external statistics or cleared figures. It is written from Shopify’s own theme and canonical-tag defaults, Google Search Console’s published report categories, and Google’s Core Web Vitals thresholds, all of which are checkable directly in each platform’s own documentation and dashboards rather than cited as third-party research.