Start a conversation

Digital in Europe

Hreflang: the markup mistake that makes your German pages vanish from German results

Hreflang tells the search engine which page is the German version of which English page. When the annotation is wrong, the engine ignores it and treats the German page as a copy of the English one. The German page then drops out of the German results without any error message.

China → France

A company builds a European site, translates it into German, French and Spanish, and publishes all of it. Weeks later the German version cannot be found by anyone in Germany, while the English version appears there instead. Nothing is broken: the pages load, the text is correct, the links work. The cause is usually a few lines in the header of each page that nobody on the team reads, and that the engine reads very carefully. The problem is common on sites built by teams who have never had to run several language versions of the same page.

What hreflang does, and what it does not

Hreflang is an annotation placed in the page header, in the sitemap or in the HTTP response. For a given page it lists the equivalent pages in the other languages and for the other countries, each with a code: a language, optionally followed by a country. When someone in Germany searches in German, the engine may replace the English result with the German one, because the annotation tells it they are the same page for different audiences. It is a signal and not an order. It does not translate, does not give a page a better position, and does not stop a page from being shown elsewhere. All it does is choose the right version among pages that already exist and are already indexed.

Why can a page disappear because of it? Because the engine avoids showing several results that look identical. When it finds pages that are nearly the same, it groups them and keeps one, called the canonical. A German page with an untranslated menu, English product names and technical specifications that are identical to the English page looks, to the engine, very close to it. The hreflang annotation is what proves they are intended for different audiences. If the annotation is invalid, the proof is ignored. The engine keeps the English page, the German one is filed as a duplicate, and nobody is told.

The three classic mistakes

  • No return link. The English page lists the German page as its equivalent, but the German page does not list the English one back. Hreflang only counts when both sides confirm each other, so the engine discards the pair. Every version has to list all the others and itself, and a version added later has to be added on every existing page, not only on the new one.
  • Codes that do not exist. The language is written first, then an optional country, with the codes of the international standards. Typical errors: a country alone with no language, the United Kingdom written with the wrong letters, an underscore where a hyphen is expected, or a code invented by the translation plugin. An invalid code is ignored without any message, as if the line were not there.
  • Annotations that contradict the canonical. The German page declares itself the German version, but its canonical tag points to the English page. The two signals say opposite things, and the canonical wins: the German page is told it is merely a copy. The same happens when hreflang points to addresses that redirect elsewhere, return an error or are blocked from indexing.

Other ways it goes wrong

Three more cases deserve a mention. The first is a page that does not reference itself: each page should appear in its own list, and many generators leave it out. The second is the default version. A special value, x-default, names the page to show when no language matches, which is often the English one or a language selector; omitting it is not an error but it leaves the choice to the engine. The third comes from automatic redirects by browser language or by IP address. If a visitor, or the engine's crawler, is sent to the English page whenever it arrives from outside a country, the crawler never sees the German page at all. Offer the choice with a visible link rather than forcing it.

How to see it from outside

  1. Open the German page and view its source. Look in the header for the lines that start with the word alternate and carry the hreflang attribute. Check that the German page itself is listed, that every language of your site is there, and that the codes are spelled as expected.
  2. Do the same on the English page and confirm that it lists the German one. Then follow each address listed and check that it loads directly, with no redirect, and carries the same list in return.
  3. Look at the canonical tag on each version. On a German page it should point to that same German page, not to the English one.
  4. In the free search tool for site owners, inspect the German address. If the report says the page is a duplicate and that the engine chose another canonical than yours, you have found the cause.
  5. In the performance report, filter on Germany and on the German page. If the English address collects the impressions that should belong to the German one, the substitution is not working.
What you seeLikely causeFirst thing to check
English page shows in German resultsAnnotation ignored; pages grouped as duplicatesReturn links on both versions
German page reported as a duplicateCanonical tag points to EnglishCanonical on the German page
Annotations present but no effectInvalid codes or redirecting addressesSpelling of codes; direct loading of each address
German version never crawledAutomatic redirect by language or countryVisit the German address without a redirect

Fixing it in a sensible order

Start with the canonical tags, because a wrong canonical cancels everything else. Then the list itself: have it produced by one template or one plugin that you understand, rather than typed on each page, since manual lists drift apart as soon as a page is added. Generate the full set of pairs from a single source, including every page, not only the home page. Then remove the automatic redirect by language. Finally, resubmit the sitemap and wait: the engine has to recrawl every page of the group before it trusts the new signal, and how long that takes depends on the size of the site and how often it is visited. A site that is only partly translated should link only the pages that genuinely exist in each language.

Hreflang does not repair a poor translation. If the German page is a machine translation with an English menu, the engine still sees little difference from the English page, and the buyer who lands on it sees the same. Fix the markup first, because it costs a few hours, then decide honestly whether the page deserves to be shown to a German buyer. A page you would not forward to a customer should not be the one you ask the engine to prefer.

Questions we get on this.

Should we use a language code alone or a language plus a country?

Use the language alone when one page serves every country that speaks it, and add the country when pages really differ by market: prices, delivery, legal pages, vocabulary. A German page for Germany and a separate one for Austria is justified if the information differs; if it does not, one German page is simpler and avoids two near-identical copies. Never use a country on its own, since the annotation always starts with a language. Whatever you choose, apply it the same way on every page and in every language, and keep a single table of the pairs that the whole team can read.

Does hreflang help us rank higher in Germany?

No. It chooses which of your own pages to show, not how high a page ranks. A German page that is correctly annotated and thin will still rank behind better German pages from competitors. What hreflang prevents is the case where your German page has been set aside as a copy, so that it never gets the chance to compete. The ranking itself still depends on the quality of the text, the match with what buyers search for, and the references that point to the site from Germany. Treat hreflang as hygiene: it removes a handicap, and it adds nothing more.

Our site uses a translation plugin. Is hreflang handled for us?

Often partly, and you cannot assume it. Some plugins produce the annotations correctly; others produce them only for some page types, add codes that do not match the standard, or translate pages at the moment of display so that the engine never sees a separate German address at all. Check by viewing the source of a page of each type: home, category, product, article. If the plugin loads the translation only in the browser, the engine may index the English page alone, and then there is nothing to annotate. In that case the fix is structural, with real addresses per language, and not a setting.