International SEO and hreflang
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-UKdoesn'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):
| Structure | Example | Advantages and disadvantages |
|---|---|---|
| A separate domain for each country | example.ie, example.de | The clearest signal of which country a site is for. The most expensive to run, and each domain has to build its reputation separately |
| Subdomains | ie.example.com, de.example.com | Easy to host separately. A weaker signal of country on its own |
| Subfolders | example.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 UKhttps://www.example.com/ie/subscriptions, in English for Ireland, with prices in euroshttps://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.
- Each version lists itself, as well as the other versions. In Fernhill's example, the UK page's tags include the UK page.
- 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.
- Addresses must be complete, starting with
https://, such ashttps://www.example.com/ie/subscriptions, not/ie/subscriptions. - Versions can be on different domains, so
example.co.ukandexample.decan list each other. - 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)).
| Value | Meaning | Valid? |
|---|---|---|
en | English, any country | Yes |
en-GB | English for users in the United Kingdom | Yes |
en-UK | Not a valid country code | No. UK isn't the standard code for the United Kingdom |
en-IE | English for users in Ireland | Yes |
ar-AE | Arabic for users in the United Arab Emirates | Yes |
de-CH | German for users in Switzerland | Yes |
fr-BE | French for users in Belgium | Yes |
be | Belarusian (not Belgium) | Yes, but probably not what you meant |
GB | A country on its own | No. "Specifying the region alone is not valid" |
es-419 | Spanish for Latin America, using a United Nations region code | No. Google says codes such as es-419 aren't supported |
zh-Hant | Chinese, written in traditional characters | Yes |
x-default | The page for users who don't match any other version | Yes |
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 ases-419. - Incomplete addresses, such as
/ie/subscriptionsinstead ofhttps://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
- If your site has versions for different countries or languages, check that each one has its own address.
- View the source of each version of an important page, and check its hreflang tags against the rules in this chapter.
- Search your site's code or settings for
en-UK, and replace it withen-GB. - Check that each version's canonical tag points to itself.
- If your site redirects visitors by location, ask your developer to replace it with a banner and a country menu.
- Read your country versions side by side, and add the local details each one is missing.
Further reading
- Tell Google about localized versions of your page(opens in a new tab), Google's hreflang rules, codes and common errors in one place.
- Managing multi-regional and multilingual sites(opens in a new tab), Google's advice on choosing a structure, and why not to redirect by location.
- How Google crawls locale-adaptive pages(opens in a new tab), on why showing different content at one address is risky.
- Does duplicate content hurt SEO and AI search visibility?(opens in a new tab), Bing on how AI systems choose between near-identical and local versions of a page.
- generateMetadata(opens in a new tab), for adding hreflang in Next.js.