Fixing Canonical Tags After a Site Migration
After a migration, the canonical tag on each new page should name that new page. Very often it does not. It still names the old domain, the staging server, the HTTP version, or a path from the old URL structure, because the value was stored in a database, hard-coded in a template or set in a plugin nobody reopened.
Search engines then receive a redirect saying one thing and a canonical saying the opposite. This guide shows where stale canonicals come from, how to find every one, and how to make every signal agree on the new address.
Why migrations break canonical tags
A canonical tag is a line in the page head, <link rel="canonical" href="...">,
that tells search engines which address is the main version of a page. During a normal day nobody thinks
about it because the CMS generates it. A migration disturbs the things it is generated from:
- Stored absolute addresses. Many systems save the full URL, domain included, in the database. Moving the database to a new domain carries the old domain with it.
- Manual overrides. SEO plugins and CMS fields let editors set a custom canonical per page. Those custom values are copied across verbatim and are easy to forget.
- Environment settings. A site built on
staging.example.co.ukmay take its base URL from a configuration file or environment variable. If production was launched with the staging value, every canonical names staging. - Hard-coded templates. A developer testing a theme sometimes types a domain into the header template. It works on the day and breaks on the move.
- Old URL patterns. A template that builds the canonical from a slug and a fixed prefix
may still use the old prefix, for example
/shop/when the section is now/products/.
The result is a conflict. The old URL redirects to the new one, which says "the new address is the real one", while the new page's canonical points back at the old address, which says "no, the old one is". Google treats canonical tags as a strong hint rather than a command, and it weighs redirects, canonicals, sitemap entries and internal links together. When they disagree, it may keep showing the old address in results, pick an address you did not intend, or take longer to settle on the new one.
The stale patterns to look for
| What the canonical says | Typical cause | Where to fix it |
|---|---|---|
https://www.old-example.co.uk/... | Domain stored in the database or in plugin settings | Site address setting, then a database search and replace |
https://staging.example.co.uk/... or a preview host | Base URL taken from the wrong environment | Production configuration or environment variables |
http://example.co.uk/... | Site address still set to HTTP after an HTTPS move | CMS site address, framework base URL |
https://example.co.uk/shop/blue-kettle when the page is at /products/blue-kettle | Template builds the path with the old prefix | Theme or route template |
| The home page, on every page | Header template outputs a fixed address | Theme header |
| No canonical at all | New theme or plugin does not output one | SEO plugin or template |
| Two different canonicals in one page | Old theme code and a new SEO plugin both output one | Remove one source |
Two canonical tags with different values is worse than it looks. When a page gives conflicting canonical tags, Google may ignore both, which leaves it to choose on its own.
How to diagnose it
Crawl first
Crawl the live site with a tool that records the canonical of each page and whether it matches the page address. Export the results and add a column that extracts the host from the canonical. Filter for any host that is not your live domain. Then filter the rest for canonicals that do not equal the page's own URL, and for pages with no canonical or more than one.
Use the migration context
The Site Migration Audit lists lost URLs, redirect coverage and indexing for the move. Cross-check canonical findings against it: a canonical that points to an old URL which the audit shows redirecting is the classic conflict, and a canonical that points to an address the audit lists as lost is sending Google to a 404.
Check what Google chose
In Search Console, run the URL Inspection tool on a sample of important new pages. It shows the User-declared canonical, which is what your tag says, and the Google-selected canonical, which is what Google decided. In the Page indexing report, the groups "Duplicate, Google chose different canonical than user" and "Alternate page with proper canonical tag" often grow after a move with stale tags.
curl -s https://example.co.uk/products/blue-kettle | grep -i 'rel="canonical"'
curl -sI https://example.co.uk/files/kettle-manual.pdf | grep -i '^link:'
The first command shows the tag the server sends before any JavaScript runs. The second shows a canonical sent as an HTTP header, which is used for PDFs and other files.
Where the value lives on common platforms
WordPress
The WordPress Address and Site Address under Settings, General set the base of every generated canonical.
If they are correct but canonicals are still wrong, the old domain is stored in post content, options
or SEO plugin data. Yoast SEO and Rank Math both have a per-post canonical field under their advanced
settings, and values typed there are copied verbatim in a migration. A search and replace with WP-CLI,
run first with --dry-run, updates stored addresses and handles serialised data safely.
Shopify
Themes output the canonical with the canonical_url Liquid object, which Shopify builds
from the primary domain. If canonicals show an old myshopify.com address or a secondary
domain, check which domain is set as primary in the domains settings, and look for a theme or app that
replaced the Liquid object with a typed address.
Frameworks and static sites
Next.js, Nuxt, Astro, Hugo, Eleventy and similar tools build canonicals from a site URL setting such
as metadataBase, site or baseURL, often read from an environment
variable. Check the production build environment, not your local one. Preview deployments should either
have their own correct value or be blocked from indexing.
The fix, step by step
Step 1
Crawl the new site and export every canonical
Crawl the live site with a crawler that records the canonical tag, the canonical HTTP header and the number of canonicals per page. Export the result to a spreadsheet and add a column that extracts the host name from each canonical value. Keep the Site Migration Audit results beside it so you can see which canonicals point at addresses that are lost or redirecting.
Step 2
Sort the stale values into groups
Filter the export into groups: canonicals naming the old domain, a staging or preview host, the HTTP version, an old path prefix, the home page on every page, pages with no canonical, and pages with two different canonicals. Count each group. Large groups nearly always share one cause in configuration or a template, while small groups are usually manual overrides typed into individual pages.
Step 3
Trace each group back to where it is set
For each group, open one affected page and work out which code or setting produced the tag. Check the site address setting, environment variables, the theme header template, the SEO plugin output and any per-page canonical override field. Search the codebase and the database for the stale host name. Note the source against each group in the spreadsheet so the fix can be applied once rather than page by page.
Step 4
Correct the source, not the individual pages
Fix the site address or base URL setting, rebuild and redeploy if it is a static site, and remove typed domains from templates so the canonical is generated from the current request or settings. For stored values, run a database search and replace from the old host to the new one, with a dry run and a backup first. Clear per-page overrides that simply repeat the page address.
Step 5
Check canonicals sent outside the HTML
Request PDFs, images and other files with a header check and look for a Link
header with rel="canonical". These are set in server configuration, a CDN rule or an application,
and a migration copies them just like templates. Also check that the CDN or cache is not still serving
pages generated before the fix, and purge it so crawlers receive the corrected head.
Step 6
Line up redirects, sitemap and internal links
Make sure every signal names the same address. The old URL should redirect in one
step to the new URL, the new URL should carry a self-referencing canonical, the XML sitemap should list
only the new URL, and internal links should point straight at it. Pay attention to small differences
such as a trailing slash or www, which make the canonical and the redirect destination disagree.
Step 7
Confirm the Google-selected canonical
Re-crawl to confirm the stale groups are empty, then use URL Inspection on a sample of important pages and check that the user-declared and Google-selected canonicals match the new address. Watch the Duplicate, Google chose different canonical than user group in the Page indexing report. Google has to recrawl each page before it changes its choice, so expect the group to shrink gradually.
Cross-domain canonicals and when they are right
Not every canonical to another host is a mistake. Some are deliberate, and deleting them would cause a different problem.
- Syndicated content. An article republished on a partner site may carry a canonical back to your original. That is correct and unrelated to your move, except that the partner's tag may now point at your old domain. It still works through your redirect, but asking the partner to update it removes one hop.
- A phased migration. If you move one section at a time, a new-domain page may briefly exist alongside the old one. Here the redirect is still the better tool; a cross-domain canonical is a fallback for cases where the old page must stay reachable for users.
- Print or AMP versions. Alternate versions correctly point their canonical at the main page. Make sure that main page address is the new one.
Google's site move guidance is to use redirects for a move. A canonical tag on the old page pointing to the new one is not a substitute, because the old page stays live and users can still reach it.
Keeping canonicals right in future moves
- Generate, do not store. Build canonicals at render time from the current site address setting, so changing that one setting changes every tag.
- Test staging for the production domain. Before launch, crawl staging with the production base URL configured and check that no canonical contains the staging host.
- One source of truth. Allow only one plugin, theme component or framework feature to output the canonical.
- Include canonicals in launch checks. Add a canonical check to the post-launch list alongside robots.txt, noindex and the sitemap, and re-run it after every major release.
1. Is it a problem if my new pages have canonicals pointing to the old domain?
Yes. The old URL redirects to the new one while the new page says the old one is the main version, so the two strongest signals you control contradict each other. Google treats the canonical as a hint and weighs all the signals, so it may still pick the new address, but it may also keep the old one in results for longer or choose unpredictably. Fix the canonicals so every signal agrees.
2. Can I use a canonical tag instead of a redirect for my migration?
It is not recommended. Google's guidance for site moves is to use server-side redirects from each old URL to its new equivalent. A canonical tag on an old page leaves that page live, so visitors and other search engines can still land on it, and Google treats the tag as a hint rather than an instruction. Use canonicals only for alternate versions that must stay reachable, not as the moving mechanism.
3. What is the difference between the user-declared and Google-selected canonical?
The user-declared canonical is the address your page names in its canonical tag or header. The Google-selected canonical is the address Google decided to treat as the main version after weighing that tag with redirects, sitemaps, internal links and content similarity. The URL Inspection tool in Search Console shows both. After a clean migration they should match the new page address. When they differ, look for the signal that disagrees.
4. How long does it take Google to pick up corrected canonical tags?
Google has to recrawl each page before it sees the corrected tag, and then reprocess the page, so there is no single timescale. Important, frequently crawled pages tend to update sooner than deep pages. You can request indexing in URL Inspection for a small number of key pages, and submitting a sitemap of the new URLs helps crawlers find the rest. Track the Page indexing report groups rather than expecting an overnight change.
5. Why does my page have two canonical tags after the migration?
Usually because two pieces of software both output one: the old theme hard-coded a tag in its header, and the new SEO plugin adds its own, or a framework component and a plugin each generate one. When a page has conflicting canonicals, Google may ignore them all. View the page source, search for rel=canonical, identify which component printed each one, and switch off or remove the duplicate so only one remains.
6. Should the canonical include www and a trailing slash?
It should match exactly the address the page is served on after all redirects, including protocol, www or non-www, and the trailing slash if your site uses one. If the canonical says one form and the server redirects to another, you have created a small conflict on every page. Pick one form, make the server redirect every variant to it, and generate canonicals, sitemaps and internal links from the same setting.
7. Do canonical tags on staging sites matter?
They matter if the staging site is public. A staging copy that is crawlable and carries canonicals naming itself can compete with the live site, and staging values copied into production cause the problems described here. Protect staging with a login, which is the most reliable way to keep it out of search engines, and check that production takes its base URL from production settings rather than from a copied staging configuration.
The Site Migration Audit compares your pre-migration crawl with the live site, finds lost URLs, validates redirects, tracks ranking shifts, checks indexing and structured data, and audits internal links.
Open Migration Audit Fixes โ