Canonical Tag Checker
What it does
Check the canonical tag on every page of a site in one run, not one URL at a time. Give it a homepage or an XML sitemap. For each page it reads the <link rel="canonical"> tag from the server-delivered HTML, resolves it, fetches the target, and tells you what's wrong and how to fix it. The same run also checks titles, descriptions, headings, robots directives and internal links.
What it flags
| Check | Severity | When |
|---|---|---|
canonical.missing | warning | No canonical tag, or an empty one |
canonical.relative | warning | Written as a relative URL instead of an absolute one |
canonical.elsewhere | warning | Resolves to a different URL than the page itself |
canonical.malformed | error | Can't be parsed as a URL |
canonical.non_200 | error | The target doesn't return HTTP 200, or can't be fetched |
A canonical that points elsewhere is sometimes intended, for example on a filtered or paginated URL. The check shows you where it happens so you can confirm it.
Input and output from a real run
We set up five demo pages on this site, each with one canonical fault (or none), and ran the Actor on them on Apify on 2026-09-30 (run atMJfdP6XdeAkvgJz). It found each fault: the correct page came back clean, the other four got the finding shown in the table above.
Input JSON
{
"startUrls": [
{ "url": "https://lintlab.dev/demo/canonical/ok/" },
{ "url": "https://lintlab.dev/demo/canonical/relative/" },
{ "url": "https://lintlab.dev/demo/canonical/elsewhere/" },
{ "url": "https://lintlab.dev/demo/canonical/gone/" },
{ "url": "https://lintlab.dev/demo/canonical/missing/" }
],
"discoverSitemap": false,
"maxPages": 5,
"checkLinks": false
}
For a whole site, give only the homepage and leave discoverSitemap on: the Actor finds the sitemap through robots.txt or /sitemap.xml.
Output excerpt: the page whose canonical target is gone
{
"url": "https://lintlab.dev/demo/canonical/gone/",
"status": 200,
"canonical": "https://lintlab.dev/demo/canonical/old-page/",
"findings": [
{
"checkId": "canonical.elsewhere",
"severity": "warning",
"message": "The canonical points to another URL.",
"fix": "Verify that consolidation to the canonical target is intentional.",
"value": "https://lintlab.dev/demo/canonical/old-page/"
},
{
"checkId": "canonical.non_200",
"severity": "error",
"message": "The canonical target returned HTTP 404.",
"fix": "Make the canonical target return HTTP 200.",
"value": 404
}
]
}
Run summary excerpt
{
"pagesAudited": 5,
"counts": { "error": 1, "warning": 4, "notice": 0 },
"topIssues": [
{ "checkId": "canonical.elsewhere", "count": 2 },
{ "checkId": "canonical.missing", "count": 1 },
{ "checkId": "canonical.non_200", "count": 1 },
{ "checkId": "canonical.relative", "count": 1 }
]
}
Price and limits
$0.004 per successfully audited page ($4 per 1,000 pages). Canonical target fetches and internal link checks aren't charged. Pages that fail or return an error status are reported but not charged.
- Up to 5,000 pages per run.
- Reads the HTML the server sends. It doesn't run JavaScript, so a canonical tag added only by client-side script won't be seen.
- Doesn't read canonicals sent in the HTTP
Linkheader. - For sites you own or are allowed to audit.
When a free tool is better
For a few URLs on a site you've verified, use the URL Inspection tool in Google Search Console. It's free and shows both the canonical you declared and the one Google chose. This Actor is for checking every page of a site at once, any public site, without verification, with JSON you can diff between runs or check in CI. URL Inspection tool documentation · Google's guide to canonical URLs.