Technical SEO MasteryInternational SEO and structured data · Lesson 11 of 18
hreflang and international SEO
Video lecture
hreflang and international SEO
The narrated lecture is in production
Every chapter is scripted and ready. Browse the chapters and read the full transcript now — the video will appear here when it’s published.
Chapters
Transcript of the narration, chapter by chapter.
0:00 hreflang and international SEO
If you serve customers in more than one country or language, hreflang is probably broken somewhere on your site. That isn't cynicism. It's what audits find again and again, because the rules are strict and CMSs get them subtly wrong. In this lecture you'll learn how to choose a site structure, the hreflang syntax, the rules that break most implementations, and a script that checks reciprocity, codes and targets across thousands of pages.
0:32 Two decisions
International SEO has two separate decisions. Structure: where each version lives. And annotation: how you tell search engines which version is for whom. For structure, you can use country-code domains like dot a e or dot p k, which give clear country signals but mean separate domains to maintain. Subdirectories like slash en-g b or slash ar-s a consolidate authority and are simpler to run. Subdomains work somewhat like separate sites. And parameters are not recommended. For most businesses expanding from one site, subdirectories are the pragmatic default.
1:10 Fundamentals
A few fundamentals before any code. Translate genuinely. A regional version where only the currency changes may be treated as a duplicate. Mark the language in HTML, for Arabic with lang equals a r and dir equals r t l. Never auto-redirect by IP without an alternative, because Googlebot crawls mostly from US IP addresses and may never see your local versions; use a dismissible banner suggesting the local version instead. And let users switch versions with crawlable links. Search Console's old country targeting report was retired in twenty twenty-two, so these signals matter more.
1:51 Syntax
The syntax. hreflang tells Google that URLs are equivalents in different languages or regions. The value is an ISO six-three-nine-one language code, optionally followed by an ISO three-one-six-six region code. So en dash g b for English in the United Kingdom, a r dash a e for Arabic in the UAE, u r dash p k for Urdu in Pakistan. Add x-default for the fallback, often a language selector or a global page. And here's the rule that matters most: every version in the set must include the same complete list, including itself.
2:31 Rules that break
Now the rules that break most implementations. Return links: if page A lists B, B must list A, or the annotation may be ignored. Self-reference: each page includes itself. Canonical alignment: hreflang must point to canonical URLs that return two hundred, and each language version should self-canonicalise; never canonicalise the Arabic page to the English one. Valid codes: e n dash u k is invalid, because the UK's code is g b, and a region alone is invalid. And consistency: use one method, HTML tags, HTTP headers or sitemaps, not a mix.
3:11 hreflang in sitemaps
For large sites, hreflang in XML sitemaps keeps HTML lighter and is easier to generate centrally. Each URL block lists alternate links for every version, including itself, using the xhtml namespace. Repeat a block for each version with the full set. It's the same rules, just in a different place. And don't put hreflang in both HTML and sitemaps unless you're absolutely sure they agree.
3:39 Hands-on: reciprocity checker
Hands-on. The lesson text has a pandas script that reads your crawler's hreflang export: source, language value, target, plus status and canonical for each page. It flags invalid codes, the dash u k mistake, missing return links, targets that aren't two hundred, and targets that aren't canonical. It also counts pages missing a self-referencing annotation, and writes everything flagged to a CSV. On a site with thousands of pages and four markets, this takes minutes, not days.
4:12 Example 1: UAE users see UK prices (illustrative)
Worked example one, with illustrative details. A SaaS company runs slash en, slash en-g b and slash a r. UAE users see the UK page with prices in pounds. The audit shows the Arabic pages canonicalise to the English pages, a CMS default, so Google drops them from the hreflang cluster. Fixes: self-canonicals, new en-a e pages with prices in dirhams where the business genuinely serves the UAE, a complete reciprocal set, and x-default pointing to a selector page.
4:46 Example 2: Arabic and English in KSA (illustrative)
Worked example two, also illustrative. A Riyadh B2B software company runs en-s a and a r-s a plus a global English site. Arabic pages rank poorly, and English pages show to Arabic searchers. The checker finds Arabic pages listing English but not themselves, and an x-default pointing at a URL that redirects. Fixes: complete self-referencing sets, x-default to the final global URL, correct lang and dir attributes, and genuinely localised Arabic copy for key pages. Then they filter Search Console Performance by country and watch which version earns impressions.
5:25 Verify
How do you verify? Crawl all language versions with hreflang extraction and run the checker. Check coverage: does every version of a page exist? Missing translations should be left out of the set, not pointed at another language. In Search Console, filter Performance by country and see which URL version gets impressions in each market. And search from the target market, using a VPN or a localisation tool, for branded and key queries.
5:57 Watch me do it: four-market hreflang check
Watch me do it. I'll check hreflang for a site with four markets. Step one: I crawl all four language folders with hreflang extraction on, and export the annotations and the internal HTML report. Step two: I run the reciprocity checker. It prints: invalid codes, zero. The uk mistake, six hundred and twelve. No return link, one thousand and forty. Target not two hundred, thirty-eight. Target not canonical, nine hundred. And four hundred pages missing self-reference. Step three: I open examples. The six hundred and twelve are all en dash uk on the UK folder; an easy fix to en dash gb. The missing return links are all on the Arabic folder, which lists English but not itself or the other markets. The non-canonical targets point to URLs with a trailing slash difference. Step four: I check Search Console Performance filtered by country, United Arab Emirates. The English UK URLs earn most of the impressions there. That's the business impact. Step five: I write one template ticket for the Arabic set, one for the code, and one for trailing-slash consistency. After release, I re-run the checker, and set a reminder to check country-level impressions in six weeks.
7:23 Mistakes and measures
Common mistakes. Using hreflang to target countries you don't actually serve with distinct content. Relying on hreflang to fix poor translations. And forgetting that hreflang is a hint; strong local relevance signals like currency, addresses, local phone numbers and local links still matter. Measure success with the number of hreflang errors going to zero, and the right URL version earning impressions in each country.
7:51 Recap and try this now
Recap. Choose a structure, usually subdirectories. Implement complete, reciprocal, self-referencing sets that point to canonical two-hundred URLs with valid codes, using one method. Verify with a checker and with Search Console by country. Try this now. Export hreflang from your crawler, run the checker, and fix the single most common issue it reports across your templates.
Two separate decisions
International SEO has two layers: site structure (where each version lives) and annotation (how you tell search engines which version is for whom).
Choosing a structure
| Structure | Example | Pros | Cons |
|---|---|---|---|
| ccTLD | example.ae, example.pk | Clear country signal, local trust | Separate domains to build and maintain |
| Subdirectory | example.com/en-gb/, example.com/ar-sa/ | Consolidated authority, simpler ops | Weaker country signal alone |
| Subdomain | uk.example.com | Can host separately | Operates somewhat like a separate site |
| Parameters | example.com?lang=ar | Easy to build | Not recommended |
For most businesses expanding from one site, subdirectories are the pragmatic default. Search Console's old International Targeting (country targeting) report was retired in 2022, so geotargeting now relies on the ccTLD, hreflang, and local signals such as currency, addresses, language and local links.
Language and locale fundamentals
- Translate content genuinely. Machine translation without review risks low quality; a region version with only currency changed may be seen as duplicate.
- Mark the language in HTML:
html lang="ar" dir="rtl"for Arabic. - Never auto-redirect by IP without an alternative. Googlebot crawls mostly from US IP addresses, so IP redirects can hide your local versions. Use a dismissible banner suggesting the local version instead.
- Let users switch versions with crawlable links.
hreflang syntax
hreflang tells Google that URLs are equivalents in different languages or regions, so it can show the right one. Values are an ISO 639-1 language code, optionally followed by an ISO 3166-1 alpha-2 region code.
<link rel="alternate" hreflang="en-gb" href="https://www.example.com/en-gb/pricing/">
<link rel="alternate" hreflang="en-ae" href="https://www.example.com/en-ae/pricing/">
<link rel="alternate" hreflang="ar-ae" href="https://www.example.com/ar-ae/pricing/">
<link rel="alternate" hreflang="ar-sa" href="https://www.example.com/ar-sa/pricing/">
<link rel="alternate" hreflang="ur-pk" href="https://www.example.com/ur-pk/pricing/">
<link rel="alternate" hreflang="en" href="https://www.example.com/en/pricing/">
<link rel="alternate" hreflang="x-default" href="https://www.example.com/pricing/">Every version in the set must include this same complete list, including itself.
The rules that break most implementations
- Return links (reciprocity). If page A lists B, B must list A. Unconfirmed annotations may be ignored.
- Self-reference. Each page includes itself.
- Canonical alignment. hreflang URLs must be the canonical versions that return 200. Pointing to redirected or non-canonical URLs breaks the set. Each language version should self-canonicalise — never canonicalise
/ar-ae/to/en/. - Valid codes.
en-ukis invalid (the region code isgb). A region alone (hreflang="gb") is invalid. Language comes first. - x-default for the fallback version (often a language selector or global English page).
- Consistency across methods. Use one method: HTML
linktags, HTTPLinkheaders (for PDFs), or XML sitemaps. Mixing them invites conflicts.
hreflang in XML sitemaps
For large sites, sitemaps keep HTML lighter and are easier to generate centrally:
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://www.example.com/en-gb/pricing/</loc>
<xhtml:link rel="alternate" hreflang="en-gb" href="https://www.example.com/en-gb/pricing/"/>
<xhtml:link rel="alternate" hreflang="ar-ae" href="https://www.example.com/ar-ae/pricing/"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/pricing/"/>
</url>
<!-- repeat a url block for each version, with the full set -->
</urlset>hreflang audit procedure
- Crawl all language versions with hreflang extraction.
- Check for: missing return links, non-200 or non-canonical targets, invalid codes, missing self-reference, missing x-default, and pages whose canonical conflicts with hreflang.
- Check coverage: does every version of a page exist? Missing translations should be omitted from the set, not pointed at another language.
- In Search Console, filter Performance by country and check which URL version is getting impressions in each market.
- Search from the target market (VPN or a SERP localisation tool) for branded and key queries.
Worked example 1: UAE users seeing UK prices
A SaaS company runs /en/, /en-gb/, /ar/. UAE users see the UK page with GBP pricing. Audit shows /ar/ pages canonicalise to /en/ (a CMS default), so Google drops them from the hreflang cluster. Fixes: self-canonicals, add en-ae pages with AED pricing where the business actually serves the UAE, a complete reciprocal set, and x-default pointing to a selector page.
Hands-on: an hreflang reciprocity checker
Export from your crawler a CSV of hreflang annotations: one row per (source URL, hreflang value, target URL), plus each URL's status and canonical. Then:
import pandas as pd, re
h = pd.read_csv("hreflang.csv") # columns: source, lang, target
pages = pd.read_csv("internal_html.csv").rename(columns={"Address": "url", "Status Code": "status",
"Canonical Link Element 1": "canonical"})
status = dict(zip(pages.url, pages.status)); canon = dict(zip(pages.url, pages.canonical))
VALID = re.compile(r"^(x-default|[a-z]{2,3}(-[a-z]{4})?(-([a-z]{2}|\d{3}))?)$", re.I)
pairs = set(zip(h.source, h.target))
h["invalid_code"] = ~h.lang.str.match(VALID)
h["uk_mistake"] = h.lang.str.lower().str.endswith("-uk")
h["no_return_link"] = [(t, s) not in pairs for s, t in zip(h.source, h.target)]
h["target_not_200"] = h.target.map(status).ne(200)
h["target_not_canonical"] = h.target.map(canon).notna() & h.target.map(canon).ne(h.target)
self_ref = h[h.source == h.target].source.unique()
missing_self = set(h.source.unique()) - set(self_ref)
issues = ["invalid_code", "uk_mistake", "no_return_link", "target_not_200", "target_not_canonical"]
print(h[issues].sum()); print(len(missing_self), "pages missing a self-referencing hreflang")
h[h[issues].any(axis=1)].to_csv("hreflang_issues.csv", index=False)(-uk passes a generic format check but is invalid for the United Kingdom — the ISO 3166-1 code is gb — hence the separate flag.)
Worked example 2: Arabic and English in Saudi Arabia
A Riyadh B2B software company (illustrative) runs /en-sa/ and /ar-sa/ plus a global /en/. Arabic pages rank poorly and English pages show to Arabic searchers. The checker finds ar pages listing en-sa but not themselves, and an x-default pointing at a URL that redirects. Fixes: complete self-referencing sets on both language versions, x-default pointing to the final global URL, html lang="ar" dir="rtl" on Arabic templates, and genuinely localised Arabic copy (not machine translation) for key pages. In Search Console they then filter Performance by country = Saudi Arabia and watch which URL version earns impressions.
Common mistakes
- Using hreflang to target countries you do not actually serve with distinct content.
- Relying on hreflang to fix poor translations.
- Forgetting that hreflang is a hint; strong local relevance signals still matter.
Key takeaways
- Pick a structure (ccTLD, subdirectory, subdomain) first; subdirectories are a pragmatic default.
- hreflang values use ISO 639-1 language plus optional ISO 3166-1 region (en-gb, not en-uk).
- Sets must be complete, self-referencing, reciprocal and point only at canonical 200 URLs.
- Do not force IP-based redirects; Googlebot mostly crawls from US IPs.
Check your understanding
Quick questions to lock in the lesson. They don’t count towards your certificate.
Put it into practice
Write a complete hreflang set (HTML tags) for a page available in English (UK), English (UAE), Arabic (Saudi Arabia) and Urdu (Pakistan), plus x-default.
Enrol for free to save your progress
Reading is always free. Enrol to keep your place, take the final assessment and earn a verifiable certificate.