What hreflang is for
It tells Google that several URLs are the same page in different languages, so it serves the right one to the right reader and stops treating them as duplicates competing with each other. It is a signal about which version to show. It is not a ranking signal, and no amount of it makes a page rank higher.
Failure one: the missing self-reference
The rule is that every page in a set names every page in the set — itself included. So both pages carry the identical block:
<link rel="alternate" hreflang="en" href="https://example.com/page/" />
<link rel="alternate" hreflang="ar" href="https://example.com/ar/page/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/page/" />The instinct is to have each page point at the others, which reads as the efficient version and is the broken one. If the English page lists only the Arabic URL, the cluster has no reciprocity and Google discards it — not the English half, the whole thing.
It is also why the block is easiest to get right when it is generated rather than written. The same block on every page is a template concern; hand-editing two files to point at each other is where the asymmetry creeps in.
Failure two: a relative href
href="/ar/page/" looks reasonable. It resolves in a browser. It validates against every schema. Google discards it without a word.
This site published 936 relative hreflang hrefs in its sitemap — 312 pages with three alternates each. Search Console reported a number and no indication of which part was wrong. The count went to zero the day they were made absolute, which was the only evidence available that this had been the problem.
And a third, smaller one: the tag itself
The language goes first in lowercase, the region after it in uppercase: en-GB. Not en_GB, not EN-gb. And a region alone is never valid — there is no hreflang="GB", because a country is not a language. x-default is the one exception to the shape, and it is not a language at all.
Where to declare it
Three places will carry a cluster: the head of each page, an HTTP header, or the sitemap. Pick one. Declaring the same set in two places is not redundancy — it is two chances to disagree, and a disagreement invalidates both declarations rather than falling back to the correct one.
The sitemap is usually the cheapest for a large site, because one file changes instead of every page. See sitemaps for a site in two languages for what those entries look like.
hreflang and canonical
They work together and are frequently confused. Each page is canonical to itself and declares the others as alternates. A canonical tag pointing from the Arabic page to the English one collapses the set: you have told Google those are the same page and only one should be indexed, which is the opposite of what hreflang says.
Checking it before you publish
The hreflang generator builds the block and checks the cluster for all of the above, including the self-reference, which it can only do if you tell it the URL the tags are going on. For a page that already exists, paste its source into the meta tag analyser — it runs the same checks on whatever alternates it finds.