Hreflang implementation: tags, headers or a sitemap
Hreflang is declared in one of three places: <link> elements in each page's <head>, an HTTP Link header, or an XML sitemap. Google's documentation says "The three methods are equivalent from Google's perspective," so the choice is practical, not tactical. The hreflang overview covers what the declaration means; this page covers how each method is written.
Choosing a method
Pick the method that your site can keep correct, and use only one. Google's documentation, last updated on and checked on , adds a warning to its statement of equivalence: "While you can use all three methods at the same time, there's no benefit in Search (in fact, it maybe be much harder to manage three implementations instead of just picking one)."
| Method | Suits | Weak point |
|---|---|---|
HTML <link> elements | Most sites, where templates can be edited | Every page lists every version; large sets mean long heads |
HTTP Link header | Files with no <head>, such as PDFs | Set by server configuration, invisible in page source |
| XML sitemap | Large sites, or templates that are hard to change | Kept apart from the pages, so it can drift from them |
Whatever the method, the rules are the same: each version lists itself and every other version, and every address is written in full.
In the HTML head
The HTML method adds one <link> element per version to the <head> of every version. Google's documentation gives the form of each element:
<link rel="alternate" hreflang="lang_code" href="url_of_page" />and an example for a company with English pages for the UK, the US and everyone else, a German page, and a default page with a language selector:
<head>
<title>Widgets, Inc</title>
<link rel="alternate" hreflang="en-GB"
href="https://en-gb.example.com/page.html" />
<link rel="alternate" hreflang="en-US"
href="https://en-us.example.com/page.html" />
<link rel="alternate" hreflang="en"
href="https://en.example.com/page.html" />
<link rel="alternate" hreflang="de"
href="https://de.example.com/page.html" />
<link rel="alternate" hreflang="x-default"
href="https://www.example.com/" />
</head>The same set appears on all five pages. Google describes it plainly: "The set of links is identical for every version of the page." The elements must sit inside a well-formed <head>, and hreflang should not be combined with other attributes, such as media, in a single <link>.
In an HTTP header
The header method sends the same information with the response, in a Link header. Google calls it "useful for non-HTML files (like PDFs)", which have no <head> to hold the elements. Its example for a PDF in English, Swiss German and German:
Link: <https://example.com/file.pdf>; rel="alternate"; hreflang="en",
<https://de-ch.example.com/file.pdf>; rel="alternate"; hreflang="de-CH",
<https://de.example.com/file.pdf>; rel="alternate"; hreflang="de"As with the HTML method, "The Link: header returned for every version of a page is identical." The header is set in the server's configuration or by the application that serves the file.
In an XML sitemap
The sitemap method moves every declaration out of the pages into the sitemap. Each version gets its own <url> entry with a <loc>, and each entry lists every version, itself included, as an <xhtml:link> child with rel="alternate" and an hreflang value. The sitemap declares the namespace at the top:
xmlns:xhtml="http://www.w3.org/1999/xhtml"Google spells out the consequence for a set of three: "your sitemap will have entries for the URLs of each version, and each entry will have 3 identical child entries." It also notes that these child elements "don't count towards the URL limit for sitemaps," and that the order of the children does not matter, though a fixed order makes mistakes easier to spot.
The sitemap has to sit where it is allowed to describe those addresses: "a sitemap can only contain descendant URLs of the directory where the sitemap is hosted from."
Switching from one method to another
A move between methods is safest as a swap, not an overlap. Build the new declarations completely, for every version, and check them against the served pages or the published sitemap. Only then remove the old ones, in the same release, so there is no period in which the two disagree.
Moving from HTML elements to a sitemap is the common direction on growing sites, because the heads stop getting longer with every new language. The risk in that move is losing the link between the declarations and the pages: when a page is renamed or removed, the template used to update itself, and the sitemap now has to be regenerated from the same source.
Keeping the set current
Most broken hreflang is not written wrong; it goes wrong later. A new language added to some pages and not others, a version that moved without its siblings being told, a page deleted while the others still point to it: each leaves the set asserting something that is no longer true.
The defence is to generate the declarations from one list of versions, wherever that list lives, rather than editing them by hand on each page. When the list changes, every page and every sitemap entry changes with it.
WordPress and other CMSs
On a CMS, hreflang usually comes from a multilingual plugin or from the theme, which writes one of the three methods for you. That saves the typing and moves the risk: the output depends on how each translation is linked inside the CMS, and a missing link there becomes a missing return tag on the page.
Check what the site actually serves, not the settings screen. Open the source of two versions of the same page and compare their sets; they should be identical, with each page present in both.
Checking the result
A correct implementation passes three checks, whichever method you chose.
- Every version lists itself and all the others. Google ignores a pair that does not point both ways; the hreflang errors page covers this and the other common faults.
- Every address is complete. Google requires fully qualified URLs, "including the transport method (http/https)."
- The canonical agrees. Each version should name itself as canonical, as covered under hreflang and canonical.
If the set has a language selector or a page for unmatched visitors, it belongs in the set as the default entry, covered under x-default.
FAQ
Which hreflang method is best?
None, from Google's side: its documentation calls the three methods equivalent. Use HTML link elements if you can edit your templates, the HTTP header for files without a head such as PDFs, and a sitemap for large sites or awkward templates. What matters is choosing one and keeping it correct.
Can I use HTML tags and a sitemap together?
You can, but Google says there is no benefit in Search and that managing several implementations is harder than picking one. Two methods also give the declarations two chances to disagree. Choose the method your site can keep accurate and remove the other once the switch is checked.
How do I add hreflang in WordPress?
Usually through a multilingual plugin or the theme, which writes the tags, the header or the sitemap entries for you. The output depends on how translations are linked inside the CMS, so check the served pages: two versions of one page should list the same set, each including itself.
Does hreflang go in the sitemap or on the page?
Either, and not necessarily both. Google treats the HTML elements and the sitemap entries as equivalent. On the page the set sits in each <head>; in the sitemap each version gets its own entry listing every version. Pick the one that is easier to keep complete on your site.