Hreflang Checker

Check a page's hreflang tags and every page they name: return links, codes, redirects, noindex and canonicals, with the fix for each.

HTML and HTTP Link header · up to 20 alternates read · Google's and Yandex's rules, quoted

How does hreflang work?

Each language or regional version of a page lists every version, itself included, with a language code and a full URL. Search engines then show the version that matches a searcher's language or region.

Google reads the set from any of three places: <link rel="alternate" hreflang="…"> tags in the page's <head>, an HTTP Link header, or xhtml:link entries in an XML sitemap. Google calls them equivalent and says using all three brings no benefit.

The versions can sit on other domains, and the same set goes on every page in it. The checker above reads one page's set, then fetches every page it names and reads theirs, so it sees the whole cluster rather than one page's half of it.

  1. en/

    <link rel="alternate" hreflang="en" href="https://www.example.com/" />
    <link rel="alternate" hreflang="de" href="https://www.example.com/de/" />
    <link rel="alternate" hreflang="fr" href="https://www.example.com/fr/" />
    <link rel="alternate" hreflang="x-default" href="https://www.example.com/" />
  2. de/de/

    <link rel="alternate" hreflang="en" href="https://www.example.com/" />
    <link rel="alternate" hreflang="de" href="https://www.example.com/de/" />
    <link rel="alternate" hreflang="fr" href="https://www.example.com/fr/" />
    <link rel="alternate" hreflang="x-default" href="https://www.example.com/" />
  3. fr/fr/

    <link rel="alternate" hreflang="en" href="https://www.example.com/" />
    <link rel="alternate" hreflang="de" href="https://www.example.com/de/" />
    <link rel="alternate" hreflang="fr" href="https://www.example.com/fr/" />
    <link rel="alternate" hreflang="x-default" href="https://www.example.com/" />
The same set on all three pages of a made-up site: each lists itself and the other two, plus x-default for everyone else (written by the generator below).
Hreflang checker: shop.example.com's five language versions in a return-link matrix, one pair missing its return linkHreflang checker: shop.example.com's five language versions in a return-link matrix, one pair missing its return linkThe verdictHow many pairs point both ways. Google ignores a pair unless both pages link to each other.FindingsEach problem with the pages it's on and its source: Google's or Yandex's own page.What search engines readWhere Google and Yandex read hreflang: the HTML, the HTTP header, the sitemap.Return linksOne row per page: does it list the page in each column? Select a cell for both sides and the tag to add.
A made-up shop: the verdict and findings, what Google and Yandex read, and the return-link matrix where each cell says whether one page lists the other. Select a number to see what each part shows.

Which hreflang codes are valid?

An ISO 639-1 language (de), optionally with an ISO 3166-1 alpha-2 region (de-AT) or an ISO 15924 script (zh-Hant). Case doesn't matter. A region on its own isn't valid.

Spanish shows the usual traps. es reaches Spanish speakers everywhere; es-ES and es-MX target Spain and Mexico; es-419, the code for Latin America, isn't supported by Google, so list the countries or use es. The United Kingdom is GB, never UK: Google ignores reserved codes in part.

Yandex takes the same languages and regions, plus Russian regions from ISO 3166-2:RU, which Google doesn't support.

CodeGoogleWhat it means
enSupportedEnglish, any region
en-GBSupportedEnglish, United Kingdom
en-UKNot supportedUK is reserved: write GBUse en-GB
esSupportedSpanish, any region
es-ESSupportedSpanish, Spain
es-MXSupportedSpanish, Mexico
es-419Not supportedLatin America isn't an ISO 3166-1 regionUse es
zh-HantSupportedChinese in Traditional script
zh-TWSupportedChinese, Taiwan
en_USNot supportedAn underscore isn't a codeUse en-US
GBNot supportedA region alone isn't valid
x-defaultSupportedThe page for unmatched languages
Each verdict computed by the checker's own code reader at build time.

Do I need x-default?

It's optional. x-default names the page for searchers whose language or region the set doesn't list; Google designed it for language selector pages.

Point it at the page you'd want an unmatched visitor to see: a language picker, or the version you treat as international. It counts like any other entry, so the page it names should list the set too.

Yandex reads x-default in the HTML markup as well.

Searcher's languageVersion it matches
German (Austria)de-AT
German (Germany)de
Englishen
Portuguese (Brazil)x-default
A made-up set of en, de, de-AT and x-default: the version each searcher's language matches (Google's rule; which result a searcher sees is Google's choice).

HTML, HTTP header or sitemap: where should hreflang go?

Pick one. Google reads all three the same way; Yandex reads only the HTML markup and no longer reads language versions from sitemaps.

Use the HTML <head> for ordinary pages. The HTTP Link header suits PDFs and other files without a head. Sitemaps keep large sets out of the page: each <url> lists every version with xhtml:link, and a sitemap can only list URLs below the folder it's served from.

This checker reads the HTML and the header. It doesn't open sitemaps yet: if your hreflang lives there, check the file with the Sitemap Checker.

MethodGoogleYandex
HTML <link>Reads itReads it
HTTP Link headerReads itNot in its docs
XML sitemapReads itNot supported
Read from Google's and Yandex's own pages on localized versions, 2026-11-01.

How do hreflang and canonical work together?

Each version's canonical should be itself, and the hreflang set should name those canonical URLs. A version whose canonical names another language's page asks Google to treat that page as the original.

Google asks for a canonical in the same language as the page. A rel=canonical that carries hreflang is ignored as a canonical, and a redirect is itself a strong canonical signal, so the tags should name the URL a redirect ends at. The checker flags alternates that redirect, carry noindex, or name another URL as canonical.

Right

/de/ canonical → /de/
hreflang de → /de/

The German page is its own canonical, and the set names it.

Wrong

/de/ canonical → /en/
hreflang de → /de/

The German page names the English one as canonical: it asks Google to treat the English page as the original.

Two made-up German pages, read by Google's canonical rules.

Where does hreflang come from in WordPress, Shopify and Wix?

From the multilingual plugin or the platform, not from SEO plugins on their own. Each documents where its tags go:

When the checker finds a missing return link on a WordPress site, the usual cause is a page that wasn't translated or linked as a translation in the plugin, so the plugin doesn't list it. Check the pair in the plugin's translation screen, then run the check again.

ProductWhere the tags gox-default
WPMLThe page <head>, or the Yoast SEO or Rank Math sitemap when WPML SEO's sitemap is on (not both)Yes
PolylangThe page <head>Home page only
TranslatePressThe page <head>A setting
WeglotThe page <head>Not by default
ShopifyEvery page's <head> and the sitemap, for markets with their own domain, subdomain or subfolderYes
WixThe page's code, by defaultYes
From each vendor's own documentation, checked 2026-11-01.

Hreflang generator: write the tags

Switch the tool to Generate tags, list each version's code and URL, and copy the same set as HTML tags, one HTTP Link header or sitemap entries.

Each code is checked as you type, with the fix Google expects (en-UK becomes en-GB, es-419 becomes es); a row is written only when its code and full URL are valid. Put the same set on every page it lists, then press Check these pages to read them back.

<link rel="alternate" hreflang="en" href="https://www.example.com/" />
<link rel="alternate" hreflang="de" href="https://www.example.com/de/" />
<link rel="alternate" hreflang="es" href="https://www.example.com/es/" />
<link rel="alternate" hreflang="x-default" href="https://www.example.com/" />
The generator's HTML output for a made-up three-language site with x-default.

Sources

Hreflang Checker FAQ

How do I check hreflang tags?

Paste any page of the set above and press Check. This hreflang checker reads the page's tags from its HTML and its HTTP Link header, fetches each page they name (up to 20), and shows in a matrix which pairs link back to each other, plus codes Google doesn't support, redirects, noindex and canonicals pointing elsewhere.

Is a hreflang validator the same as a checker?

Here, yes. It validates each code against ISO 639-1 and ISO 3166-1 as Google reads them, checks that every URL is fully qualified, and goes further than one page: it reads every alternate to confirm the return links Google requires.

What does "no return tags" mean?

One page lists another, but that page doesn't list it back. Google ignores the pair. Add the missing tag to the page that lacks it; the checker shows the exact tag when you select the cell.

Does a page need to reference itself in hreflang?

Yes. Google says each language version must list itself as well as all other versions. A set without a self-referencing hreflang tag is incomplete; the matrix shows it on the diagonal.

Which hreflang code should I use for Spanish?

es for Spanish speakers anywhere, or a country: es-ES for Spain, es-MX for Mexico, es-US for the United States. Google doesn't support es-419 (Latin America); list the countries or use es.

Should hreflang be in the sitemap or in the HTML?

Either: Google treats the HTML, the HTTP header and the sitemap as equivalent, and using more than one brings no benefit. Yandex no longer reads language versions from sitemaps, so use the HTML if Yandex matters to you.

Why does the checker say it couldn't check a page?

Our server couldn't read it: bot protection answered, it timed out, or our per-site limit held it back for a minute. That isn't a fault in your tags, so those pairs aren't counted as broken. Open the page in a browser to check by hand, or run the check from that page later.

Why are only 20 alternates checked?

To keep each run quick and fair to the sites it reads. When a page names more, the checker says how many it read; every row in the pages table has Check from here, so you can start the next run from any version.

Missing something?Suggest a feature or a new tool