Bulk Hreflang Tags Validator & Checker
Data checkedHreflang
How to use the hreflang tag checker
Back to the toolOne page carries the whole set, so one URL is enough: every code it declares is validated against the language and region lists, and the set is judged as a whole.
- 01
Enter one page per language set
A page declares the alternates for itself and its siblings, so checking one member reports on all. Single mode checks one address and runs on Enter; switch to Bulk to paste a list, one URL per line, up to 30 per run. Sets are declared page by page, so a homepage that passes says nothing about your pricing page.
- 02
Choose the URL normalization level
Normalize URL rewrites each address before fetching. Full URL keeps the path and query but drops tracking parameters and the fragment; No query removes the query string; Domain only keeps the domain. Beware the last one here: a list of one page per set collapses to one domain, so thirty rows become one and the set returned is the homepage’s.
- 03
Read the Hreflang column
The column carries codes only, in declaration order, without addresses. That is deliberate: a real set runs long, and one row carrying every code with its target would be wider than the table. Scan it for x-default and the expected length, and open the row for anything more. — means the page declares no hreflang, correct for a one-language site.
- 04
Inspect a row and export the results
View lists every declaration with the language and region its code spells out, its target and its source, and marks a wrong code in red where it sits. Below sits a second verdict on the whole set, such as whether it points back at this page. Copy table copies the rows tab-separated; Export CSV writes them to a file.
How to read the hreflang validation report
A row that declares alternates carries two verdicts: one for each code on its own, and one for the set they form together.
Result table columns
- URL
- The address exactly as it was checked — after normalization, not always what you typed.
- Resolved URL
- Where the request ended and the status it ended on. Redirects are followed first, and the set is read from that final page.
- Hreflang
- Every code the final page declares, in declaration order, without their targets. — means none was declared.
- Result
- Whether the row finished, is still running, or stopped on an error. It says nothing about the set itself.
- Actions
- View opens the detail panel for that row; Retry appears instead when the request never got through.
Single-code verdicts
- old form of id-ID
- A code that still works but has been renamed: in-ID for id-ID, iw for he, tl for fil. The hardest kind to spot, because it looks valid and shape-only validators accept it.
- malformed code
- Not a language tag at all: an underscore instead of a hyphen (en_US), stray characters, or a subtag too long to be one.
- no such language
- The shape is right but the language part names nothing: a made-up code, or a country code used where a language belongs (uk is Ukrainian, not the United Kingdom).
- no such region
- The language is real but the region is not: es-SP for Spain, where the region is ES.
- no href
- The declaration names a language but no address, so there is nothing for it to point at.
Whole-set verdicts
- The hreflang set is well formed.
- Every code is real, every one has a target, the set points back at this page, and x-default is there when the set needs one.
- No hreflang — correct for a single-language site.
- The page declares no alternates. Not a fault: only a site that publishes the same page in more than one language needs them.
- An invalid code — Google ignores the pair it appears in.
- At least one code is broken, and the panel marks which. Google drops the pair it appears in and keeps the rest, so one bad code costs one language, not the set.
- A declaration has no href, so Google ignores it.
- At least one declaration has no address. Same cost as a broken code: that one pair is discarded.
- One code points to two URLs — Google cannot pick one.
- One code appears twice with two different targets. Google has no way to choose, so the set stops being usable; this one costs more than a single pair.
- No self-reference — Google will not group the set.
- The set never names the page it is on. Google groups a set only when each member points back at itself, so without it the declarations are ignored.
- No x-default — unmatched visitors have nowhere to land.
- No fallback for visitors none of the languages match. Only raised when the set has more than one language, since a single alternate has nothing to fall back from.