Multiple canonical tags: when a page names two different originals
A page should declare one canonical URL. When it carries two rel="canonical" declarations, Google has said it is likely to ignore them all, leaving the page with no canonical preference. Find the source of the extra one, usually a second plugin, a hard-coded theme line or an HTTP header, and remove it.
Two identical tags are untidy but consistent. Two different ones are the real problem, and they are more common than you would expect because the two sources rarely compute the URL the same way.
What it looks like
Before
<link rel="canonical" href="https://example.com/blue-mugs/">
<link rel="canonical" href="https://example.com/shop/?p=412">
After
<link rel="canonical" href="https://example.com/blue-mugs/">
Count the declarations in all three places
1. The HTML source.
curl -s https://example.com/blue-mugs/ | grep -io '<link[^>]*rel=.canonical.[^>]*>'
Each match is one tag. More than one line of output confirms the issue.
2. The HTTP headers. A canonical can also be sent as a response header, which view-source never shows:
curl -sI https://example.com/blue-mugs/ | grep -i "^link:"
A line containing rel="canonical" counts as a declaration. Servers and CDNs sometimes add it for PDFs and occasionally for every response.
3. The rendered page. Tag managers and client-side frameworks can inject a canonical after load. In Search Console, inspect the URL, click View crawled page and search the HTML for canonical. This is the DOM after Google's rendering, so injected tags appear here and not in curl output.
Note the position as well. A canonical tag inside <body> is disregarded. This happens when something prints markup before wp_head() finishes, or when an element that is invalid inside <head> causes the parser to close the head early.
Usual sources on WordPress
- Two SEO plugins active together. Each prints its own canonical, along with its own description and Open Graph tags. This is the most frequent cause and the fix is to run one; follow fixing duplicate meta output so settings are imported before the other plugin is deactivated.
- A theme that hard-codes the tag. Look in
header.phpfor a literal<link rel="canonical". Older and custom themes did this before WordPress handled it. - WordPress core plus a plugin. Core prints a canonical on single posts and pages through its
rel_canonicalfunction. SEO plugins unhook it and print their own. Hydrogen SEO does this, so with it active there should be exactly one. If a snippet re-adds the core function, you get two. - Custom code in
functions.phpthat echoes a canonical onwp_headfor specific templates. - AMP, translation or e-commerce add-ons that output a canonical for their own page types without checking for an existing one.
- Server configuration adding a
Linkheader.
Remove the extra, keep the correct one
- Identify which tag is right. It is the absolute URL of the page in your preferred protocol and host, without tracking parameters.
- Find which component prints each tag. Deactivate plugins one at a time and re-run the curl command; or search the theme and plugin folders for the string
rel="canonical". - Remove the duplicate at its source:
- Second SEO plugin: deactivate it after migrating its data.
- Theme: delete the hard-coded line, in a child theme if the theme receives updates.
- Custom snippet: delete it, or if you need to change the canonical for certain pages, filter the existing one instead of printing another. With Hydrogen SEO that is the
hydrogen_seo_canonical_urlfilter, listed in the filters reference. - Header: remove the directive from the server or CDN configuration unless it is serving non-HTML files.
- Purge the page cache and CDN.
Tag in the body
If the only canonical appears after </head> in the raw source, look at what precedes it. An <img>, <div>, <iframe> or other body element printed inside the head, commonly a tracking pixel pasted into a "header scripts" box, ends the head as far as an HTML parser is concerned. Everything after it, including later meta tags, is treated as body content. Move the offending snippet out of the head, to the start of the body or the footer.
Confirm a single declaration
Run the three checks again: one <link> in the source, no canonical Link header on HTML pages, one in the crawled HTML in URL Inspection. Then check a few different templates, because duplicates are often template-specific: a post, a page, a category archive, a product and the homepage. The free SEO audit reports whether a page has a canonical tag at all; it reads the first one it finds, so use the curl count to detect extras.
Common questions
What does Google do with two different canonical tags?
Google has said that with multiple declarations it will likely ignore all of them and determine the canonical from other signals.
Are two identical canonical tags a problem?
They do not conflict, so the practical risk is low, but they show that two components are both managing head tags. Fix the cause, since their other output probably differs.
Does a canonical in a Link header override the tag in HTML?
Neither officially overrides the other. They are both hints, and if they disagree you have conflicting declarations.
Can JavaScript add or change a canonical?
Google can pick up a canonical injected by JavaScript, but it recommends setting it in the initial HTML and not changing it with scripts, to avoid exactly this kind of conflict.