Hreflang and International SEO: Syntax, Reciprocity, and x-default
Hreflang has three non-negotiable rules: return tags must be reciprocal, every version self-references, and URLs are absolute. Learn the syntax and the common errors.
Hreflang tells Google which language and region version of a page to show to which user. It rests on three non-negotiable rules: return tags must be reciprocal (if X points to Y, Y must point back to X), every version must list itself and all its siblings, and every URL must be absolute and fully qualified. Break any one and Google ignores the cluster. The rest is choosing valid codes and putting the tags in the right place.
What hreflang does and where it sits in the stack
Hreflang is an annotation that maps equivalent pages across languages and regions. It does not change rankings on its own; it swaps the displayed URL so a German user sees your German page and a UK user sees your en-GB page. It is one signal among several. Google's geotargeting priority runs: ccTLD, then hreflang, then server IP, then on-page locale cues (address, phone, currency, language), then local links and Google Business Profile. Google ignores geotargeting meta tags entirely.
Your URL structure choice sets the foundation. From strongest geo signal to weakest: a country-code TLD (example.de), a subdomain (de.example.com), a subdirectory (example.com/de/, the low-maintenance default most sites should use), and URL parameters (?loc=de, not recommended). Whatever you pick, do not auto-redirect or swap content by IP address — Googlebot crawls mostly from the United States and may never see your regional variants. Serve distinct URLs, annotate them with hreflang, and offer a user-selectable language switcher instead.
Hreflang syntax and language-region codes
Each alternate is declared with a rel="alternate" link carrying an hreflang value:
<link rel="alternate" hreflang="en-gb" href="https://en-gb.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/" />
The hreflang value is a language code, optionally followed by a region code:
- Language uses ISO 639-1:
en,de,fr,zh. - Region is optional and uses ISO 3166-1 Alpha-2:
GB,US,CH.
Valid values: de, en-GB, de-CH, zh-Hant. Invalid values are a leading cause of ignored tags: a region alone (GB with no language), or non-standard inventions like es-419, EU, or UK (the correct code for the United Kingdom is GB). Crawlinx flags malformed values as hreflang.invalid_code.
Language targets a language regardless of country; a language-region pair targets speakers of that language in that specific country. Use de when the German page serves all German speakers; use de-CH only when you have a distinct Swiss-German variant.
Return-tag reciprocity
This is the rule that breaks most often. Hreflang annotations must be bidirectional: if your English page points to your German page, the German page must point back to the English page. Google treats the cluster as a set of mutual claims, and a one-way claim is untrustworthy — if page A says "my German equivalent is B" but B never confirms it, Google discards the annotation. Every page in the cluster must reference every other page in the cluster, including itself. Missing return tags are flagged as hreflang.no_return.
Self-referencing tags
Every version must list itself among its alternates. The English page includes an hreflang="en" entry pointing at the English page, the German page includes an hreflang="de" entry pointing at itself, and so on. A cluster where pages list their siblings but omit their own entry is incomplete and unreliable, because self-reference is what anchors each page's own language claim. Crawlinx flags the omission as hreflang.missing_self.
x-default
The x-default value names the fallback page for users whose language or region does not match any listed alternate — typically a language-selector page or your primary global version. It is not strictly required, but omitting it means users outside your defined set get whichever version Google guesses, rather than the landing page you chose. Declaring an explicit x-default is a small, reliable improvement for genuinely international sites. Crawlinx flags a cluster without one as hreflang.x_default_missing.
Hreflang in the head versus the sitemap
You can declare hreflang three ways, and you pick one — do not mix methods for the same cluster:
- HTML
<link>tags in the<head>. Simple and visible, but every page carries the full set, so a 30-locale cluster means 30 links on every page — heavy on large sites. - HTTP
Linkheader. The only option for non-HTML files such as PDFs. - XML sitemap using
xhtml:linkentries (declarexmlns:xhtml). This keeps the annotations out of the page body and scales better across many locales, which is why large multilingual sites usually prefer it.
All three carry the same meaning; the sitemap approach simply moves the weight off the page. Whichever you choose, the reciprocity and self-reference rules apply identically.
Common errors
- Missing return tags — the top failure; the whole cluster is discarded (
hreflang.no_return). - Region-only or invented codes —
GBalone,es-419,EU,UK(hreflang.invalid_code). - Relative URLs — hreflang requires absolute, fully-qualified URLs.
- Pointing at non-canonical URLs — hreflang alternates should target the canonical version of each page; a mismatch between your hreflang targets and your canonicals sends conflicting signals. See our canonical tags guide.
- Missing
langattribute — the page's<html lang="…">should match its hreflang language; a missing or mismatchedlangundercuts the signal, flagged asi18n.lang_missing. - Malformed HTML around the tags — invalid markup can silently break hreflang parsing, so validate the head.
If your alternates live in a sitemap, keep that sitemap reachable — a robots.txt disallow on the sitemap or on locale directories can strand the annotations; see the robots.txt guide.
How Crawlinx detects hreflang problems
Crawlinx builds the hreflang graph across your crawled pages and flags broken reciprocity (hreflang.no_return), invalid language or region codes (hreflang.invalid_code), clusters missing the self-reference (hreflang.missing_self), a missing x-default (hreflang.x_default_missing), and pages lacking a matching lang attribute (i18n.lang_missing).
Takeaway
Hreflang works only when the graph is complete and honest: every page names itself and every sibling, every claim is returned, every URL is absolute, and every code is valid. Add an x-default for the users you did not target, keep hreflang and canonical in agreement, and on large sites move the annotations into the sitemap to keep pages light.
Audit your own site — free
77 checks, internal PageRank, render-diff. No signup, results in ~30s.