Most Shopify stores do not have a content problem when their rankings stall. They have a technical problem that no new blog post can fix. Google can find the same product at several different URLs, a market version can point its canonical tag at the wrong country, and filtered collections can quietly eat the crawl budget meant for bestsellers. The store looks fine in a browser, because browsers do not care which URL serves a page. Search engines do.
This is the developer version of a Shopify SEO audit. It skips generic advice about titles and descriptions, which is covered elsewhere, and focuses on the four places where Shopify creates technical risk by design: duplicate URLs, canonical tags, international versions, and crawl diagnosis. Work through it in order, and fix what you find before spending on new content or links.
What Shopify handles for you, and what it does not
Shopify does useful technical work out of the box. It generates the XML sitemap, serves pages over HTTPS, blocks cart, checkout, account, and preview URLs in robots.txt by default, and outputs a canonical tag on pages in its own themes. When Shopify Markets is configured, it also generates hreflang tags between market versions.
None of that proves your store is set up correctly. Themes get edited, apps inject their own tags, products get renamed, and markets get added without anyone checking the output. This checklist is about verifying what Shopify is actually doing on your live pages, not what it is supposed to do in theory. As a Shopify developer focused on speed and conversion, I run this sequence on client stores before touching content, because a canonical or hreflang fault can undo months of otherwise good SEO work.
1. Map every duplicate URL family before you fix anything
Shopify creates duplicate URLs by design, and each family needs a different fix. Treating them all as one problem is how stores end up blocking pages they wanted indexed, or canonicalising pages that should have stayed separate. Start with one real product and trace every way to reach it:
- The clean product URL: /products/product-handle. This is the version that should rank.
- The collection path: /collections/collection-handle/products/product-handle. The same product reached through a collection, and the duplicate most stores miss.
- The variant parameter: /products/product-handle?variant=123456789. One product with one variant selected. Useful for shoppers, useless as a separate indexed page.
- Sort and filter parameters: /collections/collection-handle?sort_by=price-ascending and filter query strings. These reorder or narrow the same collection. They are not new content.
- Tag pages: /collections/all/tag-name. These can be genuine landing pages when the tag is a real category shoppers search for, and thin duplicates when it is not. Judge them one by one.
- Paginated collections: /collections/collection-handle?page=2. A continuation of the same collection, not a duplicate of page one, and it should stay crawlable so deeper products get found.
- Market versions: /en-gb/products/product-handle or a country domain version. These are alternates, not duplicates, provided they are localised and linked with hreflang. Section 4 covers that distinction.
Write the list down for one product, one collection, and one market version. If you cannot explain, for each URL, whether Google should index it, consolidate it, or ignore it, you do not have a fix yet. You have a guess.
2. Audit canonical tags on live pages, not in theme code alone
The canonical tag is the most important technical SEO element on a Shopify store, and the easiest to break silently. A theme update, a new app, or a copied snippet can leave two canonical tags on a page, point a canonical at a collection path, or drop the tag from one template while leaving it intact elsewhere.
Check it the way Google sees it. Open a product through a collection, view page source, and search for rel=”canonical”. It should point to the clean /products/product-handle URL. Repeat the check on a product opened directly, on a sorted collection, on a filtered collection, on a blog post, and on a market version. One template passing does not prove the others pass.
In a standard theme, the tag comes from one line in theme.liquid:
<link rel="canonical" href="{{ canonical_url }}" />
Shopify fills in canonical_url for you. On a collection path product page it still resolves to the clean product URL, and on a sorted collection it resolves to the base collection URL without the sort parameter. Do not hand write canonical URLs per template unless you have a specific reason and you test the output on every template.
Watch for four faults: two canonical tags, usually from a theme and an app both injecting the tag; a canonical pointing at a collection path, often from custom code that builds the URL from the current request; a canonical pointing at a different market, which tells Google the page is a duplicate; and Google choosing a different canonical in Search Console, which usually means internal links, sitemap entries, or hreflang signals contradict your tag. Fix the contradiction, not just the tag.
For the strategy side of ranking, read the Shopify SEO guide on this site. This article stays on the technical checks that strategy depends on.
3. Fix internal links so they point at the canonical URL
Canonical tags consolidate ranking signals, but internal links decide which URL Google discovers first. Many themes link products from collection grids using the Liquid within filter, which builds the collection path version:
{{ product.url | within: collection }}
That link works for shoppers, and the canonical tag still points to the clean product URL, so nothing looks broken. The problem is quieter. Every collection grid, related product block, and search result using the within filter sends crawlers to the duplicate URL first, then relies on the canonical tag to send them back. On a large catalog, that is thousands of internal links pointing away from the URL you want to rank.
Where the theme allows it, link collection grids straight to the product URL:
{{ product.url }}
Make the change on a duplicate theme first, check that breadcrumbs and any app reading the referring collection still behave, and only then publish. Some stores keep the collection path deliberately because a feature depends on it. That is a valid trade off, but it should be a decision, not an accident left over from default theme code.
Do not try to fix collection path duplicates with robots.txt. Blocking the collection path stops Google crawling it, but a blocked URL can still be indexed without content, and blocking interferes with internal linking signals. Canonical tags are the tool for structural duplicates. Robots.txt is the tool for parameter variants, covered in section 6.
4. Hreflang and Shopify Markets: stop countries competing with each other
International SEO is where small mistakes cost the most, because the fault is invisible in the default market and only shows up in the market you are trying to grow. When Shopify Markets is configured with a subfolder or domain per market, Shopify generates hreflang tags automatically. Verify that output on the same product in two markets:
- Each market page has a self referencing canonical. The UK page should canonicalise to itself, the US page to itself. A shared canonical across markets tells Google the pages are duplicates of one version, and it is the most common international fault on Shopify stores.
- Each page lists every alternate, including itself, with hreflang. The set should be reciprocal. If the US page lists the UK alternate but the UK page does not list the US alternate, Google may ignore the set for that page.
- There is one hreflang set, not two. If a translation app or old theme snippet adds its own hreflang tags on top of the automatic tags, you get duplicate and possibly conflicting sets. Turn off one source.
- An x-default tag points at your global fallback page, usually the primary market version. It tells Google which version to show when no language or region matches.
Hreflang alone does not solve near duplicate markets. If US and UK pages carry identical English copy, identical prices in the same currency, and identical shipping text, Google may ignore hreflang and treat them as duplicates anyway. Localise spelling, currency, sizing, shipping thresholds, returns wording, and top product copy first. Even small, honest differences help Google treat each market page as a real version for its audience.
The same rule applies in reverse. If two country URLs carry materially identical content and you have no plan to localise them, do not rely on hreflang to separate them. Canonicalise them to a single primary version until localisation is real.
Choose subfolders as the default market structure unless you have a specific reason for separate domains. Subfolders keep authority on one domain. Separate domains can make sense for a brand with strong local trust and the resources to build links per domain, but they split authority and multiply the hreflang and Search Console work.
5. Redirects: one hop, per locale, no orphaned handles
Shopify only lets you redirect from a URL that no longer loads a page, so order matters: delete or unpublish the old page first, then create the redirect. You cannot redirect reserved paths such as /cart, /orders, or /apps, and tag filtered collection URLs cannot be redirected like a normal page.
- Create a 301 redirect for every changed product, collection, page, and blog handle, and check it with a live request, not just in the admin list.
- Reduce chains to a single hop. If URL A redirects to B and B redirects to C, point A straight at C. Chains accumulate across theme changes and leak ranking signals.
- Add redirects per market locale. A redirect on the primary domain does not automatically cover every market subfolder. Test the redirected URL in each market where that product was sold.
- Decide what happens to discontinued products. Redirect to a close replacement or the parent collection when the old page has no ongoing value, or keep the page live with links to alternatives when it still earns traffic or links.
- Audit redirects after every theme change and app install. Export the list quarterly and look for loops, chains, and redirects pointing at deleted pages.
6. Crawl diagnosis: find out why pages are not indexed, in order
When indexed pages drop or new products do not appear, store owners usually start by resubmitting the sitemap or rewriting content. Both steps are premature. Run this diagnosis in order, and stop at the first step that explains the symptom.
Step 1: Check what Google actually indexed. In Search Console, open Pages under Indexing and sort by status. “Duplicate, Google chose different canonical than user” points back to section 2. “Crawled, currently not indexed” usually means Google decided the page added too little value, which is a content or duplication verdict. “Discovered, currently not indexed” means Google knows the URL exists but has not crawled it yet, which points at crawl budget or linking depth. “Blocked by robots.txt” and “Excluded by noindex tag” are configuration verdicts. Each status has a different fix.
Step 2: Inspect one affected URL. Use URL Inspection on a product that should rank and one that should not. Confirm crawl allowed, the canonical Google selected, the last crawl date, and whether the page rendered fully.
Step 3: Check crawl waste. Look for budget going to internal search pages at /search, sort and filter parameter variants, preview URLs, and session parameters. This is where robots.txt earns its place. The guide to editing robots.txt in Shopify covers the exact rules, but the principle is simple: use robots.txt for parameter variants and internal search, canonical tags for structural duplicates, and noindex for pages that should stay live but stay out of search. Mixing those tools up is the most common crawl fault on Shopify stores.
Step 4: Check depth and linking. Confirm every important product is within a few clicks of the homepage and appears in the sitemap. Products linked only from a paginated page deep in a large collection get crawled slowly, if at all.
Step 5: Check the myshopify.com domain. Your store should redirect its myshopify.com subdomain to your custom domain, not serve a second copy there. Search for site:yourstore.myshopify.com and confirm nothing important is indexed under it. A second indexed copy splits signals at whole store scale, exactly like a duplicate product URL.
Shopify does not give you server logs, so this Search Console workflow is the practical substitute. It answers the same question: did Google find the page, could it crawl it, and what did it decide to do with it.
7. Thin, utility, and staging pages: hide them with the right tool
Not every page should be indexed, and deleting every thin page is not the answer. Pick the tool that matches the intent:
- Products, pages, or blog posts to hide from search and sitemaps: Shopify supports a no-code seo.hidden metafield (set to 1) that hides the item from sitemaps, search engines, and storefront search. Use it for staging and seasonal items. For products, setting status to Unlisted achieves a similar result.
- Pages that must stay accessible but out of the index: add a conditional noindex meta tag in theme.liquid for that page type, such as thin tag pages. Noindex is right when the page should be crawled but not shown in results.
- Pages that should never be crawled at scale: block them in robots.txt, such as internal search and filter variants. Blocking does not remove a page already in the index. For urgent removal, use Search Console removal plus noindex, not robots.txt alone.
- Pages that should never have been public: use draft or password protection, not robots.txt. Robots.txt is public, so blocking a URL there announces that it exists.
Audit this set after every major catalog change. Hidden products that go live without the flag removed, seasonal pages left noindexed after launch, and test pages left in the sitemap all look like ranking problems from the outside.
8. Sitemap and structured data: verify, do not assume
Shopify generates and updates the sitemap automatically, including market versions when Markets is configured. Submit it once in Search Console, confirm each market sitemap is present where you use separate market URLs, and recheck it after catalog changes. A sitemap listing hidden, discontinued, or redirected URLs trains Google to distrust it, so the checks in sections 5 and 7 are sitemap hygiene as well.
Structured data deserves the same treatment. Themes and apps can inject duplicate Product schema blocks with conflicting prices, and a theme update can break a schema template without any visible change on the page. Validate Product, BreadcrumbList, and Organization markup with the Rich Results Test after theme changes, and check view source for two Product blocks on the same page. The full field by field guide is in the Shopify product schema markup article, and this checklist deliberately does not repeat it. Schema is part of the technical audit, not a one time install.
The developer audit, in order
- Trace one product through every URL family and record the intended treatment for each URL.
- View source on live product, collection, sorted, filtered, blog, and market pages and confirm each canonical tag.
- Fix collection grid links to point at the clean product URL where the theme allows it, on a duplicate theme first.
- Verify hreflang reciprocity, self referencing canonicals per market, a single hreflang set, and an x-default tag.
- Localise market pages properly, or canonicalise them to one primary version until localisation is real.
- Reduce redirect chains to single hops, add redirects per locale, and decide the fate of every discontinued product.
- Run the five step crawl diagnosis in Search Console before rewriting any content.
- Hide thin and utility pages with the right tool: seo.hidden, noindex, or robots.txt, matched to intent.
- Confirm the myshopify.com domain redirects, the sitemap is clean, and schema validates after theme changes.
Most of these checks take minutes each and cost nothing. Together they answer the question every Shopify store owner eventually asks: is Google seeing the store I think I built, or a duplicated, fragmented version of it. Fix the technical foundation first. Content and links perform far better on a store Google can actually understand.
If this audit turns up broken canonicals across templates, hreflang spanning multiple domains, or crawl problems that persist after the checks above, that is the point to bring in a developer rather than keep guessing. You can hire a Shopify developer through Hamza Taj, or explore the Shopify development services page to see the full scope of technical work available.
FAQs
Does duplicate content on Shopify actually hurt rankings?
Duplicate URLs rarely trigger a penalty on their own. The real damage is quieter: ranking signals split across versions, Google picks the wrong version to show, and crawl budget goes to duplicates instead of products that could rank. Fixing canonicals and internal links consolidates those signals.
Should I block collection product URLs in robots.txt?
No. Collection path product URLs are structural duplicates, and canonical tags are the correct tool for them. Blocking them can leave them indexed without content and interferes with internal linking signals. Reserve robots.txt for parameter variants such as sort and filter URLs, and for internal search pages.
Do I need hreflang if I sell to several countries in English?
Yes, if each country has its own URL, such as /en-us/ and /en-gb/, or separate country domains. Hreflang tells Google which country version to show in each market, even when the language is the same. It only works well when each version is localised with its own spelling, currency, shipping, and returns details.
Why did Google choose a different canonical than the one in my theme?
Google treats canonical tags as a strong hint, not an instruction. When it chooses differently, look for contradictions: internal links pointing at the duplicate, sitemap entries listing the duplicate, hreflang pointing elsewhere, or redirects sending mixed signals. Fix the contradiction, then recheck with URL Inspection after the next crawl.
How do I hide a product from search without deleting it?
Set the seo.hidden metafield to 1 on the product, which hides it from sitemaps, search engines, and storefront search, or set its status to Unlisted. When the product is ready to sell, remove the flag and confirm it reappears in the sitemap before promoting it.
What should I check first when indexed pages suddenly drop?
Start in Search Console, not in your content. Check the Pages report for the status of the dropped URLs, inspect one affected URL for its canonical and crawl status, and check whether a theme update, app install, or market change happened at the same time. Most sudden drops trace back to a canonical, hreflang, redirect, or noindex change.