Shopify serves the same product under several URLs out of the box, which Google reads as duplicate content and which quietly dilutes your rankings. The good news is that the platform already sets some canonical tags for you. The bad news is that this automation is not a free pass. You still have to step in to protect crawl budget and consolidate link equity onto one strong URL.
Key Takeaways
- Shopify creates at least two indexable URLs for every product:
/products/and/collections/[name]/products/. - Canonical tags are hints, not directives. Google does not always follow them.
- Tag-filtered collection pages such as
/collections/shoes/runningare silent duplicate content factories. ?page=1is a free duplicate of every collection page, and Shopify does not canonicalise it for you.- The correct order of fixes is: check canonicals, clean up internal links, apply noindex, and only then touch robots.txt.
What is duplicate content on Shopify?
Duplicate content exists when identical or near-identical content is reachable under more than one URL. To a search engine those are technically different pages, even though a shopper would never notice the difference. Google then has to decide which URL goes into the index and which one gets ignored. It makes that call on its own, and usually not the way you would want.
Shopify produces duplicate content from four main sources:
- Collection-scoped product URLs (the biggest problem)
- Tag-filtered collection pages
- Pagination URLs (
?page=1) - Variant parameters (
?variant=12345)
The four sources in detail
1. Collection-scoped product URLs
This is by far the most common cause. Every product in Shopify is reachable through two paths:
https://your-store.com/products/blue-t-shirthttps://your-store.com/collections/t-shirts/products/blue-t-shirt
Shopify automatically adds a canonical tag on the collection version that points to the /products/ URL. That sounds like a solution, but it only gets you halfway. Canonical tags are recommendations, not instructions. If your internal links keep pointing at the collection-scoped URL, you are sending Google contradictory signals, and Google may well pick the wrong URL as the master version.
The usual trigger: the Liquid filter | within: collection ships in many themes and generates collection-aware links automatically. Every product linked from inside a collection ends up with its own duplicate URL.
The fix in your Liquid template:
Open your product-card.liquid or whichever snippet renders product links. The link should always point at product.url, never at product.url | within: collection:
{# Wrong, creates a collection-scoped URL #}
<a href="{{ product.url | within: collection }}">
{# Right, always points at /products/ #}
<a href="{{ product.url }}">
That single change in your theme code redirects every internal link signal to the canonical URL.
2. Tag-filtered collection pages
Shopify's tagging system is convenient, and it is also a silent duplicate content producer. When customers filter a collection by tag, you get URLs like these:
/collections/shoes/running/collections/shoes/waterproof/collections/shoes/running+waterproof
These pages often contain exactly the same products as the parent collection, with the same title and the same meta description. In a store with 200 tags across 50 collections that can easily add up to more than 10,000 thin pages, all of them eating crawl budget without ever ranking.
The fix:
Add a noindex meta tag to every tag-filtered page. In theme.liquid, check whether current_tags is set:
{% if current_tags %}
<meta name="robots" content="noindex, follow">
{% endif %}
The follow value still lets Googlebot follow the links on the page. Only indexing is blocked. You can also block tag pages in your robots.txt.liquid with Disallow: /collections/*/, but keep in mind that robots.txt is a crawl hint, not indexing protection. If you want indexing to stay clean long term, combine both measures.
3. Pagination URLs
A collection with 200 products and 24 per page produces 9 pagination URLs, with Shopify appending ?page=2, ?page=3 and so on. The real problem is that ?page=1 is a straight duplicate of the base URL /collections/shoes, and Shopify does not canonicalise that variant automatically.
| URL | Status | Shopify default |
|---|---|---|
/collections/shoes | Canonical, indexable | Correct |
/collections/shoes?page=1 | Duplicate of the base URL | Not canonicalised |
/collections/shoes?page=2 | Genuine pagination page | Self-canonicalised |
/collections/shoes?sort_by=price | Duplicate with a different sort order | Not canonicalised |
For ?page=1, a manual canonical in your collection template does the job:
{% if current_page == 1 %}
<link rel="canonical" href="{{ collection.url | prepend: shop.url }}">
{% else %}
<link rel="canonical" href="{{ collection.url | prepend: shop.url }}?page={{ current_page }}">
{% endif %}
4. Variant parameters
Product variants generate URLs such as /products/t-shirt?variant=12345678. Here Shopify actually does the right thing: the canonical tag it sets on variant URLs always points at the base product URL, without the variant parameter. That covers you against duplicate content in this area.
Where you do need to pay attention is third-party apps for complex product configurators. Some of them create their own pages for variants and bypass Shopify's default canonicals. After every app installation, check whether new URLs without a canonical tag have appeared.
Diagnosing duplicate content: the tools
Before you start applying fixes, you need an inventory. These tools will surface the problems:
- Google Search Console: go to "Pages" and filter for "Duplicate, Google chose different canonical than user". If Google is ignoring your canonical, that is a strong sign your internal links are contradicting it.
- Screaming Frog SEO Spider: crawl your store and export every URL, then look for URLs that share the same canonical tag.
- Google Search: run
site:your-store.com inurl:/collections/. If product URLs with a collection path show up in the results, Google has not accepted your canonical. - View page source: open a product URL from inside a collection, press
Ctrl+Uand search forrel="canonical". The href should point at/products/, not at the collection URL.
The right order for your fixes
Plenty of merchants reach straight for robots.txt. That is a mistake. The correct order:
- Check and correct canonical tags (theme.liquid and product snippets)
- Clean up internal links (no
| within: collectionfilters in product links) - Apply noindex to weak pages (tag pages, internal search results)
- Adjust robots.txt (as a supporting measure only, never as a replacement)
Remember: robots.txt prevents crawling, not indexing. If Google already knows about links to a page, it can still end up in the index with the note "No information is available for this page."
Checklist: duplicate content audit for Shopify
- [ ] Check whether your theme snippets use
product.url | within: collection - [ ] Test the canonical tag on 5 product URLs from different collections
- [ ] Check Google Search Console for "Duplicate, Google chose different canonical than user"
- [ ] Confirm tag pages carry a noindex tag (the
current_tagscondition) - [ ] Verify that
?page=1is correctly canonicalised on collection pages - [ ] After app installations, test for new variant URLs without a canonical
- [ ] Make sure your sitemap.xml contains only canonical, indexable URLs
What Shopify handles for you (and what it does not)
| Problem | Shopify default | Manual work needed? |
|---|---|---|
| Product in collection vs. /products/ | Canonical set | Yes, if internal links point the wrong way |
| Variant URLs (?variant=) | Canonical to the base URL | Only with app configurators |
| Tag-filtered pages | No protection | Yes, noindex required |
| ?page=1 duplicate | Not canonicalised | Yes, manual canonical logic |
| ?sort_by= parameter | Not canonicalised | Yes, robots.txt or noindex |
| UTM parameters (?utm_source=) | Canonical ignores the parameter | No, Shopify handles it |
| Blog pages | Self-canonicalised | No |
Duplicate content and AI visibility in 2026
Since 2026, clean site architecture carries extra weight: AI-driven search surfaces such as Google AI Overviews and Perplexity favour pages that are structurally clear and trustworthy. Stores with unresolved duplicate content send contradictory crawl signals, and that does not just affect classic Google rankings. It also lowers your odds of being cited in AI-generated answers.
If you want to go deeper into the technical SEO fundamentals, my Shopify Technical SEO Playbook covers the full sitemap and crawl architecture. And if you want to understand how faceted navigation and filter URLs drain your crawl budget, read my guide to Shopify faceted navigation SEO.
Conclusion
Duplicate content on Shopify is not a sign of a broken platform. It is an architectural trait that needs active management. Shopify gives you the canonical foundation, but the fine tuning is yours: clean internal links, noindex on thin pages, and solid canonical logic in your Liquid code. Close these four sources systematically and you consolidate your link equity onto the pages that are actually meant to rank.
Frequently asked questions
Is duplicate content a serious SEO problem on Shopify?
Yes. Duplicate content spreads your link equity across several URLs and forces Google to decide for itself which page to rank. That often means a weaker or unwanted URL is the one that shows up in search results. Shopify does set canonical tags automatically, but those are hints, not binding directives.
Does the canonical tag fix every duplicate content problem on Shopify?
Not on its own. Canonical tags are recommendations, and Google ignores them when the signals contradict each other, for example when your internal links point at the duplicate URL. You also need clean internal linking, noindex on thin pages and, where relevant, robots.txt adjustments.
Do I have to set canonical tags myself on Shopify, or does the platform handle it?
Shopify sets canonical tags automatically for product URLs and variant parameters. For tag-filtered collection pages, the ?page=1 duplicate and ?sort_by parameters you have to step in manually, either with Liquid code in your theme or with noindex tags.