hreflang is a line in the source code that tells search engines which language version of a page belongs to which audience. You need it as soon as the same content sits in several languages or for several countries on separate URLs. Three rules decide whether it works: every version points at all versions including itself, every reference is reciprocal and there is one x-default for visitors who fit none of the languages given. hreflang is not a ranking factor and it only steers which version is shown to whom. The mistake that most often costs a whole language market sits somewhere else: a language version without an entry of its own in your sitemap stays quietly invisible, even when the hreflang itself is perfect.
When you need it and when you do not
You need hreflang in two cases. The first is that the same page exists in several languages on separate URLs, for example /diensten.html and /en/services.html. The second is that the same language has two versions for two countries that differ in content: other prices, other VAT treatment.
You do not need it for a site in one language for one market. Nor for a page that exists in only one language.
There is a third case where the answer is uncomfortable. If your site switches language without the URL changing, there is no second URL to point at. A search engine indexes one version of one URL, so you have one language in the index and the rest does not exist. If you want four languages to be findable, you need four URLs. That is a build decision and not a setting.
The three rules that decide whether it works
This is what a complete set looks like, in the <head> of every page:
<link rel="alternate" hreflang="nl" href="https://uwdomein.be/diensten.html">
<link rel="alternate" hreflang="en" href="https://uwdomein.be/en/services.html">
<link rel="alternate" hreflang="de" href="https://uwdomein.be/de/leistungen.html">
<link rel="alternate" hreflang="fr" href="https://uwdomein.be/fr/services.html">
<link rel="alternate" hreflang="x-default" href="https://uwdomein.be/en/services.html">
Complete. The set contains all versions that exist. If you forget one, it does not belong to the group.
With a self-reference. Every page also points at itself. On the Dutch page the line with hreflang="nl" is therefore present as well. Without that line Google ignores the whole set.
Reciprocal. These five lines sit literally identically on all four pages. If A points at B and B does not point back at A, Google drops the pair. This is the most common error and you see it with the naked eye.
Two further requirements. Use absolute URLs with protocol and domain, never relative paths. And let every URL given load directly. An hreflang that points at an address that redirects or that ends up elsewhere through a canonical is ignored.
What x-default exactly is
x-default is not your main language. It is the version for everyone who falls under none of the languages given: a visitor from Spain, Japan or Brazil. In practice you pick either your language chooser or the most broadly usable version, usually the English one.
One per set. It is not compulsory. It is advisable, because without x-default the search engine picks for itself and then it becomes your main language.
Language codes with and without a region
The language code is two letters from ISO 639-1: nl, en, de, fr. The region code behind it is optional, two letters from ISO 3166-1 Alpha 2, always with a hyphen in between: nl-BE, nl-NL, de-AT, fr-CH. A region without a language in front of it does not exist.
This is where it often goes wrong, because the codes for languages and the codes for countries resemble each other without being the same.
| What is there | What it means | What it should have been |
|---|---|---|
hreflang="be"
|
Belarusian |
nl-BE or fr-BE
|
hreflang="uk"
|
Ukrainian |
en-GB
|
hreflang="en-UK"
|
invalid and gets ignored |
en-GB
|
hreflang="nl_BE"
|
invalid, underscore instead of hyphen |
nl-BE
|
hreflang="eu"
|
Basque | no code covers the EU, pick per language |
Split nl-BE and nl-NL only when the content really differs. If you have one Dutch-language page for both countries, simply use nl. That code covers all Dutch speakers wherever they sit. Two identical pages under two region codes split your signals and double your maintenance.
The region code steers on the presumed location of the visitor and not on their language setting. nl-BE means Dutch speakers in Belgium.
Where you put it: pick one place
-
<link>elements in the<head>. The most used and the easiest to check, because you see it in the source code. -
A
Link:HTTP header. Needed for files without a head, such as a PDF. - In the XML sitemap. Best for large sites, because you maintain everything in one place instead of on every page.
Pick one. Two methods side by side that contradict each other is worse than none at all.
In the sitemap it looks like this. The namespace xmlns:xhtml belongs on <urlset>:
<url>
<loc>https://uwdomein.be/diensten.html</loc>
<xhtml:link rel="alternate" hreflang="nl" href="https://uwdomein.be/diensten.html"/>
<xhtml:link rel="alternate" hreflang="en" href="https://uwdomein.be/en/services.html"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://uwdomein.be/en/services.html"/>
</url>
The language version without an entry of its own stays quietly invisible
This is the part that costs a whole market and that nobody notices.
A search engine finds a page along three routes: an ordinary link with an href in it, an entry in your sitemap or an hreflang reference from a page it already knows. If those three fall away, the page does not exist.
The scenario we see most often goes like this. The language chooser at the top is a menu in JavaScript that produces no real link. The sitemap is generated on the basis of the main language and therefore contains only Dutch URLs. The German and French pages simply sit on the server. Nobody points at them.
The nasty part is that nothing raises an alarm. Search Console reports no error, because a URL that Google never discovered cannot produce an error either. Your statistics show no drop, because there was never any traffic. The pages exist, the translation invoice has been paid and the market stays empty.
Two checks of one minute each:
-
Type
site:uwdomein.be/de/in Google. Zero results means zero indexed German pages. - Open the Sitemaps section in Search Console and look at the number of discovered URLs. A site of 20 pages in four languages should show about 80 URLs there. If it says 20, you have one language in the index and three invisible ones.
Pages times languages. That is the most usable rule of thumb from this chapter. If the number deviates strongly, you are not looking for hreflang errors but for missing URLs.
One last trap, right after that. A canonical from /de/diensten.html to /diensten.html takes your German page out of the index, however much hreflang you put around it. Every language version gets a canonical that points at itself. See chapter 1.
What hreflang does not do
It does not raise positions. hreflang decides which version someone gets to see and not in which place. It is moreover a hint and not an order: Google may show another version when that one fits the search better.
It also does not solve duplicate content between languages. That problem does not exist, because a translation is not a copy.
Google, Bing and Yandex use hreflang. Whether the systems behind AI answers do anything with it is not documented and we have not measured it. For GEO something else counts: every language its own URL with real text in the server HTML. See chapter 6 and chapter 7.
Checking it yourself, without paid tools
Search Console does not report hreflang errors as a separate category. So you check yourself. The manual test takes two minutes and catches most errors:
- Open a page and press Ctrl+U or Cmd+Option+U.
-
Search for
hreflangand note down the set. - Open one of the URLs listed and repeat step 2.
- If exactly the same set is there including the self-reference, the reciprocity is in order.
- Check that every URL loads directly without a redirect.
Besides that there are free hreflang checkers that walk through your site and set out the non-reciprocal pairs in a row. Useful from about twenty pages onwards. We name none of them, because such lists age.
What you can do yourself and what you cannot
To do yourself, without a developer:
- The manual reciprocity test on your five most important pages.
-
Checking language codes for
be,ukanden-UK. This alone solves a surprising share of the cases. -
Adding an
x-defaultif it is missing. - Counting how many URLs your sitemap contains and setting that against pages times languages.
- Checking that every language version has a canonical to itself.
What you need help with:
- A language chooser that produces no real links. That is a build decision and not a checkbox.
- A CMS that makes a separate sitemap per language without an index that brings them together.
- Four languages across hundreds of pages, where hreflang has to come from the sitemap instead of from the head of every page.
- A redirect based on the country of the visitor. That pushes the crawler to the same version every time, which means the rest is never read.
Count on half a day for a site of twenty pages in four languages, including the checking afterwards. This chapter is small. Anyone who has it wrong does lose a whole language market without seeing it.
Frequently asked questions
What is hreflang and do I need it?
hreflang is a line in the source code that tells search engines which language version of a page belongs to which audience. You need it as soon as the same content sits in several languages on separate URLs. For a site in one language for one market it has no use at all.
What does x-default mean in hreflang?
It is the version shown to visitors who fall under none of the languages or regions given, for example someone from Japan or Brazil. It is not the same as your main language. You give one per set and in practice it points at your language chooser or at the English version.
Do I have to give nl-BE and nl-NL separately?
Only when the two pages really differ in content, for example through other prices or other delivery terms. If the text is identical, simply use nl. That code covers all Dutch speakers and you avoid double maintenance.
Why does my hreflang not work?
In most cases the reciprocity is missing: page A points at B and B does not point back at A, after which Google drops the pair. Other common causes are a missing self-reference, a wrong language code such as be or en-UK and a URL given that redirects instead of loading directly.
Is hreflang a ranking factor?
No. hreflang decides which language version someone gets to see and not in which position you sit. It is moreover a hint and not an order: Google may show another version when it thinks that one fits better.
Would you rather not do this yourself: SEMANU carries out the full SEO and GEO audit for 1,450 euro, report and working session included. What it covers is on the guide page.
Measurability and findability belong in your software strategy
Measurability and findability are part of strategic advice, not a separate discipline. If you would rather not do this yourself, we take it up in the software strategy: what you measure, which threshold justifies an action and who follows it up.