International SEO and hreflang

Updated 16 October 2026 · 12 min read

Andy Bright

Director of Product and Technology

On this page

International SEO means setting up a website so that search engines show each visitor the version meant for their country or language. Fernhill Coffee has sold only in the UK until now. It's starting to deliver to Ireland and Germany, so it needs a version of its site for Irish customers, with prices in euros and Irish delivery times, and a version in German.

When someone in Dublin searches for "coffee subscription", Fernhill wants Google to show the Irish page. When someone in Berlin searches for "Kaffee-Abo", it wants the German page. A tag called hreflang is how a website tells search engines which version of a page is for which language and country.

The rules for hreflang are short, but mistakes are easy to make and hard to spot, because nothing looks wrong on the page. This chapter explains:

  • how to give each version of your site its own address
  • when you need hreflang
  • how hreflang works, using Fernhill's subscription page
  • the language and country codes, including why en-UK doesn't work
  • the different ways to add hreflang to a site
  • how hreflang and canonical tags fit together
  • the most common mistakes
  • how local versions affect AI answers

Give every version its own address

Each language or country version needs its own URL. Some sites instead show different content at the same address depending on where the visitor is, or on their browser's language setting. Google recommends against this⁠(opens in a new tab), because its crawler can't reliably see the other versions.

Googlebot usually crawls from IP addresses in the USA (an IP address is the number that identifies a computer on the internet). It also doesn't tell websites which language it prefers, which browsers do using a setting called the Accept-Language header. So a page that changes its content by location or language usually shows Googlebot only one version (Google on locale-adaptive pages⁠(opens in a new tab)).

If Fernhill's subscription page showed German to visitors in Germany and English to everyone else, Googlebot would arrive from the USA, get the English page, and might never see the German one. The German page would never appear in German search results.

Choosing a structure

Google describes three common ways to organise the addresses⁠(opens in a new tab):

StructureExampleAdvantages and disadvantages
A separate domain for each countryexample.ie, example.deThe clearest signal of which country a site is for. The most expensive to run, and each domain has to build its reputation separately
Subdomainsie.example.com, de.example.comEasy to host separately. A weaker signal of country on its own
Subfoldersexample.com/ie/, example.com/de/The cheapest to run, and every version shares the main domain's reputation. All versions are on the same server

All three work. For most businesses, subfolders are the simplest to run well. Whichever you choose, use it the same way across the whole site.

Fernhill chooses subfolders. The UK site stays where it is, the Irish version goes in /ie/ and the German version goes in /de/.

The folder name alone doesn't tell Google who a version is for. Google says⁠(opens in a new tab) it doesn't use names like ie or en-gb in a folder or subdomain to work out a page's audience. You have to state it with hreflang.

When you need hreflang

Google recommends hreflang⁠(opens in a new tab) in three situations:

  • your content is fully translated into several languages, like Fernhill's German pages
  • you have similar content in one language with small differences for each country, like Fernhill's UK and Irish pages
  • you translate only the menus and footer, and keep the main content in one language, as many forums do

If your site is in one language for one country, you don't need hreflang.

Translated pages aren't duplicate content. Google says⁠(opens in a new tab) different language versions of a page are only treated as duplicates if the main content hasn't been translated. Fernhill's German page isn't a duplicate of its English one.

How hreflang works

Fernhill now has three versions of its subscription page:

  • https://www.example.com/subscriptions, in English for the UK
  • https://www.example.com/ie/subscriptions, in English for Ireland, with prices in euros
  • https://www.example.com/de/kaffee-abo, in German

Each of the three pages gets the same set of hreflang tags in its <head> section:

<link rel="alternate" hreflang="en-GB" href="https://www.example.com/subscriptions" />
<link rel="alternate" hreflang="en-IE" href="https://www.example.com/ie/subscriptions" />
<link rel="alternate" hreflang="de" href="https://www.example.com/de/kaffee-abo" />
<link rel="alternate" hreflang="x-default" href="https://www.example.com/subscriptions" />

Each line names one version of the page and says who it's for. en-GB means English speakers in the United Kingdom, and en-IE means English speakers in Ireland. de means German speakers in any country. Fernhill has only one German version, so it uses de, which also covers German speakers in Austria and Switzerland. de-DE would mean German speakers in Germany only. x-default names the page for everyone else, which the x-default section explains.

The group of pages that list each other is called an hreflang cluster. A search engine that finds the cluster can show the Irish page to searchers in Ireland, even if the UK page has more links pointing to it.

The rules

These rules come from Google's hreflang documentation⁠(opens in a new tab). They're the brief to give your developer.

  1. Each version lists itself, as well as the other versions. In Fernhill's example, the UK page's tags include the UK page.
  2. Links must go both ways. If the UK page lists the Irish page, the Irish page must list the UK page. In Google's words, "If two pages don't both point to each other, the tags will be ignored." This stops other websites claiming to be a version of yours.
  3. Addresses must be complete, starting with https://, such as https://www.example.com/ie/subscriptions, not /ie/subscriptions.
  4. Versions can be on different domains, so example.co.uk and example.de can list each other.
  5. Choose one method of adding hreflang. Tags in the HTML, HTTP headers and sitemaps all work the same for Google, and using more than one adds work with no benefit in search.

In September 2026 Google updated its documentation⁠(opens in a new tab) to say that you can leave some languages off some pages, and it will still use the pairs of pages that list each other. Listing the full set on every version is still the simplest way to keep the cluster consistent.

hreflang doesn't tell Google what language a page is in. Google works that out from the content⁠(opens in a new tab), and doesn't use hreflang or the HTML lang setting to decide. hreflang only says which pages are versions of each other and who each one is for, so the main content still has to be in the language you've given.

Language and country codes

Each hreflang value starts with a two-letter language code from a standard called ISO 639-1, such as en for English or de for German. It can be followed by a two-letter country code from a standard called ISO 3166-1, such as IE for Ireland. You can also add a code for the writing system, from a standard called ISO 15924, such as Hant for traditional Chinese characters (Google's documentation⁠(opens in a new tab)).

ValueMeaningValid?
enEnglish, any countryYes
en-GBEnglish for users in the United KingdomYes
en-UKNot a valid country codeNo. UK isn't the standard code for the United Kingdom
en-IEEnglish for users in IrelandYes
ar-AEArabic for users in the United Arab EmiratesYes
de-CHGerman for users in SwitzerlandYes
fr-BEFrench for users in BelgiumYes
beBelarusian (not Belgium)Yes, but probably not what you meant
GBA country on its ownNo. "Specifying the region alone is not valid"
es-419Spanish for Latin America, using a United Nations region codeNo. Google says codes such as es-419 aren't supported
zh-HantChinese, written in traditional charactersYes
x-defaultThe page for users who don't match any other versionYes

Codes aren't case-sensitive, so en-gb works too. Writing the country in capitals, as in en-GB, follows the standard and makes the codes easier to read.

x-default

x-default names the page for anyone whose language or country doesn't match any version you list. Fernhill points it at the UK page, so a visitor from France or Spain gets the English UK version.

Google says⁠(opens in a new tab) x-default was designed for language selection pages, where visitors choose their country or language, and works best with them. You can use it on any page, though, such as your main English home page.

If you have more than one English version, Google also suggests⁠(opens in a new tab) tagging one of them with plain en as well, for English speakers in other countries. A page can have more than one hreflang value, so the UK page could be both en-GB and en. This helps when your x-default page is a language selection page, because English speakers elsewhere then get a page with real content. Fernhill's x-default already points to its UK page, so it doesn't need a separate en tag.

Other ways to add hreflang

The HTML tags in Fernhill's example are the most common method. Google requires⁠(opens in a new tab) them to be inside a correctly formed <head> section. It also says not to put hreflang in the same <link> tag as other settings, such as media. Some scripts and badly formed tags can end the <head> early, which pushes the hreflang tags into the page body, where they don't count.

There are two other methods, useful in different situations.

HTTP headers, for PDFs and other files

Files that aren't web pages, such as PDFs, have no <head> section. Instead, the server can send the same information in an HTTP header, a line of information sent alongside the file. If Fernhill offers a printable price list in English and German, the header looks like this:

Link: <https://www.example.com/price-list.pdf>; rel="alternate"; hreflang="en-GB",
      <https://www.example.com/de/preisliste.pdf>; rel="alternate"; hreflang="de"

In your XML sitemap

On large sites, the sitemap is often the easiest place for hreflang, because every cluster is in one file, and the file can be created from the same data as the pages (Google's documentation⁠(opens in a new tab)). The sitemaps chapter explains sitemaps.

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://www.example.com/subscriptions</loc>
    <xhtml:link rel="alternate" hreflang="en-GB" href="https://www.example.com/subscriptions"/>
    <xhtml:link rel="alternate" hreflang="en-IE" href="https://www.example.com/ie/subscriptions"/>
    <xhtml:link rel="alternate" hreflang="de" href="https://www.example.com/de/kaffee-abo"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/subscriptions"/>
  </url>
  <url>
    <loc>https://www.example.com/ie/subscriptions</loc>
    <xhtml:link rel="alternate" hreflang="en-GB" href="https://www.example.com/subscriptions"/>
    <xhtml:link rel="alternate" hreflang="en-IE" href="https://www.example.com/ie/subscriptions"/>
    <xhtml:link rel="alternate" hreflang="de" href="https://www.example.com/de/kaffee-abo"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/subscriptions"/>
  </url>
  <!-- ...and a third <url> entry for the German page, with the same four lines -->
</urlset>

Each address gets its own <url> entry, and each entry lists every version, including itself. Google says⁠(opens in a new tab) the xhtml:link lines don't count towards a sitemap's limit of 50,000 addresses.

In Next.js

This section is for developers. In Next.js, the Metadata API adds hreflang tags through alternates.languages (generateMetadata documentation⁠(opens in a new tab)):

// lib/subscription-versions.ts: one list, shared by all three pages
export const versions = {
  'en-GB': '/subscriptions',
  'en-IE': '/ie/subscriptions',
  de: '/de/kaffee-abo',
}

// app/ie/subscriptions/page.tsx
import { versions } from '@/lib/subscription-versions'

export const metadata = {
  alternates: {
    canonical: versions['en-IE'],
    languages: { ...versions, 'x-default': '/subscriptions' },
  },
}

With metadataBase set in the root layout, Next.js turns these paths into complete addresses. Next.js sitemaps support hreflang in the same way, through alternates.languages in app/sitemap.ts (sitemap documentation⁠(opens in a new tab)).

Set the lang and dir attributes too

Set the lang attribute on the <html> tag of every version, for example <html lang="de"> on Fernhill's German pages. Google doesn't use it to detect language, but browsers, screen readers, translation tools and other crawlers do. For languages written from right to left, such as Arabic and Hebrew, also add dir="rtl" so the page displays correctly.

Make hreflang and canonical tags agree

A canonical tag tells search engines which address is the main version of a page. The indexing chapter explains them. hreflang and canonical tags are the most common source of confusion in international SEO.

Each version should have a canonical tag that points to itself. Fernhill's Irish page should name https://www.example.com/ie/subscriptions as its canonical, not the UK page. If every version pointed its canonical tag at the UK page, Fernhill would be telling search engines that the Irish and German pages are duplicates of the UK page, which cancels out the hreflang tags.

Every address in an hreflang cluster should also be the canonical version and allowed in the index. Don't list addresses that redirect, have a noindex tag, or point their canonical tag somewhere else.

Getting this right helps. Google prefers addresses in hreflang clusters⁠(opens in a new tab) when it chooses which version of a page is the main one, so a consistent cluster helps the right version appear.

Common mistakes

These come from Google's list of common errors⁠(opens in a new tab), plus two more:

  • Missing return links, where one page lists another but the other doesn't list it back. The fix is to create the hreflang tags from one shared list of versions, so every version lists the same set.
  • Wrong codes, such as en-UK, a country code on its own, or unsupported values such as es-419.
  • Incomplete addresses, such as /ie/subscriptions instead of https://www.example.com/ie/subscriptions.
  • Tags outside the <head> section, often because a script or badly formed tag ended it early.
  • Canonical tags that point from one language version to another.
  • Country versions that are almost identical. UK, Irish and Australian English pages that differ only in currency are hard to tell apart, for search engines and AI systems.

Don't redirect visitors by location

Some sites automatically send visitors to a different version based on their location or browser language. Visitors in Germany who open the UK page would be sent to the German page, for example. This can stop search engines reaching some versions at all. Google warns⁠(opens in a new tab) that such redirects "could prevent users (and search engines) from viewing all the versions of your site".

A safer approach is a banner that suggests the local version, such as "Shopping from Germany? Visit our German shop", together with a menu where visitors can choose their country or language.

Local versions and AI answers

AI assistants have the same problem as search engines when a site has several similar versions of a page: they have to pick one to use. Bing's December 2025 article on duplicate content⁠(opens in a new tab) explains that AI systems group near-identical pages together and choose one page to represent the group. It mentions local versions of pages specifically, and recommends making real local differences and using hreflang "to define language and regional targeting".

Make each country version properly local. For Fernhill's Irish page, that means prices in euros including Irish VAT, delivery times and charges for Ireland, Irish contact details, and Irish examples where the page has any. If the Irish page were the UK page with a euro sign, an AI assistant might treat the two as one page, and quote the UK prices to someone in Dublin.

Put those local details in the page's HTML text, not only in a currency switcher built with JavaScript. AI crawlers that don't run JavaScript can't see what a script changes, as the JavaScript chapter explains.

Expect AI answers to differ between countries. AI assistants write each answer for the question and the person asking, so what an assistant tells someone in London can differ from what it tells someone in Dublin or Berlin. Test the questions that matter to you in each country you sell to, rather than assuming one result applies everywhere.

What to do next

  1. If your site has versions for different countries or languages, check that each one has its own address.
  2. View the source of each version of an important page, and check its hreflang tags against the rules in this chapter.
  3. Search your site's code or settings for en-UK, and replace it with en-GB.
  4. Check that each version's canonical tag points to itself.
  5. If your site redirects visitors by location, ask your developer to replace it with a banner and a country menu.
  6. Read your country versions side by side, and add the local details each one is missing.

Further reading