---
title: "Hreflang mistakes that break international targeting - Serpwise"
description: "Missing return tags, mismatched language codes, region-without-language, and other hreflang implementation bugs that quietly break geo-targeted indexing."
url: "https://serpwise.ai/learn/hreflang-mistakes/"
source: "https://serpwise.ai/learn/hreflang-mistakes/"
---
[← Back to Learn](/learn/)

International & Mobile Warning

# Hreflang mistakes that break international targeting

Missing return tags, mismatched language codes, region-without-language, and other hreflang implementation bugs that quietly break geo-targeted indexing.

Hreflang helps Google choose the appropriate language or regional version of equivalent pages. When the cluster is incomplete or invalid, Google may ignore those annotations and choose a version from its other signals.

## Why it matters

Hreflang is a clustering signal. If the cluster is malformed, Google doesn’t penalize - it ignores the hreflang entirely and picks a canonical version on its own. You end up with `example.com/de/` competing against `example.com/` for German users instead of being served in their place.

The four mistakes that account for most broken hreflang clusters:

1. **Missing return tags.** Page A references page B; page B doesn’t reference page A. Google requires bidirectional confirmation.
2. **Wrong language codes.** ISO 639-1 only. `en-uk` is invalid (it’s `en-gb`). `cn` is invalid (it’s `zh`).
3. **Region without language.** Hreflang values must always include a language. `hreflang="us"` is invalid; use `hreflang="en-us"`.
4. **Pointing to non-200 URLs.** Targets that redirect, 404, or canonicalize elsewhere are silently dropped from the cluster.

## How to detect it

Inspect the raw HTML or response headers - not the rendered DOM, since some crawlers don’t execute JS:

```
curl -s https://example.com/de/ | grep -i 'hreflang'
```

Then verify reciprocity. For every URL in the set, every other URL in the set must reference it back, including a self-reference:

```
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="de" href="https://example.com/de/" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/" />
```

The same four tags must appear on the English, German, AND French pages. Each page references the full cluster, including itself.

Search Console no longer provides the old International Targeting report. Validate the rendered HTML or sitemap directly: confirm valid codes, self-references, reciprocal alternates, successful target responses, and matching canonicals across the full cluster.

## The fix

### Universal HTML - in `<head>`

```
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="en-gb" href="https://example.com/uk/" />
<link rel="alternate" hreflang="de" href="https://example.com/de/" />
<link rel="alternate" hreflang="de-at" href="https://example.com/at/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/" />
```

Rules:

- Use ISO 639-1 language codes (`en`, `de`, `fr`, `zh`) and ISO 3166-1 Alpha 2 region codes (`gb`, `us`, `de`, `at`).
- Always pair region with language: `en-gb`, never `gb` alone.
- Include `x-default` for the fallback when no language matches.
- Absolute URLs only.

### HTTP header - for non-HTML resources (PDFs, etc.)

```
Link: <https://example.com/doc-en.pdf>; rel="alternate"; hreflang="en",
      <https://example.com/doc-de.pdf>; rel="alternate"; hreflang="de"
```

### XML sitemap - at scale

For sites with hundreds of localized URLs, the sitemap-based approach scales better than per-page tags:

```
<url>
  <loc>https://example.com/</loc>
  <xhtml:link rel="alternate" hreflang="en" href="https://example.com/" />
  <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/" />
</url>
<url>
  <loc>https://example.com/de/</loc>
  <xhtml:link rel="alternate" hreflang="en" href="https://example.com/" />
  <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/" />
</url>
```

Pick one method per cluster. Mixing tag-based and sitemap-based for the same URLs creates conflicting signals.

### WordPress

WPML and Polylang both emit hreflang automatically once languages are configured. Yoast SEO Multilingual handles reciprocity by reading the translation graph. Verify the output - manual overrides in custom themes are the usual source of broken clusters.

### Next.js (App Router)

```
export async function generateMetadata({ params }: Props): Promise<Metadata> {
	return {
		alternates: {
			languages: {
				en: "https://example.com/",
				de: "https://example.com/de/",
				fr: "https://example.com/fr/",
				"x-default": "https://example.com/",
			},
		},
	};
}
```

## Common pitfalls

- **`en-uk` is wrong.** The country code for the United Kingdom is `gb`, not `uk`. This is the single most common hreflang bug.
- **`zh` vs `zh-cn` vs `zh-tw`.** Use `zh-cn` (Simplified) and `zh-tw` (Traditional) - plain `zh` is ambiguous.
- **Pointing the cluster at canonical URLs that point elsewhere.** If `/de/` has `<link rel="canonical" href="https://example.com/">`, Google drops the German URL from the cluster entirely.
- **Forgetting the self-reference.** Each page in the cluster must reference itself with its own hreflang.
- **Adding hreflang to noindexed pages.** Google ignores hreflang signals from non-indexable URLs.

From diagnosis to deployment

## Find the issue. Ship the fix.

Use Learn to understand the problem, then run Serpwise against your own site to see what can be approved and deployed.

[Run free audit](/audit/) [Book a demo](/demo/)