What this hreflang checker tests
An hreflang checker reads a page's hreflang annotations and tests them against the rules in Google's documentation on localized versions. Enter one URL and this tool does two things. First, it validates the annotations on that page: the language and region codes, the URLs, duplicates, the self-reference and x-default. Second, it fetches each alternate URL and confirms that the alternate returns 200, isn't noindexed or canonicalized somewhere else, and links back with the same set of annotations.
The second part is where most hreflang problems hide. A tag can be perfectly valid on the page you're looking at and still be ignored because the German version doesn't point back.
What hreflang does
hreflang tells Google that several URLs are versions of the same page for different languages or regions, so it can show searchers the version that fits their language and location. It doesn't redirect anyone. The annotations have to be reciprocal: if page A lists page B but B doesn't list A, Google ignores the pair.
For background on why implementations break and how to audit a whole site, see Hreflang: why it breaks, how to audit it, and how to fix it.
The three ways to add hreflang
Google reads hreflang from three places. They're equivalent, and Google says using more than one has no benefit.
1. HTML link tags in the head
<link rel="alternate" hreflang="en-us" href="https://example.com/en-us/pricing">
<link rel="alternate" hreflang="de" href="https://example.com/de/pricing">
<link rel="alternate" hreflang="x-default" href="https://example.com/pricing">
2. HTTP Link header
Useful for PDFs and other non-HTML files.
Link: <https://example.com/en-us/guide.pdf>; rel="alternate"; hreflang="en-us",
<https://example.com/de/guide.pdf>; rel="alternate"; hreflang="de"
3. XML sitemap
Each <url> entry lists every version, including itself, with <xhtml:link> elements. This tool checks the first two methods only. Use the XML sitemap checker to validate the sitemap itself.
Hreflang validation checklist
These are the rules the checker applies, with examples. Values are not case-sensitive, so en-US and en-us are the same.
| Rule | Wrong | Right |
|---|---|---|
| Language is a two-letter ISO 639-1 code | eng | en |
| Region, if used, is an ISO 3166-1 alpha-2 code | en-uk | en-gb |
| Language comes first; a country alone isn't valid | us, jp | en-us, ja |
| Separator is a hyphen | en_US | en-US |
| No UN M.49 or supranational regions | es-419, en-eu | es-mx, es-ar, en |
| Script subtags are allowed | zh-traditional | zh-Hant, zh-Hant-TW |
| The fallback value is spelled exactly | default, x_default | x-default |
| URLs are fully qualified | /de/page, //example.com/de/page | https://example.com/de/page |
Link tags are inside <head> | Tags after a <div> or <img> that closes the head | Tags before any body content |
| Each value points to one URL | de listed twice with different URLs | One de entry |
| The page lists itself | The English page lists only de and fr | The English page lists en, de and fr |
| Every alternate links back | The de page has no hreflang | All pages carry the same full set |
Some checks are warnings rather than failures. A missing x-default is a warning because Google recommends it but doesn't require it; the x-default guide explains when to use it. A language-only value is fine, and so is listing en alongside en-gb and en-us. The same URL may appear under more than one value, for example as both en and x-default. The tool also warns on codes that are valid but often a mistake: uk is Ukrainian, not the United Kingdom, and ca is Catalan, not Canada.
How to read the return-link matrix
Each row is one alternate URL from the tested page (up to 15). The columns are:
- HTTP: the status code, with any redirects in front of it. A redirect is a warning; anything other than 200 at the end is a failure.
- Canonical OK: the alternate has no canonical or a canonical pointing to itself. Google's canonicalization docs say to specify a canonical page in the same language when you use hreflang. If the alternate canonicalizes to another URL, the annotation points at a page Google may not index.
- Indexable: no
noindexin a meta robots tag or the X-Robots-Tag header. - Links back: the alternate has an annotation whose URL matches the tested page. The comparison ignores case in the scheme and host and default ports, but not trailing slashes:
/de/pageand/de/page/are different URLs. When the only difference is a slash, or the return link is relative or outside the head, the row says so. - Same set: the alternate lists exactly the same hreflang values and URLs as the tested page. Missing and extra entries are listed under the row.
Only the tested page's alternates are fetched. To confirm the whole cluster, run the check again on one of the alternates, or crawl the site.
How to fix common hreflang problems
Relative URLs from a CMS or plugin
Some themes and plugins build the href from the path only, producing href="/fr/page". Google ignores these. Set the site's base URL in the plugin or template settings so it prints the full https:// URL, and confirm there isn't a second plugin emitting its own set. Two plugins usually show up here as exact duplicates or as conflicting URLs for the same value.
Alternates that redirect
Common causes are http to https, a missing or extra trailing slash, or a language folder that redirects based on the visitor's location. Update the annotations to the final URL shown in the matrix. If a URL redirects by location or browser language, Googlebot may never see the version you listed.
Canonical conflicts
Each language version should have a self-referencing canonical. A frequent mistake is pointing every language's canonical at the English page, which tells Google the translations are duplicates. Fix the canonical, then check it with the canonical tag checker.
Missing return links on one language
When one row in the matrix fails "Links back" while the others pass, that language's template usually isn't outputting hreflang, or it was launched later and was never added to the others' sets. Generate the full set from one shared list of versions and print it on every page, including the page's own entry.
Tags pushed out of the head
If the annotation table shows "HTML body", something before the tags ended the head: an <img> tracking pixel, a <div>, or stray text inserted by a script or tag manager. Move hreflang tags above those elements or move the elements into the body.
Checking hreflang across a whole site
This tool checks one page and its alternates. bseoa crawls every page on your machine, and its internationalization analyzer reports duplicate hreflang values on a page, hreflang URLs that don't parse as absolute URLs, missing x-default, and a missing or badly formatted lang attribute on the <html> element. See duplicate hreflang attributes and invalid URLs in hreflang for details on those warnings.