Skip to content
Instant · runs in your browser

Hreflang Generator

Link tags, HTTP headers or sitemap XML - with the code mistakes caught.

Hreflang generator output is only worth shipping if the whole set agrees with itself. Google never reads one annotation in isolation. It reads a cluster: your US page claims the French page is its alternate, and the French page has to make the same claim back, or the pairing is thrown away on both sides. This tool takes a flat list of locale | URL lines, builds the complete reciprocal set in whichever of the three formats Google accepts, and audits every code before you paste anything into production.

Pick the plain language if one page serves everyone who speaks it, or the language-and-country version if you keep separate pages per market.

Where someone lands when none of your languages match theirs - usually your main version or a language picker. Google recommends setting one.

Dominate AI Search Using a Proven System

BlazeHive runs the whole system for you - finds the keywords buyers actually search, writes the pages end to end, and publishes them so you show up in Google and in AI answers. Free trial, no card.

Start with BlazeHive Free trial

The cluster is the unit, not the line, in hreflang generation

3 conditions have to hold before any of this counts:

  • Every page in the set references every other page and itself. The self-reference is not optional and it is the single most common omission.
  • Every href is an absolute URL, protocol included. /fr/ is ignored. //example.com/fr/ is ignored.
  • The block is identical on every URL in the set. Same order, same codes, same URLs.

That last point is why the generator emits one block rather than a per-page variant. You paste the same output on all of them. If a page in the set is missing the block, that page drops out, and so does every pairing that pointed at it.

What goes in the locale list for generated hreflang tags

The locales field takes one pair per line. Left of the pipe is the hreflang value, right of it the absolute URL:

en-us | https://example.com/
en-gb | https://example.com/uk/
fr-fr | https://example.com/fr/
de    | https://example.com/de/

Language comes first: ISO 639-1, 2 letters, lowercase by convention. The region is optional and is ISO 3166-1 alpha-2, uppercase by convention. The region narrows the language, it never replaces it. de-CH means German as written for Switzerland. There is no valid hreflang value that is a country on its own.

A language-only code is often the better choice. es | https://example.com/es/ serves every Spanish speaker anywhere. Reach for es-MX and es-ES only when the pages genuinely differ by market, in currency, shipping or legal copy. Splitting one page into 2 country variants that say the same thing gains nothing and doubles the surface area for mistakes.

Blank lines and lines starting with # are skipped. Pipes are the documented separator, but a tab, a comma or plain whitespace also parse, so a paste straight out of a spreadsheet works.

Why en-uk quietly voids a line

The ISO 3166-1 alpha-2 code for the United Kingdom is GB. en-uk is not a near miss that Google rounds off. It is an invalid region, and the annotation is discarded. The audit panel catches that one plus the rest of the family:

  • Country code where a language belongs. jp is not Japanese, ja is. cn is not Chinese, zh is. Same for kr (use ko) and dk (use da).
  • Deprecated codes. iw was Hebrew decades ago. It is he now. Old CMS templates still ship the old value.
  • UN M.49 regions. es-419 is a real code for Latin America and Google does not read it. Split it into the countries you actually sell to.
  • EU as a region. The EU is not a country. Use per-country codes, or drop to a language-only code.
  • Underscores. en_US comes from application locale files. hreflang wants a hyphen.
  • Codes that are valid but mean something else. uk is Ukrainian, not the United Kingdom. se is Northern Sami, not Sweden, which is sv. Both pass a syntax check and both send your annotation somewhere you did not intend, so they surface as a soft warning rather than an error.

Warnings never block the output. You still get the tags, with a list of what to fix first.

Choosing an x-default worth having

The x-default field is the fallback for every visitor whose language and country you do not cover. A Portuguese speaker in Angola hitting a set of English, French and German pages has to land somewhere, and x-default is where you decide that.

2 sensible values: a language selector page, or your primary-market page. Point it at the URL a stranger should see. It is optional in the spec and recommended on every set, and the generator flags its absence because leaving it out means the choice gets made for you.

3 places hreflang output can live

The output format field switches the artifact, not the content.

<link> tags are the default and the right answer for ordinary HTML pages. They go in the <head> of every URL in the set.

A Link: response header is one comma-separated header carrying the same information. This is the only option for files with no <head>, which in practice means PDFs. Apache sends it with Header add Link "…", nginx with add_header Link "…";.

An XML sitemap with <xhtml:link> children annotates the entire set from one file, which is useful when your templating layer cannot vary the head per page. One trap: the urlset element has to declare the xhtml namespace or the file is invalid XML and gets rejected whole.

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://example.com/uk/</loc>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://example.com/" />
    <xhtml:link rel="alternate" hreflang="en-GB" href="https://example.com/uk/" />
    <xhtml:link rel="alternate" hreflang="fr-FR" href="https://example.com/fr/" />
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/" />
  </url>
</urlset>

Pick one method. Annotating the same page in the head and in a sitemap gives Google 2 sources that will eventually disagree, usually right after someone edits only one of them.

Checks that catch the failures worth catching

Fetch the raw HTML, not the DevTools DOM. curl -s https://example.com/uk/ | grep hreflang tells you what a crawler received. The DOM inspector shows you what JavaScript built afterward, which is a different question.

Then confirm the reciprocity by hand on one pair. Load the French page, find the tag pointing at the English page, load the English page, find the tag pointing back. If both exist, the templating is right and the rest of the set almost certainly follows.

2 more things worth verifying: the annotated URLs are the canonical URLs (a page canonicalized somewhere else exports its hreflang to nowhere), and each locale has its own URL. 2 locales sharing one URL collapses the cluster to a single page.

Dominate AI Search Using a Proven System

BlazeHive runs the whole system for you - finds the keywords buyers actually search, writes the pages end to end, and publishes them so you show up in Google and in AI answers. Free trial, no card.

Start with BlazeHive Free trial

Frequently Asked Questions

Do I need hreflang if all my pages are in English?

Yes, if you run separate pages for separate English-speaking markets. en-us, en-gb, en-au and en-ca variants of the same product page are exactly the case hreflang exists for, and without annotations they compete with each other in every one of those markets.

Does hreflang replace canonical tags?

No. They answer different questions. Canonical says which URL is the real one among duplicates. hreflang says which real URL suits which audience. Each page in the set should be self-canonical, and then annotate. Canonicalizing a locale page to another locale removes it from the set.

What happens if one page in the set has no tags?

That page is dropped, and every reference to it from the other pages is dropped with it. The rest of the cluster keeps working. This is why partial rollouts across a large site look like hreflang "not working" when the markup on the pages you checked is fine.

Can I use a language code with no region?

Yes, and it is usually the cleaner option. fr covers French speakers everywhere. Add the region only when the pages differ in ways a user in that country would notice.

Should the href point to the http or https version?

Whichever one is canonical and actually serves a 200. Mixed protocols inside a set are a common source of self-reference failures, because the page annotates http:// while the canonical is https://, so nothing matches.

How long until Google acts on a new set?

It has to recrawl every page in the cluster before the annotations mean anything, so the timeline is your crawl rate, not a fixed number. Small sets settle in days, large ones in weeks.

Getting the set right once is a fixed cost. Keeping the rest of your international SEO current is the recurring one, which is what BlazeHive automates end to end.

Related free tools

All tools →