The pattern: every Shopify product lives at two URLs
Shopify's URL routing makes every product reachable at two paths: the bare /products/handle (the primary URL) and the collection-prefixed /collections/COLLECTION-HANDLE/products/handle (the contextual URL). The same template renders at both paths — the same title, the same description, the same images, the same Add to Cart. To a search engine without canonical guidance, these are two URLs serving identical content. That's the duplicate-content surface Shopify's auto-canonical was designed for.
Why Shopify keeps the collection-prefix URL
Shopify could route every product link through /products/handle and avoid the duplicate entirely. They don't because the collection-prefix URL serves three real purposes. (1) Theme features like 'previous / next product' know which collection to traverse based on the URL prefix. (2) Faceted filtering preserves filter state across product clicks (the customer who filtered to 'red dresses' stays inside 'red dresses' after clicking a product). (3) Analytics attribution can map a product click back to its source collection. Removing the collection prefix would break all three. The auto-canonical is the duplicate-content tradeoff Shopify accepts for the navigation UX.
The default canonical fix
Shopify's themes ship with a canonical tag in theme.liquid's head that resolves to canonical_url — the Liquid object that always returns the bare /products/handle for a product, regardless of how the page was reached. When Google crawls /collections/foo/products/bar, it finds a canonical pointing to /products/bar, consolidates signals to the canonical, and treats the collection-prefixed URL as a duplicate. Per Google's canonical guidance, ranking signals (links, engagement, freshness) flow to the canonical.
The within: collection Liquid trap
The Liquid filter within: collection generates collection-prefixed product URLs in custom theme code. Developers use it for product loops that should preserve the collection context (e.g. a custom 'related products' block that pulls from the parent collection). The trap: every link emitted with within: collection is a /collections/foo/products/bar URL. The auto-canonical still works on the destination page, but the link itself is the variant URL, and many such links across the site create more crawlable variant URLs than necessary. The fix is to use within: collection only where the collection context is genuinely needed, and to add an explicit canonical override on any custom template that emits these links heavily.
Three-step remediation if your store is affected
If a Shopify store is generating crawlable /collections/foo/products/bar URLs that Google is indexing alongside the bare /products/bar, three remediation steps fix it. (1) Confirm the auto-canonical is intact — curl a collection-prefixed URL and verify the canonical tag points to the bare /products/handle. (2) Audit theme code for unnecessary within: collection filters on product links and remove them where collection context isn't required. (3) In Google Search Console, monitor the 'Duplicate, Google chose different canonical' report; affected URLs should shift to 'Duplicate, submitted URL not selected as canonical' over 4-6 weeks as Google re-crawls and re-consolidates.