In the early days of the web, most websites existed in a single language. English, usually. If your site happened to attract visitors from France or Japan, that was nice, but you weren't building separate pages for them. Search engines, for their part, didn't have sophisticated mechanisms for understanding which version of a page was meant for which audience. The result was a mess — Google might show the German version of your product page to users searching in English, or the US-targeted page to someone in Australia who should've been seeing locally relevant pricing and content. Users would land on pages in languages they couldn't read, or they'd see the right language but the wrong currency, the wrong phone number, the wrong shipping information.
Key Takeaways
- Three Ways to Implement Hreflang
- Method 1: HTML Link Elements
- Method 2: XML Sitemap
- Method 3: HTTP Headers
- Common Mistakes That Break Hreflang
- Validating Your Implementation
Google introduced the hreflang annotation in December 2011 to solve this problem. The concept came from a real and growing need: multinational companies were building localized versions of their sites and had no reliable way to tell search engines which version should appear for which audience. Before hreflang, webmasters tried various workarounds — setting geographic targets in Google Search Console, using ccTLDs (country-code top-level domains like .de or .fr), or just hoping Google would figure it out from the content. Some of those approaches helped, but none of them gave Google the precise, page-level signal it needed to consistently serve the right version to the right user.
The hreflang tag is, when you break it down, a simple instruction. It says: "This page exists in multiple versions for different languages and regions, and here's where to find each one." It uses standardized language codes (ISO 639-1) and optional region codes (ISO 3166-1 Alpha 2) to specify the intended audience. So en-us means English for the United States. fr-ca means French for Canada. de means German, without a regional specification — which implies it's for all German-speaking audiences. The concept is elegant. The implementation, as we'll see, can get surprisingly tricky.
Three Ways to Implement Hreflang
Google supports three different methods for implementing hreflang annotations. You can add them as HTML link elements in the <head> of each page, include them in your XML sitemap, or deliver them through HTTP headers. Each method has its own strengths and weaknesses, and the right choice depends on your site's architecture, size, and technical constraints.
Before diving into each method, one rule applies to all of them: hreflang annotations must be bidirectional. If Page A declares that Page B is its French equivalent, then Page B must also declare that Page A is its English equivalent. If the annotations don't point in both directions, Google may ignore them entirely. This reciprocal requirement trips up a lot of people. I've audited sites where the English pages correctly pointed to the French versions, but the French pages didn't point back. Half the implementation was there, and yet effectively none of it was working. Our article on 301 vs 302 Redirects: Impact on Link Equity explores this idea in more depth.
Method 1: HTML Link Elements

This is probably the most common implementation method and the one most people encounter first. You add <link> elements to the <head> section of each page, one for each language/region variant including the page itself. Yes — every page must reference itself in its own hreflang annotations. That self-referencing requirement is easy to forget and another common source of errors.
Here's what it looks like for a page that exists in English (US), English (UK), French, and German:
<head>
<link rel="alternate" hreflang="en-us" href="https://example.com/page" />
<link rel="alternate" hreflang="en-gb" href="https://example.co.uk/page" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/page" />
<link rel="alternate" hreflang="de" href="https://example.com/de/page" />
<link rel="alternate" hreflang="x-default" href="https://example.com/page" />
</head>
Notice the x-default value at the end. That's a special hreflang value that tells Google which page to show when none of the specified language/region combinations match the user's location or language settings. It's your fallback. Often, sites point x-default to their English version or to a language selector page. You don't strictly need x-default — it's optional — but including it gives Google a clear instruction for edge cases, and I'd recommend always having one.
The HTML method works well for sites with a manageable number of language variants. If you have three or four versions of each page, adding a handful of link elements to the head is fine. But consider what happens when your site targets 30 countries and 15 languages. You could end up with 30+ link elements in the head of every page. That's a lot of extra HTML being loaded on every single page view. It increases page size, it can slow down initial parsing (however marginally), and it becomes a maintenance challenge. Every time you add a new language, you need to update the hreflang tags on every existing page across every version of the site. For large-scale international sites, this method starts to buckle under its own weight.
There's also a technical subtlety that matters. The hreflang link elements must appear in the <head> section, not the <body>. If your CMS or templating system injects them into the body — which I've seen happen with misconfigured plugins — Google won't process them. The HTML spec requires link elements to be in the head, and Google follows that requirement strictly for hreflang.
Method 2: XML Sitemap
This is the method I recommend for most medium-to-large international sites, and it's the one I want to spend the most time on because it sidesteps several of the problems that plague the HTML method.
Instead of adding hreflang annotations to every page's HTML, you declare them in your XML sitemap. Each URL entry in the sitemap includes <xhtml:link> elements that specify all the alternate language/region versions. Here's what a sitemap entry looks like:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://example.com/page</loc>
<xhtml:link rel="alternate" hreflang="en-us" href="https://example.com/page" />
<xhtml:link rel="alternate" hreflang="en-gb" href="https://example.co.uk/page" />
<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/page" />
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/page" />
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/page" />
</url>
<url>
<loc>https://example.co.uk/page</loc>
<xhtml:link rel="alternate" hreflang="en-us" href="https://example.com/page" />
<xhtml:link rel="alternate" hreflang="en-gb" href="https://example.co.uk/page" />
<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/page" />
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/page" />
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/page" />
</url>
</urlset>
Each URL in the sitemap lists all of its alternate versions, including itself. And the reciprocal requirement still applies — the UK version must be listed as a URL entry with its own set of xhtml:link elements pointing to all the other versions, including the US one. Every version must reference every other version. This is verbose, I know. A sitemap for a site with 1,000 pages in 10 languages would contain 10,000 URL entries, each with 10 xhtml:link elements. That's 100,000 xhtml:link elements in total. The files can get large. This ties directly into Canonical Tags and Their Effect on Links, which is worth reading next.
So why do I still prefer this method? Several reasons.
First, it decouples the hreflang logic from your page templates. Your HTML stays clean. You don't need to modify every page template to include the right set of link elements, and you don't need to worry about a theme update or CMS migration accidentally stripping out your hreflang tags. The sitemap is a separate file that can be generated and managed independently.
Second, it's easier to automate. Most sites with serious international presences generate their sitemaps programmatically anyway. Adding hreflang annotations to the sitemap generator is usually a simpler engineering task than modifying the page rendering pipeline. You can write a script that queries your database of pages and their translations, builds the appropriate xhtml:link elements for each URL, and outputs a valid XML sitemap. If you add a new language, you update the script and regenerate. The pages themselves don't need to change at all.
Third, Google processes sitemaps efficiently. Large sitemaps can be split into multiple files and referenced from a sitemap index file, which means you can organize your hreflang data across manageable chunks. The sitemap protocol supports files up to 50MB uncompressed or 50,000 URLs per file (whichever limit you hit first), and with gzip compression, even large files are transmitted efficiently. Here's what a sitemap index file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://example.com/sitemap-en-us.xml</loc>
</sitemap>
<sitemap>
<loc>https://example.com/sitemap-en-gb.xml</loc>
</sitemap>
<sitemap>
<loc>https://example.com/sitemap-fr.xml</loc>
</sitemap>
<sitemap>
<loc>https://example.com/sitemap-de.xml</loc>
</sitemap>
</sitemapindex>
One common mistake with the sitemap method: including URLs in the hreflang annotations that aren't actually in the sitemap or that return non-200 status codes. If you reference a URL that 404s or redirects, Google will discard that annotation. Every URL you reference in an hreflang annotation should be a live, indexable page that returns a 200 status code. Redirecting URLs, pages blocked by robots.txt, pages with noindex tags — none of those should appear in your hreflang annotations. This sounds obvious, but on large sites with thousands of pages and frequent content changes, broken references creep in surprisingly fast.
Another gotcha: make sure the URLs in your sitemap exactly match the canonical URLs of those pages. If a page's canonical tag points to https://example.com/page/ (with trailing slash) but your sitemap lists https://example.com/page (without trailing slash), Google may treat those as different URLs and not process the hreflang correctly. Consistency matters. Pick a URL format and stick with it everywhere — in your canonical tags, your sitemap, your hreflang annotations, and your internal links.
Method 3: HTTP Headers
The third method is using HTTP response headers to deliver hreflang annotations. This is the least commonly used approach, but it serves an important niche: non-HTML documents. If you need to specify hreflang for PDF files, downloadable documents, or other content types where you can't inject HTML link elements, HTTP headers are your only option (aside from the sitemap method).
The format uses the Link HTTP header:
Link: <https://example.com/page>; rel="alternate"; hreflang="en-us",
<https://example.co.uk/page>; rel="alternate"; hreflang="en-gb",
<https://example.com/fr/page>; rel="alternate"; hreflang="fr",
<https://example.com/de/page>; rel="alternate"; hreflang="de"
This gets sent as part of the HTTP response when the page is requested. Configuring it typically requires access to your web server configuration (Apache's .htaccess, Nginx config files) or your application code. It's not something you can do through most CMS admin panels.
I'll be honest — I rarely recommend the HTTP header method for HTML pages. It's harder to configure, harder to debug, and harder to maintain than either of the other two methods. You can't just "view source" to check if the annotations are present; you need to inspect the HTTP headers using browser developer tools, curl, or a crawling tool. If something breaks, it's often less visible. And for large sites with many language variants, the HTTP header can become extremely long, which some servers may truncate or handle poorly. We cover this in more detail in How to Handle Links During a Site Migration.
Where the HTTP header method does shine is for PDFs and other non-HTML resources that you want to appear in search results with the correct language targeting. If you have a product manual available in eight languages as PDF downloads, and you want Google to show the French PDF to French users and the Japanese PDF to Japanese users, HTTP headers are the way to go.
Common Mistakes That Break Hreflang
I've spent a probably unreasonable amount of time debugging hreflang implementations that weren't working, and certain patterns come up again and again. Let me walk through the most frequent mistakes.
Missing return links. I mentioned this earlier but it bears repeating because it's the single most common error. Page A says "my French version is Page B." But Page B doesn't say "my English version is Page A." Google sees the one-way annotation, can't confirm it, and ignores it. Both pages must point to each other. Every page in the hreflang set must reference every other page in the set, including itself. If you have five language versions, each page needs five hreflang annotations.
Wrong language or region codes. The language code must be in ISO 639-1 format (two-letter codes like "en", "fr", "de", "ja"). The region code, if used, must be in ISO 3166-1 Alpha 2 format (two-letter codes like "US", "GB", "CA", "DE"). I've seen people use three-letter language codes ("eng" instead of "en"), full country names ("France" instead of "FR"), and even made-up codes. Google doesn't recognize any of those. And the region code should be separated from the language code by a hyphen, not an underscore. en-US is correct. en_US is wrong, even though many programming frameworks use the underscore format internally.
Using hreflang for content that isn't truly equivalent. Hreflang tells Google that these pages are alternate versions of the same content in different languages. If your English page is a 3,000-word product guide and your "French equivalent" is a 200-word stub with half the information, those aren't really equivalent pages. Google may not penalize you for it directly, but the annotations won't work as intended because the pages don't serve the same user need. Each language version should cover the same topic with comparable depth, even if the exact content differs to account for cultural or regional differences.
Mixing hreflang with conflicting canonicals. This is a subtle one. If the English US page has a canonical tag pointing to itself (good) and the English UK page also has a canonical tag pointing to the US page (bad), you've told Google that the UK page is a duplicate of the US page. The canonical says "treat the US version as the original." But the hreflang says "these are separate versions for different regions." Those signals contradict each other, and Google will have to pick one — usually the canonical wins, which means your UK page gets ignored. Each language/region variant must have a self-referencing canonical tag. The canonical on the French page should point to the French page, not to the English one.
Not updating hreflang when pages are removed. Sites evolve. Pages get deleted, products go out of stock, content gets consolidated. When you remove a page that was part of an hreflang set, you need to also remove all the hreflang annotations pointing to it from all the other pages in the set. Otherwise, those other pages are telling Google "my Spanish version is over here" and Google follows the link to a 404 page. At best, the annotation gets ignored. At worst, it confuses Google's understanding of your site's international structure. I've seen this become a significant issue on e-commerce sites where products are frequently added and removed — the hreflang annotations get stale fast if there isn't an automated process keeping them in sync.
Validating Your Implementation
Once you've implemented hreflang tags, you need to validate them. Don't just assume everything is working because you added the code. Google Search Console's International Targeting report used to show hreflang errors, though the specific reporting has evolved over the years and isn't always as detailed as you'd want. Third-party tools are often more helpful for validation. For a deeper look at this topic, see our guide on Rel Attributes Explained: nofollow, sponsored, ugc.
Screaming Frog's SEO Spider can crawl your site and validate hreflang annotations across all three implementation methods. It'll flag missing return links, invalid language codes, and inconsistencies between your hreflang tags and canonical tags. Ahrefs' Site Audit also checks for hreflang issues. And there are dedicated hreflang validation tools — some free, some paid — that let you enter a URL and see exactly what hreflang annotations Google would find.
For quick spot-checks, you can view source on a page and search for "hreflang" to see the HTML annotations. For sitemap-based implementations, open the sitemap directly and look for the xhtml:link elements. For HTTP headers, use curl:
curl -I https://example.com/page
The -I flag returns just the headers, where you can check for the Link header containing your hreflang annotations.
I'd suggest running a full hreflang audit at least quarterly, or more often if your site changes frequently. Pages get added, pages get removed, URLs change structure during migrations, and all of those events can introduce hreflang errors that silently undermine your international targeting.
Language Targeting vs. Region Targeting
There's a distinction that's worth being explicit about. Hreflang handles two different dimensions: language and region. You can target just a language (hreflang="fr" for all French speakers everywhere), just a region implicitly through the language-region combination (hreflang="fr-ca" for French speakers in Canada specifically), but you cannot target a region without a language. There's no hreflang="ca" for "all languages in Canada." The language code is always required; the region code is always optional.
This has practical implications. If you have a page in French that's meant for all French-speaking users worldwide, use hreflang="fr". If you have a separate French page specifically for Canadian users (with Canadian pricing, Canadian regulations, Canadian spelling preferences), use hreflang="fr-ca". If you have both, the fr-ca version will take priority for users in Canada, while the generic fr version serves as the fallback for French-speaking users in other countries. Google's documentation describes this as a specificity hierarchy — more specific annotations take precedence over less specific ones for users who match the specific criteria.
A situation I encounter fairly often: companies that serve the US and UK markets with slightly different English content (different spellings, different product availability, different legal language) but don't have localized content for other English-speaking countries like Australia, Ireland, or South Africa. The right approach is usually to use hreflang="en-us" for the US page, hreflang="en-gb" for the UK page, and hreflang="x-default" pointing to one of them (usually the US version) as the fallback for everyone else. An Australian user would see the x-default version. It's not perfect, but it covers the bases without requiring you to create separate pages for every English-speaking country.
Don't try to cover every possible language-region combination unless you genuinely have distinct content for each. I've seen sites create hreflang annotations for en-au, en-nz, en-ie, en-za, and more — all pointing to the same UK English page. That's unnecessary noise. If the content is the same, there's no need for separate annotations. Just let x-default handle it, or use the broader hreflang="en" without a region code for your general English page. If this is new to you, The Ultimate Guide to Internal Linking for SEO breaks it down step by step.
Does Hreflang Affect Rankings?
This comes up a lot, and the answer is — it depends on what you mean by "affect rankings." Hreflang tags don't directly boost your rankings. Having hreflang annotations won't make your French page rank higher for French keywords than it would without them. What hreflang does is tell Google which version of a page to show in which market. It's a targeting signal, not a ranking signal.
That said, the indirect effects on SEO performance can be significant. Without hreflang, Google might consolidate your US and UK pages as duplicates and only index one of them. With hreflang, Google understands they're distinct versions for different audiences and indexes both. Without hreflang, a user in Germany might land on your English page, immediately bounce because they can't read it, and that poor user experience signal could affect your performance in that market. With hreflang, the German user sees the German page, stays longer, and engages more meaningfully.
Hreflang also helps with consolidating ranking signals across language versions. If your English page has earned lots of backlinks and your French page has earned some French backlinks, hreflang helps Google understand that these are related pages. While Google hasn't confirmed that ranking signals are directly passed between hreflang-connected pages, the practical evidence suggests that Google does consider the relationship. Pages that are properly connected via hreflang seem to perform better in their respective markets than isolated pages with no declared relationship to their counterparts.
If you're running an international site and trying to decide where to invest your limited technical SEO resources, hreflang should probably be near the top of the list. But don't try to boil the ocean — start with your highest-traffic international pages. Identify the pages that drive the most organic traffic and the markets where you have the strongest presence. Get hreflang right on those pages first, validate that everything is working, and then expand to the rest of your site. Incremental, validated implementation beats a massive all-at-once rollout that's full of errors you don't catch for months.
Comments (0)
No comments yet. Be the first to share your thoughts!
Leave a Comment