Two questions hiding in one check
Checking a canonical tag means answering two different questions with different tools: View Source and curl show what the server declares, the DevTools Elements panel shows what JavaScript leaves in the page, and only the indexed result in Search Console's URL Inspection shows which URL Google actually chose. Each method is trustworthy only for the question it can answer.
The first question is what the site declared. That declaration is either a <link rel="canonical"> element (the canonical link element, a link relation defined in RFC 6596) in the HTML <head>, or a Link HTTP response header carrying rel="canonical". Search Console calls it the user-declared canonical. The second question is which URL Google's indexing process decided should represent the group of duplicates, which Search Console calls the Google-selected canonical. Google's own summary is that "indicating a canonical preference is a hint, not a rule," so the two answers can differ without anything being broken.
That distinction sets the limits of every third-party tool, including the free canonical tag checker, bulk checker and validator on this site: they read what a server sends or what pasted HTML contains, which is the declared side, and cannot see the selected side at all.
Reading the server's HTML with View Source
View Source (Ctrl+U or Cmd+U, or the view-source: prefix in the address bar) shows the HTML exactly as the server delivered it, before any script runs. Search it for canonical and work through what you find:
- Count the matches. One is correct. Two or more is a problem regardless of whether they agree in value; Google's 2013 guidance was that with multiple declarations it will likely ignore all of them.
- Check what precedes it. Google stops reading the
<head>at the first element that does not belong there, such as aniframeorimg. The valid head elements aretitle,meta,link,script,style,base,noscriptandtemplate. View Source will still show the canonical inside the head, so this needs a deliberate look. - Read the
href. It should be absolute, with the scheme. A value such asexample.com/pagehas no protocol and resolves as a relative path, so it points somewhere nobody intended. - Look for extra attributes. A canonical carrying
hreflang,lang,mediaortypeis not used for canonicalization. - Look for a fragment. Google generally does not support URL fragments, so
#sectionin a canonical target is wasted.
The first tag below passes; each of the other three fails one of the checks above.
<link rel="canonical" href="https://www.example.com/shoes/">
<link rel="canonical" href="example.com/shoes/">
<link rel="canonical" hreflang="en" href="https://www.example.com/shoes/">
<link rel="canonical" href="https://www.example.com/shoes/#reviews">Checking the HTTP header with curl
A canonical sent as an HTTP header never appears in View Source, and for PDFs and other non-HTML files the header is the only way to declare one. curl reads it directly:
# headers only, using a HEAD request
curl -sI https://www.example.com/page
# headers from a real GET, body discarded
curl -s -D - -o /dev/null https://www.example.com/page
# follow redirects and report each hop's headers
curl -sIL https://www.example.com/page
The line to look for has the form Link: <https://www.example.com/page>; rel="canonical". Three details keep the result honest. First, some servers answer HEAD differently from GET, so if -I shows nothing, repeat with the GET form before concluding there is no header. Second, -L matters because a redirect is itself a strong canonical signal, and a page that redirects has expressed its preference before any tag is read. Third, a header canonical and an HTML canonical on the same page must name the same URL. Google advises against declaring different canonicals through different techniques, and the mismatch is easy to miss when each is checked with a different tool.
curl's -A flag sets a user agent, and it is tempting to send Googlebot's string to see what Google sees. It does not work that way. Google publishes reverse-DNS checks and IP ranges precisely because user agents can be spoofed, and sites that verify Googlebot may block a spoofed request or serve it something different.
Comparing the source with the rendered DOM
The Elements panel in Chrome DevTools shows the live DOM, the page as it exists after scripts have added, removed or edited nodes. View Source shows the starting point; Elements shows the end state. On a JavaScript application the difference between them is the diagnosis.
| View Source | Elements panel | What it means |
|---|---|---|
| Canonical A | Canonical A | Consistent; the normal case |
| No canonical | Canonical A | Injected by JavaScript. Google can pick it up during rendering, but any raw-HTML checker will report it missing |
| Canonical A | Canonical B | Rewritten by JavaScript, the pattern Google's guidance warns against |
| Canonical A | Canonical A and B | A script added a second tag instead of replacing the first, producing multiple declarations |
Google's JavaScript guidance draws the line clearly: "You shouldn't use JavaScript to change the canonical URL to something else than the URL you specified as the canonical URL in the original HTML," and a script-injected canonical has to be the only one on the page. The safest arrangement is a correct canonical in the server HTML that no script touches. Browser extensions that display the canonical are convenient for spot checks, but they generally read the live DOM, so treat them as a version of the Elements view, not of the source.
URL Inspection: the only view of Google's choice
Search Console's URL Inspection reports both answers side by side for any URL in a property you have verified. The user-declared canonical field shows the declaration Google found; the Google-selected canonical field shows what it chose, which Search Console Help notes may or may not be the declared URL. When they differ, page indexing statuses such as "Duplicate, Google chose different canonical than user" and "Alternate page with proper canonical tag" describe the situation, and each has its own page on this site.
The indexed result is the one that counts. Google states that the canonical can be determined only from indexed data and that the live test cannot predict whether the tested URL will be considered canonical; canonical-related states are not detected by the live test either. The live test still answers a narrower question, whether Google can fetch the page and see the tag; it uses Google-InspectionTool, a crawler that obeys robots.txt.
Two further cautions apply. The HTML shown under "View crawled page" may not be the rendered version; John Mueller has said it can contain static or rendered HTML depending on processing time, so it cannot settle a JavaScript question on its own. And after a fix, Google's troubleshooting guidance allows up to about two weeks for re-evaluation, so an unchanged Google-selected canonical the next morning is not evidence the fix failed. Tutorials that point to the Mobile-Friendly Test for rendered HTML are out of date; it was retired on December 1, 2023. Whether Bing Webmaster Tools exposes a selected canonical is undocumented in the sources reviewed here.
Checking canonicals across a whole site
A single-URL check asks whether one page is right; a crawl asks where the template is wrong, usually the more useful question. Crawlers such as Screaming Frog and Sitebulb, named here as examples, turn the checks above into filters.
- Screaming Frog's Canonicals tab reports both link-element and HTTP canonicals, with filters including Missing, Self Referencing, Multiple, Multiple Conflicting, Non-Indexable Canonical, Canonical Is Relative, Unlinked, Contains Fragment URL, Invalid Attribute In Annotation and Outside <head>.
- Rendering mode decides which view the crawl sees. Screaming Frog can crawl as Text Only or with JavaScript rendering in headless Chrome, and storing both the original and the rendered HTML allows a source-versus-DOM comparison across every URL. Its "Canonical Only In Rendered HTML" issue flags the injected-canonical row from the table above.
- Sitebulb's indexability hints cover the same ground from another angle, including a mismatched canonical between HTML and HTTP header, a canonical loop, a canonical pointing to a redirecting URL, a canonical found only in the rendered DOM, and a rendered canonical that differs from the HTML source.
A bulk check shows consistency, not correctness. A thousand pages that all canonicalize to the same wrong URL look perfectly uniform, which is why bulk canonical data belongs next to redirect and indexability data from a crawl rather than on its own.
Checking where the canonical points
A well-formed tag can still name the wrong page, and no syntax check catches that. RFC 6596 requires the target to be a duplicate or a superset of the page declaring it, and it lists targets to avoid: the source of a permanent redirect, a URL that returns an error code, and a URL that itself canonicalizes somewhere else. In practice, request the target with curl and confirm:
- it returns 200 without redirecting;
- it carries no
noindexand is not disallowed in robots.txt, since Google cannot read the tags on a page it is blocked from crawling; - its own canonical is itself, so the chain ends there;
- it is the URL your sitemap lists, your internal links use, and your hreflang annotations reference.
The last point matters because the tag is one signal among several. Google names redirects and rel="canonical" as strong signals and sitemap inclusion as a weak one, and a tag that contradicts every internal link on the site is asking Google to overrule the rest of the evidence. Paginated series are the exception to pointing at a main version: each page carries its own canonical, not page 1's.
Common misreadings, and when a mismatch can stay
Most wrong conclusions about canonicals come from asking a tool a question it cannot answer.
- A clean live test is not Google's verdict. Only the indexed URL Inspection result shows the selected canonical.
- A
site:search is not a canonical check. Google documents URL Inspection for this purpose, not search operators. - "No canonical in the source" is not "no canonical." The header may carry it.
Not every disagreement needs fixing. If Google selected, say, the https or www form of a URL that the site actually links to, the choice may be sensible, and Google's troubleshooting guidance frames the test as whether the selection makes sense. What to avoid is steering the result with noindex: Google does not recommend it for preventing canonical selection within a single site, and Mueller has described a page that carries both as sending very contradictory information. Fix the declaration and the supporting signals, then wait for the indexed result to catch up.
Frequently asked questions
How do I find the canonical URL of a page?
Open View Source and search for canonical to find the declared URL in the HTML, and run curl -sI on the page to catch a canonical sent as an HTTP header. That tells you what the site declares. To see the URL Google treats as canonical, inspect the page in Search Console's URL Inspection and read the Google-selected canonical in the indexed result.
Why does URL Inspection show a different canonical than my tag?
Google treats the tag as a hint and weighs it against other signals such as redirects, internal links and sitemap entries. When those point elsewhere, or the tag is unreadable because it sits after an invalid head element, Google may select a different URL. If the selected URL is one you would accept anyway, it may not need fixing.
Can the URL Inspection live test show the Google-selected canonical?
No. Google states that the canonical version can be determined only from indexed data and that the live test cannot predict it. Use the live test to confirm Google can fetch the page and see your tag, and the indexed result to see Google's choice.
How do I check a canonical set in the HTTP header?
Request the URL's headers with curl, for example curl -sI https://www.example.com/file.pdf, and look for a Link line ending in rel="canonical". If the HEAD request returns nothing, repeat with curl -s -D - -o /dev/null to see the headers of a real GET, since some servers treat the two differently.
Why does a canonical checker report no canonical when DevTools shows one?
The canonical is probably added by JavaScript. Server-side checkers and View Source read the HTML before scripts run, while the DevTools Elements panel shows the DOM after they finish. Google can process a script-injected canonical during rendering, but a canonical in the server HTML is the more reliable arrangement.
Does a site: search show which URL Google treats as canonical?
No. Google does not document search operators as a way to see its canonical choice. URL Inspection in Search Console is the documented method, and its indexed result is the one to rely on.
How long does Google take to reflect a canonical fix?
Google's troubleshooting guidance allows up to about two weeks for a changed canonical to be re-evaluated. Check the indexed URL Inspection result after that window rather than the next day, and confirm the fix is visible in the server HTML or header first.