Shopify Duplicate Content: /collections/*/products/*, Variants and Canonicals, Explained
Every duplicate URL type on Shopify, tested: collection-path products, the within filter, ?variant= URLs, tag and vendor pages, pagination and filters, with the fix for each.

- Shopify canonicalizes /collections/x/products/y and ?variant= URLs to /products/y by default; the damage comes from themes and apps that link to the non-canonical version.
- Removing | within: collection from product cards is often the single biggest duplicate-content fix on older Shopify themes.
- Collection tag pages and vendor pages are self-canonical and indexable by default, and tag URLs can't be redirected, so decide: real collection or noindex.
- Paginated collection pages should keep their own canonical; Google says not to point page 2 at page 1.
- Canonical tags fix duplicate URLs, not duplicate copy. Reused Amazon or manufacturer descriptions need rewriting.
Shopify duplicate content has a reputation it only half deserves. Out of the box, Shopify handles most duplicate URLs with canonical tags, and it handles them correctly. The problems on big catalogs come from three places: themes and apps that link to the non-canonical version, URL types Shopify leaves indexable on purpose (tag, vendor and paginated pages), and real duplicate copy that no canonical tag can fix.
We tested each URL pattern below on Shopify's Dawn demo store and on live stores in September 2026, reading the canonical tag from the raw HTML. Your theme may behave differently, so each section ends with how to check yours.
Is there a Shopify duplicate content penalty?#
No. Google's stated position is that duplicate content on a site isn't grounds for action unless the intent is to deceive or manipulate rankings. What happens instead is quieter and still costly:
- Google picks one URL from each duplicate set, and sometimes it isn't the one you wanted.
- Links and other signals spread across copies instead of landing on one page.
- Crawling spent on duplicates isn't spent on new products and collections.
On a 200-product store you'd barely notice. On a catalog with 20,000 crawlable URLs, where Googlebot only visits a slice of the store each day, it decides how quickly new pages get indexed and refreshed.
The short version: every duplicate URL type on Shopify#
| URL pattern | Example | Default behavior we saw on Dawn | What to do |
|---|---|---|---|
| Collection-path product | /collections/bags/products/tote | Canonical points to /products/tote | Stop linking to it (remove within) |
| Variant parameter | /products/tote?variant=3957… | Canonical points to /products/tote | Nothing, unless an app breaks it |
| Collection tag page | /collections/bags/leather | Self-canonical, indexable | Build a real collection or noindex |
| Tag combination | /collections/bags/leather+tote | Self-canonical, blocked in robots.txt | Nothing |
| Vendor page | /collections/vendors?q=brand | Self-canonical, indexable | Build a brand collection or noindex |
| Pagination | /collections/bags?page=2 | Self-canonical, indexable | Leave it; make sure links are crawlable |
| Filter | /collections/bags?filter.v.availability=1 | Canonical to /collections/bags | See the faceted navigation guide |
| Sort | /collections/bags?sort_by=price-ascending | Canonical to /collections/bags, blocked in robots.txt | Don't link to it |
| Market subfolder | /en-au/products/tote | Self-canonical plus hreflang | Translate and localize it |
/collections//products/: the within filter#
Every Shopify product is reachable at two kinds of address: /products/handle and /collections/any-collection/products/handle. A product in 12 collections has 13 URLs. Shopify's canonical_url object points all of them at /products/handle, so Google is told which one to index.
The trouble starts when the theme links to the collection path. Older themes built product cards like this:
<a href="{{ product.url | within: collection }}">
{{ product.title }}
</a>The within filter "generates a product URL within the context of the provided collection", and Shopify's own documentation carries a caution about its SEO implications. On a 3,000-product store with products in several collections each, that single line can create tens of thousands of internal links to non-canonical URLs. Google crawls them, reads the canonical, and usually folds them together, but you've spent crawl budget and sent mixed signals on every collection page.
Current Shopify themes don't do this. Dawn's product card links to {{ card_product.url }}, and Horizon's links to {{ product.url }}. We confirmed Dawn's collection grid outputs plain /products/handle links.
How to fix it#
- In the theme editor, open Edit code and search for
within. - Replace each
{{ product.url | within: collection }}(orcard_product.url | within: collection) with the plainproduct.url. - Check breadcrumbs. Some themes build "Home > Collection > Product" breadcrumbs from the collection in the URL. Without it, the product page has no
collectionobject.
If your breadcrumb depends on it, fall back to the product's first collection:
{%- liquid
assign crumb_collection = collection
if crumb_collection == blank
assign crumb_collection = product.collections.first
endif
-%}
{%- if crumb_collection -%}
<a href="{{ crumb_collection.url }}">{{ crumb_collection.title }}</a>
{%- endif -%}Apps can bring the problem back after the theme is fixed. Mega menus, "recently viewed" widgets, quick-view pop-ups and some search apps build their own product links. After a crawl, filter internal links for /collections/ + /products/ and check the source page of each: if they all come from one widget, that's your culprit.
For big catalogs, a product metafield that names the primary collection is more reliable than collections.first, which may pick a sale or "new arrivals" collection.
Variant URLs: ?variant=#
Each variant can be opened with ?variant= and its ID. On Dawn, /products/puff-olive-leaf?variant=39577056936025 carries a canonical to /products/puff-olive-leaf. Google Shopping feeds often use these variant URLs as landing pages, which is fine: the shopper lands on the right color and the canonical keeps the index clean.
The real variant question is a keyword one. A variant can't rank for its own term because it doesn't have its own page. If "white oak dining table" and "walnut dining table" each have real search demand, a single product with a "Wood" option can only target one of them. Shopify now allows up to 2,048 variants per product (still three options), which makes it easy to pack everything into one product. On high-ticket catalogs we often split high-demand options into separate products (or combined listings on Shopify Plus) so each gets a page, a title and reviews.
Collection tag pages: /collections/x/tag#
Shopify's legacy tag filtering creates a URL for every tag in every collection: /collections/sofas/leather, /collections/sofas/grey, /collections/sofas/sale. On Dawn these are self-canonical and indexable, and the title tag gets a suffix like – tagged "leather". The page content is the same collection copy with fewer products.
Three things are worth knowing:
- Combinations are blocked.
/collections/sofas/leather+greyis caught by the defaultDisallow: /collections/*+*rule. - You can't redirect a tag URL. Shopify's help center says tag-filter paths count as valid even with zero products, so URL redirects on them won't fire.
- Thousands can exist. A store with 200 collections and 300 tags in use has more potential tag pages than products.
If a tag page has real demand ("leather sofas"), turn it into a proper collection with its own handle, copy and title. For the rest, add noindex, follow in theme.liquid inside <head>:
{%- if template.name == 'collection' and current_tags -%}
<meta name="robots" content="noindex, follow">
{%- endif -%}The same pattern with template.name == 'blog' covers blog tag pages (/blogs/news/tagged/tips).
Vendor and type pages#
Shopify creates /collections/vendors?q=Brand and /collections/types?q=Type automatically. On Dawn, the vendor page returned a self-canonical with the query lowercased. A type page returns a 404 if no product has that type.
These pages have no editable copy, no SEO fields and a generic title. For a multi-brand retailer, "Brand + product type" searches are valuable, and an auto-generated vendor page is a weak way to target them. Build a real brand collection (/collections/brand-name), then noindex the automatic page:
{%- liquid
assign auto_collection = false
if collection.current_vendor != blank or collection.current_type != blank
assign auto_collection = true
endif
-%}
{%- if template.name == 'collection' and auto_collection -%}
<meta name="robots" content="noindex, follow">
{%- endif -%}Liquid evaluates chained and/or operators from right to left with no parentheses, which is why the check is split into two steps. Test it on a vendor page, a type page and a normal collection before publishing. You can also check whether any template links to vendor pages in the first place: themes often wrap the vendor name on product pages in a link_to_vendor link.
Pagination: ?page=2#
On Dawn, /collections/bags?page=2 is self-canonical and its title gets – Page 2. That matches Google's guidance: give each page in a sequence its own canonical and don't canonicalize everything to page 1. Google no longer uses rel="next" and rel="prev".
If a collection runs to 25 pages, that's usually a sign it's covering several buyer keywords at once. Splitting it into sub-collections ("sectional sofas", "sleeper sofas") gives each group a page that can rank, and shortens the pagination on all of them.
Don't noindex page 2 and beyond. Products that only appear on deep pages need those pages crawled. Keep collections to a sensible page size and make sure page links are real <a href> links, including behind any "load more" button.
Filters, sort and search#
Filtered collections (?filter.p.m.custom.material=oak) canonicalize to the unfiltered collection on the stores we tested, and URLs with two or more filters are blocked by the default robots.txt. Sort URLs are blocked and canonicalized. Whether any filter page deserves indexing is its own topic, covered in faceted navigation on Shopify.
Internal search pages are worth a separate check. On Dawn, /search?q=bag is self-canonical with no noindex, and some stores' 2026 robots.txt no longer disallows /search. Shopify's help center gives this snippet for the <head>:
{% if template contains 'search' %}
<meta name="robots" content="noindex">
{% endif %}Markets subfolders are not duplicate content#
/en-au/products/tote and /products/tote look identical in English, but Shopify gives each a self-canonical and adds hreflang tags linking the set. That's the correct setup. The risk is the opposite: a German subfolder with English handles and meta descriptions. See our international SEO service for how we handle translated handles and market-specific pricing in schema.
The duplicate content canonicals can't fix#
Canonical tags handle URL duplicates. They do nothing for duplicate text across different pages, which is where big catalogs actually lose rankings:
- Manufacturer descriptions used by every reseller of the same grill or sauna.
- Amazon listing copy pasted into Shopify. We see this constantly with Chinese brands: the same bullet points on Amazon, Walmart, AliExpress and the brand's own store.
- Near-identical products (the same cabinet in 14 finishes as 14 products with one sentence changed).
- Collection descriptions reused across "sofas", "couches" and "sofa beds".
The fix is writing: unique product copy for the pages that matter, and distinct collection copy for each buyer keyword. Start with the pages Search Console already shows impressions for: they're the ones Google is willing to rank, and unique copy there moves results fastest. Canonicalizing similar products to one "main" product removes the others from search, which is only right when they truly have no demand of their own.
Audit your store in an afternoon#
- Crawl everything with JavaScript rendering off and export all internal URLs.
- Group by pattern using the table at the top. Count how many internal links point to each pattern.
- Spot-check canonicals with
curl:
for u in \
"https://yourstore.com/collections/sofas/products/milo-sofa" \
"https://yourstore.com/products/milo-sofa?variant=123" \
"https://yourstore.com/collections/sofas/leather" \
"https://yourstore.com/collections/vendors?q=milo"; do
echo "$u"
curl -sL "$u" | grep -oiE '<link[^>]*rel="canonical"[^>]*>|<meta[^>]*name="robots"[^>]*>'
done- Open Search Console's Page indexing report and read "Duplicate, Google chose different canonical than user" and "Alternate page with proper canonical tag". The second is normal; the first tells you where Google disagrees with you.
- Fix links first, tags second. Removing
withinand linking menus to real collections does more than addingnoindexto thousands of pages.
This is the work at the start of every large catalog engagement we run. If you want a full list of checks beyond duplicates, use the Shopify SEO checklist.
Questions people ask about this
Does Shopify create duplicate content automatically?
Yes, in the sense that the same product is reachable at /products/handle and at /collections/any-collection/products/handle, and variants add ?variant= URLs. Shopify handles these with canonical tags pointing to /products/handle. Tag, vendor and paginated pages are separate indexable URLs by default. The real risk is internal links to non-canonical URLs and duplicated text.
Will Google penalize my Shopify store for duplicate content?
Google says duplicate content isn't grounds for action unless it's meant to deceive or manipulate rankings. The cost is indirect: Google may pick a different URL than you want, signals spread across copies, and crawling spent on duplicates slows indexing of new products and collections. On large catalogs that cost is real.
Should I remove the within: collection filter from my Shopify theme?
In most cases, yes. It makes collection grids link to /collections/x/products/y instead of the canonical /products/y. Replace it with plain product.url, then check breadcrumbs: some themes use the collection in the URL to build them. Fall back to a primary-collection metafield or product.collections.first so breadcrumbs keep working.
Should Shopify collection tag pages be indexed?
Only when the tag represents a real buyer keyword and the page has unique copy, which tag pages can't easily have. Usually it's better to create a proper collection for that keyword and add noindex, follow to tag pages. Tag combinations with a plus sign are already blocked by Shopify's default robots.txt.
Do Shopify Markets subfolders count as duplicate content?
No. Shopify gives each market URL its own canonical and adds hreflang tags linking the versions, which tells Google they are regional alternatives. The problem to watch for is untranslated content in non-English subfolders, such as English handles, titles and meta descriptions in /de/, which weakens those pages in local search.
Want this done on your store?
Fixes for the crawl, index and schema problems Shopify creates on its own: duplicate product paths, tag pages, filter URLs, app bloat and Markets hreflang.
More from Technical SEO

The Shopify Apps Slowing Down Your Store and Quietly Hurting SEO (Plus a 20-Minute Audit)
Shopify apps slow down your store, leave code behind after you uninstall them, and sometimes change what Google sees. This 20-minute audit shows where to look and what to remove.

Crawled – Currently Not Indexed on Shopify: Why Google Skips Your Pages
Crawled – currently not indexed means Google fetched a page and chose to leave it out. On Shopify most of those URLs are harmless; here is how to find the few that cost you sales and fix them.

Shopify Speed Optimization: Fixing LCP on Collection Pages Without Killing Apps
Why Shopify collection pages fail LCP, how to find the real LCP element, and the fixes in order: image loading, animations, app scripts and Liquid render time.