Skip to content
Published

Canonical & Duplicate

The /products/ + /collections/products/ Duplicate, Decoded

Every Shopify product is reachable at two URLs by design: /products/handle and /collections/foo/products/handle. The platform auto-emits a canonical tag pointing the collection-prefixed URL back to the canonical /products/handle1. The default robots.txt also blocks /collections/*+* filter combinations2, and internal search result pages at /search send a noindex header5, which keeps the other thin-duplicate URL patterns out of the index. This cluster covers what to do when the auto-canonical fails.

The four leaves: auto-canonical behaviour, collection-prefixed URL suppression, the filtered /collections/*+* pattern, and the internal /search noindex.

The Shopify-specific duplicate pattern

Shopify routes every product at /products/handle and also at /collections/foo/products/handle whenever the product belongs to a collection. The platform auto-canonicals the collection-prefixed URL back to the canonical /products/handle, which means Google treats them as one resource — but only when the canonical tag is correctly emitted by the theme. Custom-coded theme templates, third-party page-builder apps, and stores using the within: collection Liquid filter without a canonical override are the cases where the auto-canonical fails.

html The two URLs every Shopify product has, and the canonical that resolves them
<!-- URL 1: the canonical product URL -->
https://yourstore.com/products/linen-roman-shade

<!-- URL 2: the collection-prefixed URL (when the product is in a collection) -->
https://yourstore.com/collections/window-treatments/products/linen-roman-shade

<!-- Themes auto-emit on URL 2: -->
<link rel="canonical" href="https://yourstore.com/products/linen-roman-shade" />

This page is the fix: the URL pattern, the failure modes, and the audit. For what duplicate content is as a concept — the generic definition, the 2009 origin of rel="canonical", and how classical and AI engines consolidate duplicates — see the duplicate content entry in the glossary.

What Shopify's auto-canonical actually does

Shopify's SEO overview states the platform auto-generates canonical tags 'to prevent duplicate content from appearing in search results.' The auto-canonical fires on products, collections, pages, and blog posts. It is self-referencing on the canonical URL (the page's canonical points to itself) and signal-bearing on duplicate URLs (the collection-prefixed product URL's canonical points to the /products/handle canonical URL). Per Google's canonicalization doc, this is the correct rel='canonical' pattern — Google reads it as a strong signal but reserves the right to choose a different canonical if other signals contradict.

The leaf at /shopify-seo/canonical-tags/ covers the auto-canonical behaviour, the GSC Pages report that surfaces "User-declared vs Google-selected canonical" mismatches4, and the rare cases where the auto-canonical fires incorrectly (custom themes that broke the canonical_url Liquid object, third-party page builders that re-render the head, or per-template overrides that conflict with the global canonical).

Filtered collection URLs and the /collections/*+* pattern

Every filter combination on a Shopify collection produces its own URL — /collections/dresses/red+xl — and the default robots.txt blocks the /collections/*+* wildcard so that open-ended surface never enters the crawl. Unblocking it is almost never the right move.

The leaf at /shopify-seo/filtered-collections/ owns this one: the few legitimate unblock cases, and the alternative architecture of promoting a high-value filter combination to a real collection with its own description and canonical URL.

Internal search result pages (/search?q=...) render a query string against a product list with no editorial content and no unique meta, so they shouldn't be indexed. Shopify handles that without any setup. Search result pages send an X-Robots-Tag: noindex, nofollow header. Whether robots.txt also blocks /search depends on the store: the managed file Shopify serves when a theme has no robots.txt.liquid leaves it crawlable, and a store with the template prints Shopify's older rules, which block it.

Shopify's help page still lists /search as a default block2, but on 16 September 2026 the managed file didn't contain one, and search result pages carried the noindex header on stores with and without a template5. The robots.txt checker shows which of the two files your store serves.

When the auto-canonical fails

Three failure modes account for most Shopify canonical issues: (1) custom-coded theme templates that lost the canonical_url Liquid object during a redesign; (2) third-party page-builder apps (PageFly, Shogun, GemPages) that re-render the page head and skip the auto-canonical; (3) stores using the within: collection Liquid filter to render collection-aware product templates without a canonical override. Each failure mode produces a different GSC signature.

The collection-canonical leaf at /shopify-seo/collections-products-canonical/ covers the within: collection case in detail — it is the most common Shopify-specific canonical failure on stores with custom theme work. The pattern is to add an explicit {% if template == 'product' %}<link rel="canonical" href="{{ canonical_url }}" />{% endif %} in theme.liquid when the global canonical is rendered conditionally.

The GSC Pages report under "Duplicate, Google chose different canonical than user" is the diagnostic surface. If that report shows a Shopify store's collection-prefixed product URLs with the wrong selected canonical, the theme has broken the auto-canonical — not a content issue, a code issue.