What this checker compares
The checker fetches your page through the site's server, follows any redirects, and reads the final URL that was reached, every <link rel="canonical"> tag in the HTML (the rel value is read as a token list, so rel="canonical nofollow" counts) and any canonical in an HTTP Link header. It then reports one of four main verdicts, plus warnings when there are duplicate or conflicting declarations. The canonical tag is defined in RFC 6596, and Google treats it as a strong hint, not a command.
| Verdict | Meaning |
|---|---|
| No canonical tag declared (red) | No rel="canonical" link with an href was found in the HTML |
| Canonical URL is relative (amber) | The value does not start with http:// or https:// |
| Self-referencing (green) | The canonical equals the final URL after normalization |
| Points to a different URL (amber) | Absolute, but not equal to the final URL |
| Conflicting canonical declarations (red) | Two or more canonicals, or an HTML tag and a Link header, pointing at different URLs |
| Multiple canonical tags (amber) | More than one tag, all pointing at the same URL |
| Canonical only in the HTTP Link header (amber) | No HTML tag, but the response header names a canonical |
When a page declares more than one canonical tag, every tag is listed, but the relative, self-referencing and different-URL checks use the last one in the document, the same tag the site's page-meta API reports. Browsers and search engines are not consistent here, and Google says conflicting canonicals may be ignored altogether, so treat any page with several tags as a bug to fix rather than relying on which one wins.
How "same URL" is decided
Before comparing, both URLs are normalized: the host is lowercased and one trailing slash is dropped from any path longer than /. The scheme, path case and query string are kept exactly as written, so differences there count as a mismatch. I ran these pairs through the same normalization:
| Canonical | Final URL | Result |
|---|---|---|
https://Example.com/blog/ | https://example.com/blog | Same |
http://example.com/blog | https://example.com/blog | Different (scheme) |
https://example.com/blog?utm=1 | https://example.com/blog | Different (query) |
https://example.com/Blog | https://example.com/blog | Different (path case) |
The second row is the classic migration bug: an HTTPS page whose canonical still says HTTP, which asks search engines to prefer the insecure version.
Limits and common mistakes
- The HTTP header is read too. A canonical sent as
Link: <https://example.com/page>; rel="canonical"(used for PDFs and other non-HTML files) is picked up and compared with the HTML tag. The HTTP headers checker shows the raw header. - The first megabyte of HTML. A canonical tag placed after about 1 MB of markup is missed. Canonicals belong in
<head>, near the top, anyway. - Two canonical tags are flagged, not silently resolved. Every tag found is listed. If they differ the verdict is a red conflict, since search engines may ignore conflicting tags entirely; if they match it is an amber warning. Duplicates (often added by both a theme and an SEO plugin) are worth removing.
- Tags added by JavaScript are not seen. Only the HTML the server returns is parsed, which can differ from what Google sees after rendering.
- The checked URL matters. If you enter a parameter URL and the canonical points to the clean version, that is the setup working as intended, even though the verdict is amber.
To see everything else a page declares in its head, such as the robots meta tag and Open Graph data, use the meta tag checker, and read the meta tag audit guide for the order to check things in.