hreflang checker

The language versions
this page says it has.

An hreflang set is a page listing every language and region version of itself, its own included. This reads the set in this page’s head and says whether it is written the way Google’s documentation requires — including the part that is easiest to get wrong, which is listing this page itself.

It reads one page, so it does not measure return links. Google ignores a set whose pages do not point back at each other, and establishing that means fetching every address the set names — up to 137 of them on a real page. This does not fetch them, and the report says so on its own row rather than leaving it to be assumed.

This tool works differently from the generator. The generator never uploads your image — it runs in your browser. The checker cannot: it fetches the public address you type, from our server, and reads that page’s HTML in full, not only its head — the body is fetched and read here, then turned into findings and dropped: it is never stored, and never sent back. The addresses the set names are read out of that page and shown to you; none of them is fetched. Only the address you enter is sent. The addresses you check are then kept in this browser, so it can tell you what changed since last time; they go nowhere, and you can clear them.

Questions

Why does the return-links row never pass?

Because it never measured anything, and saying so is the honest state. Google ignores a set whose pages do not point back at each other, and establishing that means fetching every address the set names and reading each one. Real pages were counted before this was decided: apple.com declares 137 alternates in its head, ikea.com 116, airbnb.com 96. One click turning into 137 outbound requests is not something this site does, so the row states the gap instead of guessing at it.

My page has hreflang and the report found none. Why?

Two possibilities, and the report distinguishes them. hreflang can also be declared in an HTTP Link header or in an XML sitemap, and this reads only the head — so the row says "not measured" rather than "none", because a page annotated entirely in its sitemap is annotated. The other possibility is a language switcher: hreflang is a valid attribute on a link you click as well as on a head declaration, and only the head declarations are a set. One measured page carries 71 of one and 70 of the other.

Why is hreflang="gb" wrong when hreflang="uk" is fine?

Because uk is a language and gb is not. The first code must be a language — uk is Ukrainian, zh is Chinese, br is Breton — and gb, cn and jp are country codes that name no language at all. Google’s documentation carries a warning about exactly this: "you can’t specify the country code by itself." The check reads against IANA’s language subtag registry, file dated 2026-09-17, rather than against the browser’s own locale data, which differs between machines.

Why read half a megabyte of a page to find tags in the head?

Because heads are not always short. The fetch is capped at 512 KB, and that cap was checked against real pages rather than assumed: one measured site closes its head at 271 KB, with its last language alternate at 271,078 bytes. If the cap does cut a page short, every row that would otherwise report something missing says "not measured" instead — an absence below the cut is not an absence.

Is a missing x-default a problem?

Not according to the source, so it is not scored. Google recommends x-default as a catch-all for visitors no other version matches and does not require it. Marking its absence as a failure would cost a page points against no rule, and marking its presence as a pass would read as though something had been verified. It is reported as a fact beside the set: declared, or not.