Hreflang Tag Checker avatar

Hreflang Tag Checker

Pricing

$0.90 / 1,000 hreflang audits

Go to Apify Store
Hreflang Tag Checker

Hreflang Tag Checker

Check public pages for hreflang declarations and SEO findings. Get language or region codes, target URLs, coverage details, HTTP status, and a compliance grade in a dataset.

Pricing

$0.90 / 1,000 hreflang audits

Rating

0.0

(0)

Developer

Maxime Dupré

Maxime Dupré

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

🌐 Hreflang Checker for International SEO Audits

SEO specialists, developers, and site owners can use Hreflang Checker to audit public pages. It returns requested and final URLs, HTTP status, page details, hreflang declarations, coverage, findings, and a compliance grade in a dataset, so you can review international SEO setup in one place.

📦 Page Audit Data

Each saved row covers one distinct publicly reachable page, including a page where no hreflang declarations are found. The row includes the requested and final URLs, response status, available page metadata, declarations from HTML or HTTP Link headers, coverage, findings, and a compliance grade.

🔎 Running Hreflang Page Audits

Add public page URLs, choose the checks for the run, and open the dataset after the run finishes. All submitted pages use the same options. By default, the Actor audits the URLs you submit; you can also follow same-site links and optionally check whether alternate targets link back.

⚙️ Input

Add one or more public HTTP or HTTPS page URLs. The same options apply to every page in the run.

FieldTypeWhat it does
pageUrlsarrayRequired. The public pages to audit. Add one or more items.
pageUrls[].urlstringRequired. The public page URL to audit.
verifyReciprocalLinksbooleanOptional, default false. When true, checks whether each alternate target links back to the source page.
expandSameSiteAuditbooleanOptional, default false. When true, follows same-site links to audit pages beyond the URLs you submit.
maxPagesintegerOptional positive limit for pages audited through same-site links. It is used only when expandSameSiteAudit is on. Leave it empty to return all available results until the source is exhausted.
crossDomainPolicystring (flag or accept)Optional, default flag. Choose whether an alternate URL on another domain is accepted or flagged in the findings.

The example below is the public input from a successful current beta run:

{
"pageUrls": [
{
"url": "https://www.bbc.com/"
}
],
"verifyReciprocalLinks": false,
"expandSameSiteAudit": false,
"maxPages": 50,
"crossDomainPolicy": "flag"
}

🧾 Output

The run output exposes datasetUrl, which links to the page audit rows. The dataset uses one row shape for normal audits, optional reciprocal checks, and cross-page comparisons. Optional fields are omitted when the related data is not available or the option was not used.

FieldTypeWhat it does
datasetUrlstringRun output link to the page audit dataset.
requestedUrlstringURL submitted for the page audit.
finalUrlstringFinal page URL after redirects.
httpStatusintegerHTTP response status for the final page.
pageTitlestring (optional)Page title when it is available.
domainstringDomain of the final page URL.
canonicalUrlstring (optional)Canonical URL declared by the page when it is available.
declarationsarrayHreflang declarations found on the page.
declarations[].hreflangstringLanguage or region code in the declaration.
declarations[].targetUrlstringAbsolute URL targeted by the declaration.
declarations[].codeValiditystring (valid, invalid, or unknown)Validity assessment for the language or region code.
declarations[].declarationSourcestring (html, httpHeader, or both)Where the declaration was found.
declarations[].reciprocalCheckobject (optional)Result of checking whether the target links back to the source page.
declarations[].reciprocalCheck.statusstringReciprocal check result: linksBack, doesNotLinkBack, or unreachable.
declarations[].reciprocalCheck.finalUrlstring (optional)Final URL reached when the target was checked.
declarations[].reciprocalCheck.httpStatusinteger (optional)HTTP response status from the target check.
coverageobjectSummary of the page's hreflang coverage.
coverage.declarationCountintegerNumber of hreflang declarations found.
coverage.hasXDefaultbooleanWhether the page has an x-default declaration.
coverage.hasSelfReferencebooleanWhether a declaration points back to the page.
findingsarrayWarnings and errors found during the page audit.
findings[].severitystring (warning or error)Severity of the finding.
findings[].codestringStable code for the finding.
findings[].messagestringPlain-language explanation of the finding.
findings[].hreflangstring (optional)Hreflang code linked to the finding, when applicable.
complianceGradestring (A, B, C, D, or F)Page-level grade based on the audit findings.
crossPageComparisonobject (optional)Differences found when the page is compared with peer pages in the run.
crossPageComparison.missingHreflangstring[]Codes found on peer pages but missing here.
crossPageComparison.missingTargetUrlsstring[]Alternate target URLs found on peer pages but missing here.

A no-declaration page audit row from the current beta:

{
"requestedUrl": "https://www.w3.org/International/questions/qa-html-language-declarations",
"finalUrl": "https://www.w3.org/International/questions/qa-html-language-declarations",
"httpStatus": 200,
"domain": "www.w3.org",
"pageTitle": "Declaring language in HTML",
"declarations": [],
"coverage": {
"declarationCount": 0,
"hasXDefault": false,
"hasSelfReference": false
},
"findings": [
{
"severity": "warning",
"code": "missing-declarations",
"message": "No hreflang declarations were found in the HTML or HTTP Link headers."
}
],
"complianceGrade": "B",
"crossPageComparison": {
"missingHreflang": [],
"missingTargetUrls": []
}
}

A header-based page audit row from the current beta:

{
"requestedUrl": "https://httpbin.org/response-headers?Link=%3Chttps%3A%2F%2Fexample.com%2Fen%3E%3B%20rel%3D%22alternate%22%3B%20hreflang%3D%22en%22",
"finalUrl": "https://httpbin.org/response-headers?Link=%3Chttps%3A%2F%2Fexample.com%2Fen%3E%3B%20rel%3D%22alternate%22%3B%20hreflang%3D%22en%22",
"httpStatus": 200,
"domain": "httpbin.org",
"declarations": [
{
"hreflang": "en",
"targetUrl": "https://example.com/en",
"codeValidity": "valid",
"declarationSource": "httpHeader"
}
],
"coverage": {
"declarationCount": 1,
"hasXDefault": false,
"hasSelfReference": false
},
"findings": [
{
"severity": "warning",
"code": "cross-domain-alternate",
"message": "The en alternate target is on another hostname.",
"hreflang": "en"
},
{
"severity": "warning",
"code": "missing-x-default",
"message": "No x-default declaration was found.",
"hreflang": "x-default"
},
{
"severity": "warning",
"code": "missing-self-reference",
"message": "No hreflang declaration points back to the fetched page."
}
],
"complianceGrade": "C",
"crossPageComparison": {
"missingHreflang": [],
"missingTargetUrls": []
}
}

A reciprocal-check row from the current beta:

{
"requestedUrl": "https://www.bbc.com/",
"finalUrl": "https://www.bbc.com/",
"httpStatus": 200,
"domain": "www.bbc.com",
"pageTitle": "BBC Home - Breaking News, World News, US News, Sports, Business, Innovation, Climate, Culture, Travel, Video & Audio",
"canonicalUrl": "https://www.bbc.com/",
"declarations": [
{
"hreflang": "en",
"targetUrl": "https://www.bbc.com/",
"codeValidity": "valid",
"declarationSource": "html",
"reciprocalCheck": {
"status": "linksBack",
"finalUrl": "https://www.bbc.com/",
"httpStatus": 200
}
},
{
"hreflang": "en-gb",
"targetUrl": "https://www.bbc.co.uk/",
"codeValidity": "valid",
"declarationSource": "html",
"reciprocalCheck": {
"status": "linksBack",
"finalUrl": "https://www.bbc.co.uk/",
"httpStatus": 200
}
}
],
"coverage": {
"declarationCount": 2,
"hasXDefault": false,
"hasSelfReference": true
},
"findings": [
{
"severity": "warning",
"code": "cross-domain-alternate",
"message": "The en-gb alternate target is on another hostname.",
"hreflang": "en-gb"
},
{
"severity": "warning",
"code": "missing-x-default",
"message": "No x-default declaration was found.",
"hreflang": "x-default"
}
],
"complianceGrade": "C",
"crossPageComparison": {
"missingHreflang": [],
"missingTargetUrls": []
}
}

A cross-page comparison row from the current beta:

{
"requestedUrl": "https://www.bbc.com/watch-live-news",
"finalUrl": "https://www.bbc.com/watch-live-news",
"httpStatus": 200,
"domain": "www.bbc.com",
"pageTitle": "BBC News Channel | Watch Live Breaking News",
"canonicalUrl": "https://www.bbc.com/watch-live-news",
"declarations": [
{
"hreflang": "en",
"targetUrl": "https://www.bbc.com/watch-live-news",
"codeValidity": "valid",
"declarationSource": "html"
}
],
"coverage": {
"declarationCount": 1,
"hasXDefault": false,
"hasSelfReference": true
},
"findings": [
{
"severity": "warning",
"code": "missing-x-default",
"message": "No x-default declaration was found.",
"hreflang": "x-default"
}
],
"complianceGrade": "B",
"crossPageComparison": {
"missingHreflang": [
"en-gb"
],
"missingTargetUrls": [
"https://www.bbc.co.uk/",
"https://www.bbc.com/"
]
}
}

💳 Pricing

The Actor uses pay-per-event pricing. The Hreflang audit event covers one publicly reachable page audit with its hreflang findings.

EventPriceWhat it covers
Hreflang audit$0.0009One publicly reachable page audit with hreflang findings saved.

🔌 Integrations

Use the dataset URL to export audit rows or read them through the Apify API. This walkthrough shows an Apify integration:

❓ FAQ

Can it audit a page with no hreflang declarations?

Yes. The Actor keeps an outcome for a publicly reachable page even when no hreflang declarations are found, and the findings explain that result.

Yes. Each declaration records whether it came from HTML, an HTTP Link header, or both.

Does it check x-default and self-reference?

Yes. The coverage object reports whether the page has an x-default declaration and whether it points back to itself. Findings can also flag missing coverage.

What does reciprocal checking do?

Set verifyReciprocalLinks to true to check whether each alternate target links back to the source page. The output can include the check status, final target URL, and target HTTP status.

Can it compare several pages in one run?

Yes. Add multiple pageUrls items. The output can compare peer pages and list hreflang codes or target URLs missing from the page.

What happens when same-site audit expansion is on?

When expandSameSiteAudit is true, the Actor follows same-site links beyond the submitted URLs. maxPages limits those pages; leave it empty to return all available results until the source is exhausted.

Does it crawl my whole website?

No. By default it audits the submitted pages. Same-site expansion can extend the run, but the Actor does not discover a complete URL inventory from XML sitemaps or crawl unrelated external sites.

No. It reports the absolute target URLs it finds. Reciprocal checking can inspect whether a target links back, but this Actor does not validate target-page content, broken links, or redirect chains as a separate audit.

Can it find tags that are missing from the fetched response?

No. It reports declarations present in the fetched public response. A declaration that is not present there may not be found.

Do I need source-site login credentials or an external API key?

No. The Actor audits publicly reachable pages without source-site login credentials or external API keys.

📝 Changelog

0.0: Initial release

🆘 Support

For issues, questions, or feature requests, file a ticket and I'll fix or implement it in less than 24h 🫡

Made with ❤️ by Maxime Dupré