A hreflang crawler (Screaming Frog, Sitebulb, Ahrefs) flags “missing return links” — historically called “no return tags” in Google Search Console. Your English page correctly points to its Chinese translation with <link rel="alternate" hreflang="zh" href="...">, but the Chinese page doesn’t link back to the English one. Hreflang is reciprocal by rule: if A says “my zh alternate is B,” then B must say “my en alternate is A.” When the return link is missing, Google treats the whole annotation as unreliable and silently ignores it.
Fastest fix: emit hreflang from one shared layout that lists every language in the cluster (including the current page’s self-reference), using byte-for-byte identical URLs and matching language codes on both sides. One template = guaranteed reciprocity. Details below.
Heads-up (as of June 2026): Google does not report hreflang errors anywhere in Search Console. The old International Targeting report — where “No return tags” used to appear — was deprecated in September 2022 and removed. If an old article tells you to “check International Targeting,” that report is gone. Today you diagnose with the URL Inspection tool (per-URL) or a third-party crawler (whole-site). See Validate it’s fixed below.
The symptom is subtle because nothing errors loudly: the Chinese page ranks for English queries even though a good English version exists, or the wrong-language URL shows in a country’s SERP. The cause is almost always one of seven concrete things.
Which bucket are you in?
| What you observe | Most likely cause | Jump to |
|---|---|---|
grep hreflang on one language returns nothing | That template never emitted hreflang | Cause 1 |
| Tags exist on both sides but crawler still flags it | URL strings don’t match byte-for-byte | Cause 2 |
One side says zh, the other zh-CN | Language-code mismatch (or _ instead of -) | Cause 3 |
Return-side URL is a 404, 301, or noindex | Return link points to a non-200 / non-indexable page | Cause 4 |
| Both sides have tags but one self-canonicalizes elsewhere | Cross-language canonical overrides hreflang | Cause 5 |
| Cluster has 3+ languages, only some pair up | Missing self-reference or missing third member | Cause 6 |
| Tags differ between HTML head and sitemap | Two declaration sources disagree | Cause 7 |
Common causes
1. One template emits hreflang, the other forgot
The English layout has hreflang links to every language alternate. The Chinese layout was copy-pasted from a single-language template and never got the hreflang block.
How to spot it: curl -s https://yoursite.com/zh/articles/foo/ | grep -i hreflang. Empty output means the Chinese template emits no hreflang at all, so no return link can exist.
2. Hreflang URLs don’t match the served URL
The EN page declares <link rel="alternate" hreflang="zh" href="https://yoursite.com/zh/articles/foo/">. But the ZH page is actually served at https://yoursite.com/zh/articles/foo (no trailing slash) or https://www.yoursite.com/zh/articles/foo/ (different host). Google compares the round trip as exact strings and can’t close the loop.
How to spot it: compare the alternate URL each side declares against the canonical URL the page is actually served at. Trailing slash, www vs no-www, http vs https — every difference breaks the match.
3. Language-code mismatch
The EN page says hreflang="zh"; the ZH page says hreflang="zh-CN". Google treats zh and zh-CN as different annotations and won’t pair them. A very common variant is using an underscore (zh_CN) instead of a hyphen (zh-CN) — the underscore form is invalid and silently dropped.
How to spot it: grep every hreflang value across the cluster. The language code must be an exact string match on both ends, and must use a hyphen, never an underscore.
4. The return side is a 404, 301, or noindex
The EN page links to ZH, but the ZH page was deleted (404), redirects elsewhere (301/302), or carries <meta name="robots" content="noindex">. A return link to a non-200 or non-indexable page does not count: Google ignores hreflang relationships whose return target is noindexed, and a redirect/404 has no tag to read.
How to spot it: for each hreflang target, run curl -sI https://yoursite.com/zh/articles/foo/ and confirm 200. Then check the page isn’t noindex (grep the head for robots / noindex). Screaming Frog surfaces these under Reports > Hreflang > Non-200 Hreflang URLs and Reports > Hreflang > Noindex Return Links.
5. Canonical points to a different URL
The ZH page has a correct hreflang back to EN, but it also has <link rel="canonical" href="..."> pointing to a third URL. Google resolves canonical first and reads hreflang from the canonical target — which has no return tag. Cross-language canonical (ZH canonicalizing to EN) is the single most common version of this bug.
How to spot it: for each cluster member, check its rel=canonical. It must point to itself. If it points anywhere else, fix canonical before touching hreflang.
6. Self-reference or a cluster member is missing
Every language version must include a hreflang for itself. The EN page needs both hreflang="en" (self) and hreflang="zh" (other). With 3+ languages, each page must list all members. Miss one and that whole sub-pairing fails its return check.
How to spot it: view source and count hreflang entries. The count should equal the number of language versions, including the current page itself.
7. HTML and sitemap hreflang disagree
Some teams put hreflang only in sitemap.xml; others put it in the HTML <head>. If both exist and disagree, Google may read one source and miss return links in the other. Pick one source of truth.
How to spot it: compare the sitemap <xhtml:link> block and the HTML <link rel="alternate"> tags for the same URL. They must match exactly, or one of them should not exist.
Shortest path to fix
Step 1: Pick one declaration method and stick with it
Three valid methods — choose one, never two:
- HTML
<head>tags (most common for content sites) - HTTP response headers (
Link:header — the only option for non-HTML files like PDFs) - XML sitemap
<xhtml:link>blocks
For HTML, every language version must include a hreflang for every language, including itself.
Step 2: Emit hreflang from one shared layout
Build a single helper that takes the current article’s translationKey and emits the full cluster. One template guarantees reciprocity because every page renders the same list:
---
const { translationKey, currentSlug } = Astro.props;
const translations = (await getCollection('articles'))
.filter(a => a.data.translationKey === translationKey);
const SITE = 'https://yoursite.com';
---
{translations.map(t => (
<link rel="alternate" hreflang={t.data.lang}
href={`${SITE}/${t.data.lang}/articles/${t.data.urlSlug}/`} />
))}
<link rel="alternate" hreflang="x-default"
href={`${SITE}/en/articles/${currentSlug}/`} />
Because the list is derived from the cluster (not hand-written per page), every member links to every other member and to itself.
Step 3: Match URL formats exactly
Lock one canonical URL form — protocol, host with/without www, trailing slash or not — and use it everywhere:
# compare what each page declares
for url in \
"https://yoursite.com/en/articles/foo/" \
"https://yoursite.com/zh/articles/foo/"; do
echo "== $url"
curl -s "$url" | grep -oE 'hreflang="[^"]+" href="[^"]+"'
done
Confirm every declared hreflang URL is exactly the canonical URL of that language version.
Step 4: Use consistent language codes
Use ISO 639-1 two-letter codes (en, zh), optionally with an ISO 3166-1 region (en-US, zh-CN). Pick one style and never mix. Always use a hyphen, never an underscore. For Chinese, prefer zh-Hans (Simplified) and zh-Hant (Traditional) when you need to distinguish scripts; otherwise plain zh is fine.
Step 5: Fix canonicals first
Each cluster member must rel=canonical to itself, never to another language version:
<!-- WRONG: ZH page canonical to EN -->
<link rel="canonical" href="https://yoursite.com/en/articles/foo/">
<!-- RIGHT: ZH page canonical to itself -->
<link rel="canonical" href="https://yoursite.com/zh/articles/foo/">
If canonical and hreflang disagree, canonical wins and your hreflang is wasted. Fix this before re-checking the return tags.
Step 6: Validate cluster integrity in CI
Catch missing members before they ship:
// scripts/check-hreflang.mjs
import { glob } from 'glob';
const errors = [];
const files = glob.sync('src/content/articles/**/*.mdx');
const byKey = {};
for (const f of files) {
const fm = parseFrontmatter(f); // your frontmatter parser
(byKey[fm.translationKey] ??= []).push({ file: f, lang: fm.lang });
}
for (const [key, members] of Object.entries(byKey)) {
if (members.length < 2) continue; // single-lang, fine
const langs = new Set(members.map(m => m.lang));
// expect exactly one file per declared lang, and >= 2 langs
if (langs.size !== members.length) {
errors.push(`Duplicate lang in cluster ${key}`);
}
}
if (errors.length) { console.error(errors.join('\n')); process.exit(1); }
This won’t render HTML, but it guarantees every translationKey cluster is complete and unambiguous, which is the precondition for a correct shared-layout emit.
Step 7: Validate it’s fixed {#validate-its-fixed}
Because Search Console no longer reports hreflang (International Targeting was removed in 2022), confirm the fix two ways:
- Per-URL — URL Inspection tool. In Search Console, paste the URL, open the live test, and check that Google sees both alternates. Run it on both language versions; each should list the other.
- Whole-site — crawler. Run Screaming Frog and read
Reports > Hreflang > Missing Confirmation Links. After your fix, this report should be empty. Also checkNon-200 Hreflang URLsandNoindex Return Linksare clean.
Rankings and any wrong-language SERP results typically settle within 1–2 weeks of the next recrawl. You can nudge a recrawl with “Request Indexing” in URL Inspection for the key pages.
When the warning isn’t your fault
If a translation is published on a delay — EN goes live today, ZH next week — a crawler will flag a missing return link during the gap. That’s expected and clears itself once both sides exist. Don’t add a hreflang pointing at a URL that doesn’t return 200 yet.
Easy to misdiagnose as
A pure canonical problem. The two interact: a bad canonical makes correct hreflang ineffective. Always fix “canonical points to itself” first, then re-check the return tags — otherwise you’ll keep editing hreflang that Google never reads.
Prevention
- Emit hreflang from one shared layout helper; never hand-write it per page.
- CI check that every
translationKeycluster is complete across language files. - One canonical URL format site-wide (protocol, host, trailing slash).
- Canonical points to self on every language version.
- Re-crawl with Screaming Frog or Sitebulb quarterly and clear
Missing Confirmation Links.
FAQ
- Does Google Search Console still show “No return tags”? No. The International Targeting report that surfaced it was deprecated in September 2022 and removed. Google still uses hreflang; it just no longer reports problems with it. Validate with URL Inspection or a crawler instead.
- Do I need
x-default? Recommended, not required. It tells Google which URL to serve when no language matches — useful for a global landing page or language selector. Omitting it doesn’t cause the “no return tag” problem. - Can hreflang point to a different domain? Yes.
hreflang="ja"can point toyoursite.jpif your Japanese site lives there. The same reciprocity rule applies: the.jppage must point back. - Why does a
noindexreturn page break the cluster? A return link to a noindexed (or 404/redirected) page isn’t a valid confirmation, so Google ignores the whole pairing. Every page in a hreflang set must return200and be indexable. - How long until the warning clears? Within 1–2 weeks of recrawl once both sides are correct. Use “Request Indexing” in URL Inspection to speed up the key URLs.
Related
- Hreflang Warning in Search Console
- Hreflang x-default Confusion in Bilingual Sites
- Canonical Misconfigured
- Duplicate without User-Selected Canonical
- Alternate Page with Canonical
- Bilingual Pages Drift Apart
- Mobile-First Switch Indexing Drop
- Query-Parameter URLs Creating Duplicates
- Pages Dropped from Index
- Internal Links Not Discovered by Google
Tags: #SEO #Troubleshooting #Indexing #Search Console #hreflang #international