Most Shopify stores have thousands of duplicate URLs and it does not matter. Google folds them into the canonical page and moves on. The Shopify duplicate content problems that actually cost you traffic are narrower than the audit tools suggest: a broken or overridden canonical tag in the theme, two of your own pages competing for the same query, product pages that share the same 60 words of copy across 40 SKUs, and a crawl budget so diluted by filter combinations that new products take a fortnight to get indexed. Fix those four. Ignore the 8,000-row "duplicate URL" export.
That is the short version. The rest of this is how to tell which of the four you have.
Where Shopify creates duplicate URLs by design
Every product on Shopify is reachable at /products/handle. It is also reachable at /collections/any-collection/products/handle, once for every collection the product sits in. That is not a bug and it is not something you can turn off in settings. Shopify emits a canonical tag pointing at the clean /products/handle URL, so the collection-scoped versions get consolidated.
The others you will see in a crawl:
- Filtered collections — ?filter.v.option.size=M&filter.p.vendor=X and so on, one URL per combination a shopper can click.
- Paginated collections — ?page=2 onwards. These should self-canonicalise. Google dropped support for rel=next/prev years ago, so page 2 is just a page.
- Variant URLs — ?variant=44123456789, generated whenever a shopper picks a swatch.
- Tag views — /collections/shirts/linen. Multi-tag URLs (the ones with a plus sign) are already blocked in Shopify's default robots.txt. Single-tag views are not.
- Search results — disallowed by default.
- The .myshopify.com address — should redirect to your primary domain automatically. Should.
Open view-source on a collection-scoped product URL right now and look at the canonical. If it points at /products/handle with no collection in the path, that half of the problem is already solved and you can stop worrying about it. In Search Console you will see a large "Alternate page with proper canonical tag" count. On Shopify that number is supposed to be large.
The crawl arithmetic, which is the part that does hurt
Consolidation is not free. Googlebot has to fetch a URL before it can read the canonical tag and discard it. On a small catalogue that costs nothing. On a big one it is the whole game.
Take a collection with three filter groups: size with 8 values, colour with 6, availability with 2. The number of distinct filter states is (8+1) × (6+1) × (2+1) = 189, of which 188 are filtered variations of the same collection. Multiply by 40 collections and you have 7,520 filter URLs. Add pagination at 24 products per page on the unfiltered views and you clear 8,000 crawlable URLs for a store whose useful page count is maybe 1,600.
Now check your server logs or the Crawl Stats report. If Googlebot is fetching around 2,000 URLs a day on your store and 80% of those fetches are filter permutations, a full recrawl of the pages that sell things takes over a week. That is why the new arrival you published on Tuesday still is not indexed the following Monday.
Two fixes, in order of how much we trust them:
- Stop linking to junk internally. Product cards in most themes are rendered with product.url | within: collection, which means every internal link to every product points at a non-canonical URL. On a store with 1,400 products averaging 5 collections each, that is 7,000 collection-scoped links and 1,400 canonical ones — 83% of your internal product links aimed at pages you do not want crawled. Drop the within filter and the crawl graph changes shape in a fortnight. The trade-off: you lose breadcrumb context on the product page unless you pass the collection some other way, and some themes use it for "next product in collection" navigation.
- Disallow the filter parameters in robots.txt.liquid. You can edit it since 2021. Adding Disallow: /*?filter.* keeps the permutations out of the crawl entirely. Do not do this if you have deliberately built filtered landing pages you want ranking, and do not disallow pagination, which is how Google reaches deep products in the first place.
If your filtering is bolted on by an app that writes its own URL structure instead of using Shopify's native filter parameters, check what it emits before you write any rules. We have seen apps generate hash-fragment URLs (harmless, invisible to crawlers) and apps that generate a fresh indexable path for every combination (not harmless at all).
The canonical tag your theme quietly broke
This is the one genuine technical failure and it is more common than it should be. Someone edits theme.liquid, the {{ canonical_url }} line gets replaced with a hardcoded canonical, or an SEO app injects a second canonical tag, or a page template outputs a canonical pointing at the homepage. Google then sees two conflicting instructions and picks for itself.
How to check in five minutes: view-source on a product page, a collection page, page 2 of that collection, and a blog article. Search for "canonical". You want exactly one tag per page. The product page should point at itself, page 2 of a collection should point at page 2, not page 1.
The tell in Search Console is "Duplicate, Google chose different canonical than user". A handful of those is noise. Hundreds means your signals disagree with each other, usually because internal links, the sitemap and the canonical tag are all naming different URLs. Shopify's auto-generated sitemap only lists canonical URLs, so if the sitemap and the canonical tag conflict, the theme is what changed.
Duplicate content that is actually duplicate content
Forget URLs for a moment. Take a catalogue where 40 SKUs of the same silhouette share one description block, because that is what the supplier sent and someone pasted it 40 times. Change the colour name, keep everything else. Those pages are not competing with each other in any interesting way, but none of them has enough distinct text to rank for anything except the exact SKU code.
The fix is boring and it works: the first 40 to 60 words of each product page must be written for that product. Fabric, weight, fit note, what it is worn with, care instruction that is actually specific. Below that, a spec table pulled from metafields can be identical across the range and nobody minds. Structured, repeated attributes are fine. Repeated prose is what reads as thin.
Two related habits worth breaking. First, manufacturer copy on a reseller catalogue: if 15 other Indian stores sell the same imported product with the same paragraph, you are the fifteenth candidate for a page Google has already ranked. Second, size or colour split into separate products instead of variants, which multiplies near-identical pages and splits reviews and inventory. Separate products are the right call when the variants have genuinely different search demand and different photography. Otherwise use variants.
Your collection page versus your own blog post
The version of duplication that costs real revenue is keyword cannibalisation, and no crawler flags it as duplicate content. A collection page for "cotton bedsheets" and a blog post titled "Best cotton bedsheets in India" both target the same intent. Google ranks whichever it prefers on the day, the rankings oscillate, and neither page accumulates a stable position.
Check it in Search Console: Performance, filter by query, add the Pages dimension. If two URLs share impressions for the same query and both sit between position 8 and 25, you have found it. Pick the page that converts, point the other one's internal links at it, and either rewrite the loser to serve a different question or 301 it. Deleting content feels wrong and is usually right. Our SEO and content work starts with this audit more often than with anything technical, because it is the fastest thing on the list to fix.
Domains, redirects and the aftermath of a migration
Indian brands frequently run a .in and a .com, sometimes with a legacy WooCommerce or Magento install still answering on a subdomain. Every one of those is a copy of your store as far as a crawler is concerned. One primary domain, everything else 301 redirected at the DNS or registrar level. Not a meta refresh, not a landing page saying "we've moved".
Post-migration, the duplication comes from URL patterns that no longer exist. Magento's /catalog/product/view/id/442 and WooCommerce's /product-category/ paths need mapping to Shopify equivalents, and Shopify's redirect importer takes a CSV, so there is no excuse for skipping it. Where a pattern maps to nothing, redirect it to the closest collection rather than the homepage. We cover the mapping process in more detail on our Shopify migration page. The failure we see most: the old site left live "just in case" for three months, ranking against the new one the whole time.
Markets, currencies and hreflang
If you sell into the UAE and the US from one store using Shopify Markets subfolders, the same product exists at /products/x, /en-ae/products/x and /en-us/products/x. Shopify generates the hreflang annotations and each localised URL self-canonicalises, which is correct behaviour and not something to "fix".
Where it breaks: separate storefronts on separate domains selling the same catalogue in the same language. Then you own the hreflang problem, and if you get it wrong Google picks one domain and serves it to everyone. The dirham price shows up for the Bengaluru shopper, or worse, the other way round. Before splitting into multiple stores, be honest about whether tax, payment and fulfilment genuinely require it. Markets handles more than most founders expect, and one store is one SEO surface instead of three.
The order we work in
On a store we are seeing for the first time, this is the sequence. Canonical tags on four page types, checked by hand. Then Search Console for "Duplicate, Google chose different canonical" volume. Then the internal linking pattern for product cards. Then log files or Crawl Stats to see how much of the crawl is going to filter permutations. Then a query-level cannibalisation pass. Product copy last, because it is the slowest to fix and the least likely to be the reason a page is not ranking.
We get the cannibalisation call wrong maybe a third of the time on the first pass, because deciding whether a tag view is a legitimate landing page or crawl waste depends on demand data we do not have on day one. Give it a month of impression data before you noindex anything that is already getting clicks.
Start with view-source on one product page and one collection page and count the canonical tags. If there is more than one, that is your afternoon sorted. If you want a second pair of eyes on the crawl side, our free store audit covers indexation and internal linking alongside speed, and if the fix turns out to be theme-level, a developer on retainer is cheaper than an SEO tool subscription.


