On this page
- What does hreflang do?
- The syntax of one tag
- Language and region codes Google accepts
- Three places to declare the set
- The rules that make a set count
- Every version lists itself
- Every link is returned
- The set is identical on every version
- Each URL is final and indexable
- Unmatched visitors get a fallback
- Tags sit inside a valid <head>
- A worked example: WordPress in subdirectories
- Common mistakes, and what each one breaks
- How do you check hreflang on a live page?
- How LangRelay handles hreflang
- Further reading in this cluster
Hreflang is an HTML attribute that tells search engines which URLs are language or regional versions of the same page. With it, a searcher in Germany gets your German page in the results and a searcher in Spain gets the Spanish one. You add it as a set of <link rel="alternate"> tags in each page's <head>, as an HTTP header, or as entries in an XML sitemap. It does not translate anything and it does not tell Google what language a page is in. It only connects versions that already exist.
What does hreflang do?#
Google asks for hreflang "so that we can understand that these pages are localized variations of the same content". Its documentation, last updated on 2026-09-21, is direct about one limit: "Google doesn't use hreflang or the HTML lang attribute to detect the language of a page; instead, we use algorithms to determine the language." The companion page on multilingual sites adds that Google reads the visible content of the page for this, and ignores the URL as well.
Once Google knows that /pricing/ and /de/pricing/ are the same page in two languages, it can swap one for the other in the results depending on the searcher's language and location. If the German page is thin or half in English, hreflang will not save it, because Google still judges the page on what it reads.
Google also notes that it may find alternate versions without any annotation. Declaring them yourself is safer, and the tags cost little once your setup generates them.
The syntax of one tag#
Each tag names one version of the page:
<link rel="alternate" hreflang="de" href="https://www.harbourcoffee.example/de/pricing/">rel="alternate" says the linked URL is another version of this document. hreflang holds a language code, optionally followed by a region code, or the reserved value x-default. href is the full URL of that version, including https://. Google's guidelines say alternate URLs "must be fully-qualified", so /de/pricing/ on its own is not enough.
A page carries one tag per version, itself included, and every version of the page carries the same set.
Language and region codes Google accepts#
The value has one code, or two joined by a hyphen:
- The first part is a language in ISO 639-1, the two-letter list:
en,de,fr,nl,pt,tr. - The optional second part is a region in ISO 3166-1 Alpha 2:
GB,US,AT,CH,BR. - Case does not matter to Google, though writing the region in capitals (
en-GB) follows the ISO convention. - A script subtag from ISO 15924 is allowed, for example
zh-Hantorzh-Hansfor Chinese, optionally with a region after it.
Four values go wrong often enough to list:
When you have several regional versions of one language, Google suggests a catch-all for everyone else who speaks it: a plain en page beside en-GB and en-AU, for example. The catch-all can be one of the regional pages if you have no generic version.
Three places to declare the set#
Google accepts hreflang in three forms and treats them as equal:
- Link tags in the HTML
<head>, the usual choice for web pages. - An HTTP
Link:header, for files that have no<head>, such as PDFs. <xhtml:link>entries inside each<url>of an XML sitemap.
Its documentation says you can combine them but "there's no benefit in Search", and that managing three implementations is harder than managing one. Pick the one your stack produces reliably. If you are deciding between the head and the sitemap, the article on hreflang in XML sitemaps goes through when each fits.
The rules that make a set count#
Every version lists itself#
The German page carries a tag pointing at the German page. Google's wording is "Each language version must list itself as well as all other language versions." The article on self-referencing hreflang and x-default covers the edge cases.
Every link is returned#
If the English page names the German page as its de alternate, the German page has to name the English page back. When two pages do not point at each other, Google ignores the tags. This stops another site from claiming to be a version of yours.
The set is identical on every version#
Each version prints the same list in any order, which is the easiest way to satisfy the first two rules.
Each URL is final and indexable#
Point every tag at the URL you want in the results: the HTTPS version, with your usual trailing-slash convention, returning 200 rather than a redirect. Google's canonical documentation asks for HTTPS URLs in hreflang annotations and says it prefers URLs that sit in an hreflang cluster when it chooses a canonical. How the two tags interact is the subject of hreflang and canonical tags.
Unmatched visitors get a fallback#
x-default names the page for searchers whose language you do not cover. Google introduced it in 2013 for language selectors and home pages that adapt to the visitor, and still describes it as working best on those.
Tags sit inside a valid <head>#
Google requires the link tags inside a well-formed head section and suggests pasting the rendered source into an HTML validator when in doubt. It also asks you not to combine hreflang with other attributes such as media on one tag.
A worked example: WordPress in subdirectories#
Take a coffee roaster's WordPress site written in English, with German and Dutch versions under /de/ and /nl/, and a separate UK English version under /en-gb/ because UK customers see prices in pounds. The pricing page exists in all four. This is the <head> of the German version:
<html lang="de">
<head>
<title>Preise und Abos | Harbour Coffee</title>
<link rel="canonical" href="https://www.harbourcoffee.example/de/pricing/">
<link rel="alternate" hreflang="en" href="https://www.harbourcoffee.example/pricing/">
<link rel="alternate" hreflang="de" href="https://www.harbourcoffee.example/de/pricing/">
<link rel="alternate" hreflang="nl" href="https://www.harbourcoffee.example/nl/pricing/">
<link rel="alternate" hreflang="en-GB" href="https://www.harbourcoffee.example/en-gb/pricing/">
<link rel="alternate" hreflang="x-default" href="https://www.harbourcoffee.example/pricing/">
</head>Line by line:
lang="de"on the<html>element declares the page language for browsers and screen readers. It is a separate attribute from hreflang with a separate audience; hreflang vs the HTML lang attribute explains both.- The canonical names the German page itself. Each language version is its own canonical.
- Four language tags list all versions, including this one.
x-defaultpoints at the English original, so a searcher in Brazil or Japan lands on the English page.- The English original appears twice, as
enand asx-default, which is allowed: Google saysx-defaultcan be used for any page.
The English, Dutch and UK pages carry the same five alternate lines, each with its own canonical and its own lang.
Now suppose the Dutch translation of a new page, /brewing-guide/, is not finished. The set for that page has three alternates plus x-default, and nl is missing on every version. Listing a Dutch URL that redirects, shows English text or returns 404 would break the return-link rule and send Dutch searchers to a page that does not exist in Dutch. Add nl to the set on the day the Dutch page goes live.
On WordPress, hreflang usually comes from the translation plugin, sometimes together with an SEO plugin that also writes tags into the head. The article on hreflang in WordPress covers how to see which plugin printed what.
Common mistakes, and what each one breaks#
The last row comes from Google's canonical documentation: rel="canonical" annotations that carry hreflang, lang, media or type attributes are not used for canonicalization.
How do you check hreflang on a live page?#
Search Console's International Targeting report has been deprecated. The help page that says so adds that Google "will continue to support and use hreflang tags on your pages", so the tags still count and checking them is up to you:
- Fetch the raw HTML, not the page your browser rendered:
curl -s https://www.harbourcoffee.example/de/pricing/ | grep -i hreflang. If the tags appear only after JavaScript runs, find out whether your setup prints them on the server. - Confirm every version lists itself and every other version, with the same set on each.
- Request each
hrefand confirm it returns 200 without a redirect. - Compare each version's canonical with its own URL.
- Check the codes against the table above.
- In Search Console, run URL Inspection on an indexed translated URL and compare "User-declared canonical" with "Google-selected canonical". The help page says the Google-selected value can only be read from indexed data; the live test cannot predict it.
For more than a handful of pages, Google's own documentation names two third-party tools, a tag generator by Aleyda Solis and a single-page tester from Merkle, and says that Google does not maintain or check them. A site crawler that reads hreflang does the same job across the whole site.
How LangRelay handles hreflang#
LangRelay's WordPress plugin serves translated pages from your own WordPress, with each language in a subdirectory: /de/, /nl/, /en-gb/. The hreflang set comes from LangRelay and the plugin prints it as given. It contains the original page, every language in which that page has an approved and live translation, and x-default on the original's URL. The same set appears on the original and on every translated version, so return links hold by construction.
The codes come from one place. A target language in LangRelay is a BCP 47 tag such as de or en-GB, and the hreflang value and the lang attribute are that tag, while the URL prefix is its lowercase form.
A language joins a page's set once that page's translation is live, and until then the set leaves it out. Once a language is live on at least one page, a page with no approved translation yet answers under that language's prefix with the original, and that response carries no hreflang set. After each publish, LangRelay fetches the translated page and checks its lang, its canonical, its own hreflang entry and the x-default entry. A page that contradicts what was published is flagged on the release.
The plugin prints hreflang in the head only and does not generate a multilingual sitemap. LangRelay's script embed for non-WordPress sites translates in the browser, so crawlers see the original language and no hreflang is printed for it. The multilingual SEO page covers the rest of what the plugin does for search, and if you want to see the output on your own site, book a demo.
Further reading in this cluster#
Sources
The pages this one cites, with the day each was read.
- 01Localized versions of your pages (Google Search Central, last updated 2026-09-21)developers.google.com, checked 6 October 2026
- 02Managing multi-regional and multilingual sites (Google Search Central, last updated 2025-12-10)developers.google.com, checked 6 October 2026
- 03How to specify a canonical with rel="canonical" and other methods (Google Search Central, last updated 2026-07-10)developers.google.com, checked 6 October 2026
- 04The International Targeting report is deprecated (Search Console Help)support.google.com, checked 6 October 2026
- 05URL Inspection tool (Search Console Help)support.google.com, checked 6 October 2026
- 06Introducing "x-default hreflang" for international landing pages (Google Search Central Blog, 2013-04-10)developers.google.com, checked 6 October 2026



