TapCub is live — analytics, insights and live chat, free on one platform

Free tool Hreflang generator and code checker

hreflang tells Google which language or regional version of a page to show to whom. The syntax is simple and easy to get subtly wrong: en-UK instead of en-GB, an underscore, a relative URL, or a page that forgets to list itself. Write one line per version and get all three formats, with each mistake explained.

  • ISO 639-1 and 3166-1 checked
  • Tags, sitemap and header
  • Runs locally
Generator

List your language versions

One version per line: a language code, optionally with script or region, then the full URL. Try the button to see how common mistakes are reported.

Format: code URL, e.g. en-GB https://example.com/uk/. Spaces, tabs or commas between them all work, so you can paste two spreadsheet columns.

Optional. The page for everyone whose language matches none of the above, often a language selector or your main version.

Versions

CodeMeaningURLStatus
enEnglishhttps://www.example.com/Valid
en-GBBritish Englishhttps://www.example.com/uk/Valid
en-USAmerican Englishhttps://www.example.com/us/Valid
de-DEGerman (Germany)https://www.example.com/de/Valid
zh-HansSimplified Chinesehttps://www.example.com/zh-hans/Valid
x-defaultEveryone elsehttps://www.example.com/Valid

Checklist

  • OK5 language versions, all codes and URLs valid.
  • NotePut this same set of 6 lines on every URL listed. Each page must list itself and all the others; if page A lists B but B does not list A, Google ignores the pair.
HTML <link> tags
<link rel="alternate" hreflang="en" href="https://www.example.com/" />
<link rel="alternate" hreflang="en-GB" href="https://www.example.com/uk/" />
<link rel="alternate" hreflang="en-US" href="https://www.example.com/us/" />
<link rel="alternate" hreflang="de-DE" href="https://www.example.com/de/" />
<link rel="alternate" hreflang="zh-Hans" href="https://www.example.com/zh-hans/" />
<link rel="alternate" hreflang="x-default" href="https://www.example.com/" />

Inside <head> of every page listed, identical on each.

HTTP Link header
Link: <https://www.example.com/>; rel="alternate"; hreflang="en", <https://www.example.com/uk/>; rel="alternate"; hreflang="en-GB", <https://www.example.com/us/>; rel="alternate"; hreflang="en-US", <https://www.example.com/de/>; rel="alternate"; hreflang="de-DE", <https://www.example.com/zh-hans/>; rel="alternate"; hreflang="zh-Hans", <https://www.example.com/>; rel="alternate"; hreflang="x-default"

# Nginx (server / location)
add_header Link '<https://www.example.com/>; rel="alternate"; hreflang="en", <https://www.example.com/uk/>; rel="alternate"; hreflang="en-GB", <https://www.example.com/us/>; rel="alternate"; hreflang="en-US", <https://www.example.com/de/>; rel="alternate"; hreflang="de-DE", <https://www.example.com/zh-hans/>; rel="alternate"; hreflang="zh-Hans", <https://www.example.com/>; rel="alternate"; hreflang="x-default"';

# Apache (.htaccess, mod_headers)
Header set Link "<https://www.example.com/>; rel=\"alternate\"; hreflang=\"en\", <https://www.example.com/uk/>; rel=\"alternate\"; hreflang=\"en-GB\", <https://www.example.com/us/>; rel=\"alternate\"; hreflang=\"en-US\", <https://www.example.com/de/>; rel=\"alternate\"; hreflang=\"de-DE\", <https://www.example.com/zh-hans/>; rel=\"alternate\"; hreflang=\"zh-Hans\", <https://www.example.com/>; rel=\"alternate\"; hreflang=\"x-default\""

For PDFs and other non-HTML files. Nginx and Apache versions included.

XML sitemap
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://www.example.com/</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://www.example.com/"/>
    <xhtml:link rel="alternate" hreflang="en-GB" href="https://www.example.com/uk/"/>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://www.example.com/us/"/>
    <xhtml:link rel="alternate" hreflang="de-DE" href="https://www.example.com/de/"/>
    <xhtml:link rel="alternate" hreflang="zh-Hans" href="https://www.example.com/zh-hans/"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/"/>
  </url>
  <url>
    <loc>https://www.example.com/uk/</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://www.example.com/"/>
    <xhtml:link rel="alternate" hreflang="en-GB" href="https://www.example.com/uk/"/>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://www.example.com/us/"/>
    <xhtml:link rel="alternate" hreflang="de-DE" href="https://www.example.com/de/"/>
    <xhtml:link rel="alternate" hreflang="zh-Hans" href="https://www.example.com/zh-hans/"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/"/>
  </url>
  <url>
    <loc>https://www.example.com/us/</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://www.example.com/"/>
    <xhtml:link rel="alternate" hreflang="en-GB" href="https://www.example.com/uk/"/>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://www.example.com/us/"/>
    <xhtml:link rel="alternate" hreflang="de-DE" href="https://www.example.com/de/"/>
    <xhtml:link rel="alternate" hreflang="zh-Hans" href="https://www.example.com/zh-hans/"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/"/>
  </url>
  <url>
    <loc>https://www.example.com/de/</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://www.example.com/"/>
    <xhtml:link rel="alternate" hreflang="en-GB" href="https://www.example.com/uk/"/>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://www.example.com/us/"/>
    <xhtml:link rel="alternate" hreflang="de-DE" href="https://www.example.com/de/"/>
    <xhtml:link rel="alternate" hreflang="zh-Hans" href="https://www.example.com/zh-hans/"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/"/>
  </url>
  <url>
    <loc>https://www.example.com/zh-hans/</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://www.example.com/"/>
    <xhtml:link rel="alternate" hreflang="en-GB" href="https://www.example.com/uk/"/>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://www.example.com/us/"/>
    <xhtml:link rel="alternate" hreflang="de-DE" href="https://www.example.com/de/"/>
    <xhtml:link rel="alternate" hreflang="zh-Hans" href="https://www.example.com/zh-hans/"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/"/>
  </url>
</urlset>

One <url> per version, each listing all versions.

Runs entirely in your browser. Nothing you type here is uploaded or stored by TapCub.

Share these inputs: the values go after the # in the link, so they never reach a server.

Version v1.0Updated Update history

Read the result

What the generator tells you

The table shows how each code is read; the checklist explains anything that is wrong or worth a second look; the three code blocks are the same set in three formats.

Code and meaning

Each valid code is shown in its conventional form with its meaning, so you can spot a code that is valid but not what you meant: uk is Ukrainian, se is Northern Sami, DE alone means German, not Germany.

Errors and left-out lines

Codes Google would ignore (en-UK, jp, zh_CN, es-419) and relative URLs are errors. Those lines are left out of the output so you never copy a broken tag; the message suggests the correct form.

Fallbacks

If you have en-GB and en-US but no plain en, English speakers elsewhere match nothing. Google suggests a language-only catch-all; x-default covers everyone whose language you do not serve at all.

Three formats

Link tags, sitemap entries and the HTTP header are equivalent; pick one per page. The sitemap is easiest for large sites, the header for PDFs, the tags for everything else.

The generator checks the codes and URLs you give it. It cannot see whether each listed page actually carries the same set; that return-link check needs a crawl of the live pages.

How to use it

Three steps

Works the same for two versions or two hundred.

  1. 1

    List every version

    One line per language or region version of the page, including the one you are editing. Paste two columns from a spreadsheet if you keep a URL map.

  2. 2

    Fix what is flagged

    Read the checklist from the top. Errors mean a line is left out; notes are suggestions, such as adding a language-only fallback or an x-default.

  3. 3

    Copy one format

    Put the link tags in the head of every listed page, or add the sitemap block, or send the header. The same set goes on every version.

Rules

What a valid hreflang value looks like

From Google’s documentation on localized versions. Values are case-insensitive; the conventional form is lowercase language, title-case script and uppercase region.

  • Language: ISO 639-1, two letters. Region: ISO 3166-1 alpha-2. Script: ISO 15924, four letters
  • A region alone is invalid; a language alone is fine
  • Every URL must be absolute, and every version must list itself and all the others
Examples of valid and invalid hreflang values
ValueValid?Why
deYesGerman, any region
en-GBYesEnglish for the United Kingdom
zh-Hant, zh-Hans-USYesTraditional Chinese; Simplified Chinese for the US
x-defaultYesFallback for unmatched languages
en-UKNoUK is reserved; the code is GB
jp, cnNoCountry codes; Japanese is ja, Chinese is zh
zh_CNNoUnderscore; use zh-CN
es-419NoNumeric regions are not supported
GBNoRegion without a language
Worked example

The “common mistakes” list, fixed

What the checker reports for the list behind the “Show common mistakes” button, line by line.

Common hreflang mistakes found in the sample list and their fixes
LineWroteProblemFix
1en-UKReserved region codeen-GB
2jpCountry code instead of languageja
3zh_CNUnderscorezh-CN
4es-419Numeric region (Latin America)es, or es-MX, es-AR… per country
5de /de/Relative URLhttps://www.example.com/de/
6–7en-us twiceSame code, two URLsKeep one URL for en-US

Of seven lines, only one would survive as written, and a set with one version does nothing. After the fixes there are six versions; add an x-default and put the identical set on all six pages.

Common mistakes

Why Google ignores hreflang

Invalid codes are easy to catch. These problems pass a syntax check and still break the setup.

No return links

The English page lists the German one, but the German page lists nothing back. Google needs both directions, or it ignores the pair.

Forgetting the page itself

Each version must include its own URL in the set. Templates that list only “the other languages” break this on every page.

Pointing to redirected or noindex URLs

hreflang URLs should be the final, canonical, indexable pages. A URL that redirects or carries noindex weakens the whole cluster.

Treating it as a redirect

hreflang only changes which URL appears in results. It does not move visitors, and automatic language redirects can stop Google crawling other versions.

FAQ

Hreflang questions

Still have a question?

Chat with the team behind TapCub — we usually reply within a few hours on business days.

What is hreflang?

An annotation that tells search engines a page has versions for other languages or regions, and which is which. Google uses it to show the matching version in results, for example the UK page to searchers in Britain. It is a hint, not a redirect.

Should I use HTML tags, the sitemap or HTTP headers?

Any one of them; Google treats them as equivalent and using more than one adds nothing. Tags are simplest for small sites, the sitemap for large ones because templates stay untouched, and the header for PDFs and other non-HTML files.

What is x-default?

The URL for users whose language or region matches none of your versions. It is often a language selector or your main international version. It is optional, but without it those users get whatever Google picks.

Is it en-UK or en-GB?

en-GB. The ISO 3166-1 code for the United Kingdom is GB; UK is a reserved code, and Google’s documentation says hreflang values with UK, EU or UN have no effect.

Should I use zh-CN or zh-Hans?

Both are valid. zh-Hans and zh-Hant describe the script (Simplified or Traditional) for any region; zh-CN, zh-TW and zh-HK describe the region. If you have one Simplified version for everyone, zh-Hans or plain zh is the more accurate choice.

Does every page need to list itself?

Yes. Google’s documentation says each language version must list itself as well as all other versions. The identical set goes on every page.

Can hreflang point to another domain?

Yes. Versions can live on different domains, such as example.de and example.co.uk, as long as every page links back. Make sure each domain is verified if you use Search Console to monitor it.

Is my list sent anywhere?

No. Codes are checked and the output is built in your browser. If you copy the share link, the list is stored after the # in the URL, which browsers do not send to servers.

Changelog

Update history

New features, fixes and data refreshes for this tool, newest first.

  1. · v1.0

    LaunchedFirst release.

Missing something or found an error? Tell us — requests that come up often go into the next update. All tool updates

See your data clearly. Find your growth.

Every click, backed by data. Install one line of code and see your first numbers in a minute.

No credit card · Free plans for analytics and chat · Cookieless analytics