Cross-Domain Canonicals and When They Hold
Nothing in the canonical tag’s definition restricts it to one host. <link rel="canonical" href="https://other.example/article/"> is as valid as a same-site canonical, and it asks for exactly the same thing: consolidate this URL’s signals onto that one, and prefer that one in results.
Because it crosses a domain boundary, it is also the version of the tag most often ignored — not arbitrarily, but for reasons you can check in advance.
When a cross-domain canonical is the right tool
The tag is for cases where two URLs on different hosts are the same document and you cannot or should not redirect one to the other.
Syndication. You publish an article and a partner republishes it verbatim. The partner’s copy carries a canonical to yours. This is the honest form of multi-site publishing: the duplicate exists openly, one URL is declared authoritative, and readers of the copy usually get a visible line saying where it first appeared.
One catalogue, two storefronts. The same product page served on a regional and a global host with identical content.
A retired brand or acquired domain that still has to serve. You want the old domain’s pages to keep resolving — because a partner integration reads them, or because the brand is still referenced — but you want the new domain to be the one in results. A redirect would break the first requirement; a canonical satisfies both.
A host you do not control the redirects on. A documentation mirror, a platform-hosted copy, a marketplace listing page. If you can inject a tag but cannot configure a 301, the tag is what you have.
When you can redirect and nothing needs the old URL to keep returning content, redirect. A 301 is an instruction; a canonical is a request. The comparison, including the third option, is in canonical, redirect, or noindex.
What has to be true for it to be honoured
A canonical is a hint, and the search engine’s confidence in that hint is what decides whether it is followed. Every item below is a reason for confidence — or, when it fails, a reason to discard the declaration and pick a canonical URL itself.
The two pages must actually be near-duplicates. This is the biggest single factor. A canonical between two substantively different pages is a claim the crawler can check and disprove. If the “duplicate” has a different body, different headings, different structured data, or is a category page pointing at a product, the declaration reads as an error and gets dropped.
The target must return 200. A canonical pointing at a URL that redirects makes the crawler resolve the chain and then decide for itself; a canonical pointing at a 404 is discarded outright.
The target must be indexable. No noindex, not Disallowed, no conflicting canonical of its own pointing somewhere third. Every one of those makes the declared canonical ineligible to be a canonical.
The target must self-canonicalise. The authoritative page should carry a canonical to itself. This closes the loop and removes ambiguity — the pattern mirrors the return-tag requirement in hreflang and the return-tag requirement, where a one-sided declaration is treated as unconfirmed.
The URL in the tag must be absolute. A relative href resolves against the current host, which on a cross-domain canonical means it silently becomes a self-reference. Always write the scheme and host.
The source page must be crawlable. The tag lives in the response. If the copy is blocked from crawling, the declaration is never read and the URL sits in the index undescribed instead.
One tag per page. Two conflicting rel="canonical" elements, or a <link> tag in the <head> disagreeing with a Link: HTTP header, is a contradiction. The documented handling of contradictory canonicals is that they are all ignored.
The six ways it quietly fails
The partner strips the tag. Many publishing platforms rewrite <head> on import, and some replace the canonical with a self-reference as a matter of policy. You get no notification. The only detection is to fetch the republished URL yourself and look.
Someone republishes without the tag at all. Same outcome, no agreement in place. Here the cross-domain canonical is not available to you and the question becomes which copy the engine picks on its own — usually the one it has more confidence in, which correlates with how well established the host is rather than who published first.
Mutual canonicals. Page A canonicalises to B and B canonicalises to A. There is no authoritative URL in the pair, so the declarations cancel and the engine chooses. This happens when two teams each add a tag pointing at “the other one” believing theirs is the copy.
A chain. A canonicalises to B, B canonicalises to C. Chains are resolved in practice up to a point, but each hop is another opportunity to lose the signal, and a hop that also crosses a redirect makes the intent unrecoverable. Flatten them for the same reason you flatten redirects, described in redirect chains and how to flatten them.
Sitewide canonicalisation to a homepage. Every page on the retired domain canonicalising to https://new.example/ rather than to its own equivalent. The pages are not duplicates of the homepage, so the declaration is discarded wholesale — and the same mistake made with redirects produces soft 404s instead, as covered in soft 404s: when a 200 response is treated as missing.
The tag is injected client-side. A canonical added by JavaScript after load can be picked up, but it depends on the page being rendered, and a canonical that disagrees with the one in the served HTML is a conflict rather than a correction. Serve it in the initial response.
A worked example
You are retiring oldbrand.example in favour of newbrand.example. Twelve pages on the old domain must keep returning content because a partner’s integration fetches them; the other four hundred can move.
The configuration:
- The four hundred get 301s to their specific equivalents on the new domain. Nothing needs them to return content, so the stronger instrument applies.
- The twelve keep returning 200, each with an absolute canonical to its specific counterpart on the new domain, and each counterpart carries a self-canonical.
- Both hosts stay crawlable. No
Disallowon the old domain, or the twelve declarations are never read and the four hundred redirects are never followed. - Internal links on the old domain are updated to point at the new domain, so the crawl path reinforces the declaration rather than contradicting it.
- Sitemaps list only canonical URLs — the new domain’s sitemap lists the new URLs, and the old domain’s sitemap is either removed or lists only the twelve.
The last two points matter more than they look. A canonical is one signal among several, and the others — internal links, sitemap membership, redirects — are read as statements about the same question. Consistency across them is what turns a hint into a decision, which is the argument made at length in canonical tags are a hint, not a command.
Verifying it
Check both ends, and check the served HTML rather than the rendered DOM:
# the copy: is the tag present, absolute, and pointing where you think?
curl -s https://oldbrand.example/guide/ \
| grep -io '<link[^>]*rel="canonical"[^>]*>'
# the target: 200, self-canonical, and no noindex?
curl -sI https://newbrand.example/guide/ | grep -iE '^(HTTP|x-robots-tag|link)'
Then check the engine’s own conclusion. Search Console’s URL inspection reports the user-declared canonical and the selected canonical separately, and the gap between those two lines is the only direct evidence of whether your declaration was accepted. A selected canonical that differs from the one you declared is not a bug to argue with — it is a report that one of the conditions above was not met, and the list is short enough to walk.