You translated your site into Spanish. Both versions are live, both are indexed, and now the wrong one keeps showing up: English pages surfacing for Spanish searches, or the Spanish version of a page outranking the English original for English queries. Nothing is broken in any way your analytics will name, and the fix is a piece of markup most bilingual sites either skip or get subtly wrong.
What hreflang is actually for
hreflang does not decide whether a page ranks. It decides which of several equivalent pages gets shown once one of them has earned a position. That distinction matters, because it sets expectations correctly: adding hreflang to a page nobody was going to see will not make it visible. Fixing hreflang on a page that already ranks, but ranks in the wrong language for the wrong audience, can change the experience immediately.
It also protects you from a quieter problem. Two versions of the same page, one per language, look to a search engine like candidates for the same slot. Without a signal telling it they are alternates of one another, it may treat them as competitors — and pick one, in a way you do not control.
The three rules people get wrong
hreflang is unforgiving in a specific way: it fails silently. There is no error page, no broken layout, nothing in your logs. It either works or it is quietly ignored, so the rules are worth getting exactly right.
- Annotations must be reciprocal. If the English page names the Spanish page as its alternate, the Spanish page must name the English one back. A one-way declaration is discarded — the whole point is mutual confirmation, so an unanswered claim is untrustworthy by design.
- Every page in a set must list every page in the set, including itself. A self-referential hreflang looks redundant and is required. Two-language sites need two entries on each page, not one.
- URLs must be absolute and must be the canonical ones. A relative path, or a URL that then redirects or canonicalises elsewhere, breaks the pairing.
The self-reference rule is the one that catches careful people out, because it is the only part that looks like a mistake when you write it.
Language codes, and when to add a region
Use the plain language code unless you have a real reason not to: en and es. Add a region only when you genuinely publish different content for different countries — es-CL for Chile, es-MX for Mexico — and only when those versions differ in ways a reader would notice, such as currency, legal detail, contact details or vocabulary.
Do not add a region because it feels more precise. If you declare es-CL and someone searches in Spanish from Argentina, you have told the search engine you have nothing specifically for them. Where you serve several Spanish-speaking countries from one Spanish page, plain es is the accurate description, and accuracy is the whole game.
Add x-default for the page you want shown when no declared version matches the user. For a bilingual site this is usually the English version, and it is easy to forget it exists.
The mistake specific to toggle-based bilingual sites
Plenty of small bilingual sites do not have two URLs per page. They have one page holding both languages, with a switch that swaps the visible text in the browser. It is a legitimate way to build a site and it is genuinely simpler to maintain.
It is also invisible to hreflang, and there is no way to annotate your way out of it. hreflang points at URLs. If both languages live at the same URL, there is nothing to point at and nothing to distinguish. A crawler sees one page, in whichever language the markup serves by default, and the other language may as well not exist.
Recognising which model you have is the important step. A toggle site is not a broken hreflang implementation — it is a site where hreflang does not apply, and where the choice is to accept single-language visibility or to split the pages onto separate URLs. That is an architectural decision with real cost, and it should be made deliberately rather than discovered a year later.
Where to put the annotations
Three placements are valid: link elements in the head of each page, HTTP headers, or a sitemap. For most sites the head is simplest, because the markup lives next to the content it describes and is hard to forget when you add a page.
The sitemap approach is worth considering for a large corpus, since it centralises every pairing in one generated file rather than scattering it across thousands of pages — but only if that file is genuinely generated. Maintaining pairings by hand in a sitemap is worse than doing nothing, because it drifts from reality without ever announcing that it has.
HTTP headers exist for non-HTML files, mainly PDFs. Most sites never need them.
How to check it
Do not trust the markup by reading it. Fetch both URLs and confirm four things in order: each page returns a success status, each declares a self-referential annotation, each names the other, and every URL in every annotation is absolute and matches the canonical exactly. Most failures are a mismatch in that last check — a trailing slash, a www that the site redirects away, a stale URL from before a rename.
After that, Search Console will report international targeting issues, but slowly, and it only reports what it has crawled. The direct fetch is the check that tells you today whether you shipped it correctly.
A short checklist
- Two languages means two entries on every page, including the page's own.
- Reciprocal or ignored — every declaration must be answered.
- Absolute, canonical URLs, matching exactly.
- Plain es unless you really publish per-country content.
- Set x-default for the fallback version.
- If both languages share one URL, hreflang cannot help — decide whether to split.
- Verify by fetching both pages, not by reading your template.
hreflang never throws an error. It works, or it is silently ignored, and the only way to tell the difference is to go and look.
Does your business show up when AI answers?
ChatGPT, Claude, Perplexity and Google's AI Overviews are already answering the questions your customers ask. The $49 AI Visibility Scan shows you where you're cited, where you're invisible, and the three changes that move you first — a written report in your inbox within 48 hours. If nothing in it is actionable, you don't pay.
Run the $49 AI Visibility Scan →Share this article
Comments
Leave a comment