Shopify Variant URLs Causing Duplicate Content: The Canonical Fix
When a shopper picks a size or color, Shopify appends ?variant=123456789 to the product URL, so a single product can spawn dozens of near-identical URLs. By default Shopify points every variant URL's canonical tag back at the clean product page, so Google merges them — but if a theme edit or an SEO app stripped, duplicated, or rewrote that tag, Google starts indexing the ?variant= versions as separate pages and flags them as duplicate content. Because Shopify keeps no history of the canonical tag or any head/SEO field, there's no native way to see what the tag used to say or roll it back once it breaks.
Step by step
Confirm the canonical is actually broken before you touch anything. Open a product page, select a variant so the URL shows ?variant=, then view source (Cmd/Ctrl+U) and find rel="canonical". The healthy state is exactly one tag pointing to the clean /products/handle URL with no query string. Three red flags: it's missing, it appears twice, or its href still contains ?variant=. Then in Search Console > Pages, open the affected status — "Duplicate, Google chose different canonical than user" or "Duplicate without user-selected canonical" is a real problem, but "Alternate page with proper canonical tag" is the normal, working state for variants, so don't fix what isn't broken.
Find what overwrote it. Shopify's native tag is <link rel="canonical" href="{{ canonical_url }}"> in theme.liquid, and canonical_url deliberately drops the variant parameter. In Online Store > Themes, check whether a recent theme update or edit touched theme.liquid; if you see two canonical tags, an SEO or marketing app is injecting its own on top of the theme's. List every app you installed or updated around the time the ?variant= URLs started showing up in Search Console — the timing usually points straight at the culprit.
Restore the clean canonical, and don't block the URLs. If theme.liquid was changed, put back the native {{ canonical_url }} tag, or roll back to the older theme version under Themes > Actions if it's still in your library; if an app added a duplicate, switch off its canonical setting or remove the app so only Shopify's tag remains. Do not disallow ?variant= in robots.txt — that stops Google from reading the canonical, so the duplicates get stuck instead of merged (and the old Search Console URL Parameters tool was retired in 2022, so it isn't an option either). Finish with URL Inspection > Test Live URL on a variant URL to confirm Google now reads the right canonical, then request indexing on the clean product page.
Catch the next break before Google does. Because Shopify versions theme files but keeps no history of the canonical or SEO fields themselves, take a daily snapshot of every product and collection's canonical, meta title, description, tags and handle. With that dated baseline, the next time a theme edit or an app silently strips or rewrites a canonical, you get an alert the day it happens — often naming the app that touched it — and you can restore yesterday's correct tag in one click, instead of finding out weeks later when the ?variant= pages are already indexed as duplicates.
Source: Google Search Console Help — Page Indexing report (duplicate and canonical statuses); Shopify Help Center — canonical URLs and search engine listings
SEO Vault keeps a daily snapshot of every SEO field on your store — meta titles, descriptions, alt-text, tags, handles (products AND collections) — and emails you the moment something changes in bulk, with the likely app responsible. One click restores yesterday's state, just the SEO fields. Free to monitor and get alerted; $14/mo for 1-click restore.