Home › Tools › hreflang Tag Generator

hreflang Tag Generator

Generate hreflang as HTML link tags, an HTTP Link header or sitemap entries — validating bad language codes, missing return tags and x-default.

List one line per language version and pick an output format. The generator writes the full cluster for every URL, because that is what the specification actually requires, and it flags the mistakes that make Google silently ignore the whole set.

How to use it

  1. Enter one line per language version: the code, a pipe, then the full URL of that version.
  2. Optionally give an x-default URL for visitors whose language is not in the list.
  3. Pick the format you actually ship — head tags, HTTP header, or sitemap — and copy the block.

The return tag is the part almost everyone misses

hreflang is a two-way statement. If your US page points at the German page, the German page has to point back, or Google treats the annotation as unconfirmed and ignores it. This is why a partial rollout — tags added to the English pages but not the translated ones — produces no change in search results whatsoever, and no error message either.

Each page also has to annotate itself. A page that lists only its siblings, and not its own language, is an incomplete cluster. The generator writes the full set including the self-reference precisely so this cannot happen by omission.

x-default is not your main language

It is the fallback for a visitor whose language matches nothing in your list — someone browsing in Portuguese when you publish English, German and Japanese. Pointing it at your English page is common and works, but the more useful target is a page that lets the visitor choose.

It is optional, and Google will not penalise you for leaving it out. It earns its place when you have significant traffic from languages you do not publish in, which is most sites.

Three places to put it — and why you should pick one

HTML <link> tags in the head, the Link HTTP response header, or xhtml:link entries in your XML sitemap. The header exists for non-HTML files — a PDF has no head — and the sitemap exists for sites with too many alternates to fit comfortably in a template.

Mixing them is where it breaks. If one URL carries a different set of alternates in two places, the crawler has to guess which is authoritative, and a guess is worse than a single correct source. Pick one method per URL and keep it consistent across the whole cluster.

Sitemap annotations carry an extra rule: every URL in that sitemap must have its complete cluster, including itself. A sitemap where half the entries are annotated and half are not is worse than none.

Codes that look right and are not

en-UK is the classic one. The ISO 3166-1 code for the United Kingdom is GB, not UK, and while Google is forgiving in practice, other tooling and several CMS plugins are not. en-GB is the value to ship.

Region subtags go uppercase and language subtags lowercase: de-DE, not DE-de or de-de. Google reads the values case-insensitively, so a slip here will not break the annotation, but it will break any downstream tooling that compares strings exactly.

Only annotate canonical, indexable URLs. A hreflang link pointed at a redirected, noindexed or non-canonical URL is dropped, and — depending on how your cluster is built — can take the whole set down with it.

What 28 real hreflang clusters look like

On 2026-09-24 we requested the homepage of 78 well-known domains. 60 came back readable, and 28 of those declare hreflang, emitting 864 annotations between them — a median of 15.5 per site. The range is the first thing worth knowing: Coursera, Docker and the BBC declare two each, while Uber declares 173, Stripe 89 and Mozilla 80. Our hreflang survey covers who uses it and how much they ship; what follows is the part that survey did not measure — whether those sets hold together.

The headline is that format is not where things break. Of the 864 values, 861 are recognised as valid by ICU's own language and region tables, and the three exceptions all belong to Mozilla and are genuine ISO 639-3 codes (cak, skr, trs) that ICU simply does not carry. No site declared the same code twice with different URLs. No site mixed en-US with en-us in one set. Nobody shipped http and https in the same cluster. Every real failure we found is about relationships, not spelling.

The self-reference test, run against real canonicals

Every page in a cluster must list itself. It is the easiest rule to lose, because the page still renders and nothing logs an error. To test it we took each site's own canonical as the definition of this page — falling back to the URL the homepage finally resolves to — and asked whether that exact URL appears anywhere in its own hreflang set.

Of the 28: 20 (71.4%) declare themselves under a real language code. Five more (17.9%) match only through x-default. Three (10.7%) do not appear at all, and one of those three is LinkedIn, where our request was geo-dispatched to a localised page — a measurement artifact, not a defect. That leaves atlassian.com and kubernetes.io as the genuine failures, two of 27 testable sites.

Atlassian's homepage canonicalises to https://www.atlassian.com. Its cluster declares eleven languages — ja, fr, de, es, pt-BR, zh-Hans, ko, ru, pl, it, nl — every one of them pointing at a subdirectory, and none of them pointing back at the English page itself. Kubernetes.io does the same with sixteen: bn, zh-cn, fr, de, hi, id, it, ja, ko, fa, pl, pt-br, ru, es, uk, vi, and no en. Both are large, well-engineered sites, and both pass a syntax validator with no warnings at all.

Measuring this against the URL we requested rather than the URL the page resolves to would have produced two false accusations: nodejs.org lands on /en and squareup.com on /us/en, and both declare exactly those pages. A homepage that redirects is not the page you fetched, and the self-reference has to be checked against the destination.

x-default is not your self-reference

Five sites — Trello, rust-lang.org, Twitch, Mozilla and Cloudflare — do contain their own URL, but only as x-default. That is not the same declaration. x-default is the fallback for a visitor whose language matches nothing you publish; it is not a language, and validators looking for a self-reference are looking for the page's own code.

Trello is the clearest example. Its homepage canonicalises to https://www.trello.com/home, and its x-default points at precisely that URL — but the other eleven entries are ja, fr, de, es, pt-BR, zh-Hans, ko, ru, pl, it and nl. English is never declared. Cloudflare has the same shape: nine languages plus x-default, no English entry, on a page whose html lang is en. Four of the 27 sites whose language we could read never declare the language they are actually written in.

One page can carry many codes — on purpose

A cluster does not need one URL per code. The median site in our sample maps 1.01 codes onto each URL, but two sites fold hard: GitHub declares 26 codes across 7 URLs, with nineteen Spanish regional variants — es-AR, es-BO, es-CL and sixteen more — all pointing at https://github.com?locale=es-419; Figma declares 34 codes across 14 URLs, twenty of them landing on /es-la.

This is the correct way to say one Spanish page serves all of Latin America, and it is far better than shipping nineteen near-duplicate pages. Two sites in the sample carry the locale in a query string instead of a path or subdomain — GitHub with ?locale= and Twitch with ?lang=. We checked GitHub's: https://github.com/?locale=pt-br declares itself canonical, so the annotation points at a URL that will not be consolidated away. If your query-string locale pages canonicalise back to the bare URL instead, every alternate collapses onto one page and the cluster quietly means nothing.

Three architectures, and what each one costs

Six of the 28 clusters span more than one host. Four do it with locale subdomains under a single registrable domain — LinkedIn across 62 distinct hosts, Pinterest across 37, Semrush across 14, CNN across 2 — which is a normal, scalable pattern. Two span genuinely different domains: the BBC declares bbc.com and bbc.co.uk in one set, and Wise declares wise.com alongside wiseturkiye.com.tr. Cross-ccTLD clusters are almost always a legal or commercial fact rather than an SEO decision, and the cost is that the return tags have to be maintained by two teams who may not talk to each other.

None of the three — subdomain, subdirectory, ccTLD — is easier for a crawler than the others, so pick on operational grounds: which one your CMS can emit consistently, and which one your team can keep in sync. What matters is that the choice is made once, that every URL in the cluster lists the complete set, and that the URL form you annotate is the URL form that canonicalises. That is not always available: in our canonical survey, 11 of 55 readable homepages declare no canonical at all — including two of the sites in this sample — which leaves an annotation with nothing authoritative to agree with.

How to check your own cluster in five minutes

1. Find yourself. Copy your canonical URL exactly — scheme, host, trailing slash — and search your own head for it. If it is not there, the cluster is unconfirmed and nothing else you do matters.

2. Check your own language is declared. Compare your html lang against the codes in the set. Four of the 27 sites we could read fail this, including two of the largest software companies in the sample.

3. Confirm x-default is present, and not doing double duty. It should exist, and there should also be a real language entry for this page.

4. Fetch two targets and diff them. The German page's hreflang block should be byte-for-byte identical to the English page's. If one side lists twelve alternates and the other lists eleven, the pair is unconfirmed.

5. Then believe Search Console. Its international targeting report is the only place that tells you what Google actually accepted. Everything above is a way of guessing correctly before you get there.

When not to use hreflang

Do not add it to a monolingual site. In our sample, 32 of the 60 readable homepages declare none, and most of them are right to: hreflang tells a crawler which equivalent to serve, and a site with no equivalents has nothing to say. It is not a ranking signal and adding it defensively does nothing.

Do not use it to point at content you have not really translated. Language-only boilerplate around English body copy is not an equivalent page, and annotating it invites a crawler to serve a worse page to someone who would have been better off with the English one.

Do not declare codes you are guessing at. Folding nineteen Spanish variants onto one URL, as GitHub does, is deliberate and correct. Declaring en-GB because you suppose you have some British traffic, and pointing it at your US page, is a guess dressed as a fact.

What this tool deliberately does not do

It does not fetch your URLs. Verifying that each target returns 200, and that each page really does carry the reciprocal tags, means requesting pages on your domain from somewhere other than your browser — which browsers block, and which a privacy-respecting tool should not route through a third party anyway.

It also cannot read the hreflang report in Google Search Console, which is the only place that tells you what Google actually accepted.

Use this to get the cluster correct and complete. Then confirm it with Search Console's international targeting report, or by fetching two of the URLs and checking that each contains the other.

How we measured this

One fetch on 2026-09-24: https://<domain>/ for 78 hand-picked domains, direct first and through a local proxy where our network could not reach the host. 60 returned usable homepages and 28 of those declare hreflang, giving 864 annotations. The extraction is a single pass over <link> tags, keeping those whose rel contains alternate and whose hreflang is non-empty.

The self-reference test compares each declared URL against the page's own canonical where one is declared (25 sites) and against the resolved landing URL otherwise (3). Comparison is structural — host with any leading www. removed, trailing slashes removed, query string compared — never a string match, because https://github.com and https://github.com/ are the same page and a string comparison would call them different.

Three limits worth stating. We read only the initial HTML, so annotations delivered by HTTP Link headers, sitemap xhtml:link entries, or client-side JavaScript are invisible here — a site whose hreflang lives only in its sitemap reads as not using it. We did not fetch every declared target, so we can report self-reference but not reciprocity; confirming both directions needs a per-target crawl that a browser-only tool cannot do. And LinkedIn is counted separately throughout, because our request was geo-dispatched to a localised page whose own cluster lives elsewhere.

The script ships with the site and needs no network: node scripts/survey-hreflang-structure.mjs re-derives every number from stored HTML, and --evidence prints the original tag for each site we made a judgement about. Language and region validation uses ICU's own tables rather than a hand-written allowlist, which is why three real ISO 639-3 codes show up as unrecognised instead of being silently passed.

Questions

Should hreflang point to the canonical URL?

Yes. Only annotate self-canonical, indexable URLs. A target that redirects or carries noindex is ignored, which can invalidate the cluster.

Do I need hreflang for a single-language site?

No. It only matters when you serve substantially the same content in more than one language. Adding it to a monolingual site does nothing.

Can I put hreflang in the sitemap and in the HTML at the same time?

You can, but do not. Two sources that disagree leave the crawler guessing. Choose one method per URL set.

Is x-default required?

Not required, but recommended when you have visitors in languages you do not publish. Point it at a language chooser rather than at one language version.

Does x-default count as the self-reference?

No. It is a fallback for unmatched languages, not a language of its own. Five of the 28 sites we measured rely on it and still never declare their actual language, which leaves the page unconfirmed.

Can one URL serve several language codes?

Yes, and it is often the right call. GitHub points nineteen Spanish regional codes at a single URL; Figma points twenty at /es-la. Declaring one code per page is not a requirement.

What is the most common real hreflang mistake?

A missing self-reference. In our sample 7 of 27 sites fail it: two do not list themselves at all, and five list themselves only as x-default. No site had a malformed language code.

Should I use subdomains, subdirectories or ccTLDs?

Whichever your team can keep consistent. Six of the 28 clusters we measured span multiple hosts and four of those use locale subdomains, but there is no crawling advantage to any of the three — the failure mode is drift, not the pattern.

Is my data sent anywhere?

No. Parsing and generation happen in your browser. Nothing you type leaves the page.

Related tools