# Document does not have a valid hreflang: what it means and how to fix it

**Audit ID:** `hreflang` · **Category:** SEO

<!--QA-->
> **Quick answer:** Lighthouse fails this audit when hreflang tags are missing, malformed, or point at URLs that do not exist. Fix it by adding one hreflang link per language variant in <head>, including a self-referencing entry and an x-default fallback. This tells Google which language version to serve in international results.
<!--/QA-->

Lighthouse fails this audit when your page either has no `hreflang` annotations and serves content that should target multiple languages, or has `hreflang` annotations that are malformed, point at the wrong URLs, or use invalid language codes. The `hreflang` attribute tells Google which language and region each version of a page targets, so it can serve the right version to the right searcher.

## TL;DR

- **What:** Missing, malformed, or broken `hreflang` annotations.
- **Why it matters:** Without valid `hreflang`, Google may show the wrong language version to international users, or treat your translations as duplicates of each other.
- **Fix:** Add one `<link rel="alternate" hreflang="...">` per language variant in `<head>`, include a self-reference and `x-default`, use ISO codes with hyphens not underscores, and make sure every alternate links back to you.

## What does the hreflang audit check?

Lighthouse verifies that any `hreflang` annotations on the page are syntactically valid: the language code matches the ISO 639-1 format (`en`, `de`, `fr`, optionally `en-US`, `en-GB`), the target URL is absolute, and the value is not empty. It does NOT verify that return links exist on the alternate URLs or that the URLs return 200. Those checks fall on you. Google's Search Console reports both.

The audit also does not require you to have `hreflang` if your site is genuinely monolingual. A site that ships only English content does not need `hreflang` at all and will pass the audit without any.

## Do I need hreflang?

Yes, if any of these apply:

- Same content published in more than one language (`/en/page`, `/de/page`)
- Same language for multiple regions (`/en-US/`, `/en-GB/`, `/en-AU/`)
- Country-specific subdomains (`us.example.com`, `de.example.com`)
- Currency, shipping, or legal differences between regional variants

No, if:

- Your site is one language for one audience
- You have one global English page and accept that international users see it
- Your different-language pages are at completely different URLs that you are happy to treat as unrelated

The audit only triggers when Lighthouse detects existing `hreflang` annotations and finds them broken, OR when other signals suggest you need them. For a truly monolingual site with no `hreflang`, this audit passes.

## How do I add valid hreflang annotations?

The cleanest pattern is `<link>` tags in `<head>`. For a page that exists in English, German, and French:

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

Five rules that make the set actually work:

- **Self-reference.** The English page must list itself in its own set, not just the German and French alternates.
- **Absolute URLs.** Use the full `https://` URL on every alternate, never `/de/page`.
- **One per language or language-region.** No duplicates.
- **`x-default` for the fallback.** When no other `hreflang` matches the user's locale, Google serves the `x-default` URL. Usually point this at your English page.
- **Reciprocal.** Every URL listed as an alternate must include the original in its own `<head>`. One-sided sets are ignored.

The same set goes in `<head>` of every variant (English, German, and French each ship the same four `<link>` tags pointing at the same URLs). Easy to mess up at scale; consider generating it from a config rather than hand-editing each template.

## What language codes are valid?

Use **ISO 639-1** for the language and optionally **ISO 3166-1 alpha-2** for the region, separated by a **hyphen** (not an underscore):

- Valid: `en`, `de`, `fr`, `en-US`, `en-GB`, `pt-BR`, `zh-Hans` (script-only is allowed)
- Invalid: `en_US` (underscore, common copy-paste error from locale identifiers), `EN` (uppercase language), `en-USA` (3-letter region code), `english`

Lighthouse will accept most syntactically-correct combinations even if they make no sense semantically (`hreflang="xx"` will pass syntactic checks). Google itself only honors the ones it recognizes, so stick to real locale codes.

## What is x-default and do I need it?

`x-default` tells Google which page to serve when no other `hreflang` value matches the user's browser locale. A French Canadian user with no `fr-CA` alternate will hit the `x-default` page.

Set `x-default` to whichever variant is your best generic fallback. For most sites that is the English version. For sites where French is the lingua franca (parts of West Africa, Quebec-leaning audiences), it may be French.

`x-default` is not strictly required by the audit, but Google strongly recommends it. Without it, users with unrecognized locales get whatever Google guesses, which is often the country-domain default rather than the language-best match.

## What are common hreflang mistakes?

- **Missing return links.** `/en/page` points to `/de/page` but `/de/page` does not list `/en/page`. Google ignores one-sided sets entirely.
- **Self-reference missing.** The page lists every alternate except itself. Half the value of the set evaporates.
- **Underscores instead of hyphens.** `hreflang="en_US"` is invalid. Use `en-US`.
- **Relative URLs.** `href="/de/page"` breaks when crawled. Always absolute.
- **`hreflang` pointing at a redirect.** If `/de/page` 301s to `/de/page/`, Google may drop the annotation.
- **`hreflang` pointing at a `noindex` URL.** Same outcome: ignored.
- **Mixing locations.** `<link>` tags in `<head>` AND alternate entries in the XML sitemap for the same page. Pick one location per site.
- **Stale `hreflang` after a URL change.** Renaming `/en/page` to `/en/new-page` without updating every reciprocal `hreflang` set leaves the entire cluster broken.

## How do I verify hreflang is working?

Three checks in increasing order of confidence:

1. **View source** on the page and confirm the `<link rel="alternate" hreflang="...">` tags are present in `<head>` with absolute URLs.
2. **Google Search Console** → International Targeting report (under Legacy tools and reports). Shows hreflang errors detected during crawl, including return-link failures.
3. **Crawl the site** with Screaming Frog, Sitebulb, or Ahrefs. They flag missing return links, invalid codes, and URLs that 404 or redirect. This is the only check that catches reciprocal-link failures across many pages at scale.

## hreflang for very large sites

If you have hundreds of pages with multiple language variants, hand-maintaining `<link>` tags in every template gets brittle fast. Two scalable options:

- **XML sitemap with `xhtml:link` entries.** Each `<url>` in the sitemap lists every language variant as an `xhtml:link`. Google reads `hreflang` from the sitemap. Scales to millions of URLs.
- **HTTP Link header.** Useful for non-HTML resources (PDFs, downloads). Less common.

Use one location consistently across the site. Mixing `<head>` tags and sitemap entries for the same page does not double up; it is more likely to introduce conflicts.

## Related audits

- [Document does not have a valid rel=canonical](/audits/canonical-tag), the canonical and hreflang signals must agree.
- [Document does not have a title element](/audits/document-title), the title needs to match the language declared by hreflang.
- [Document does not have a meta description](/audits/meta-description), translate descriptions alongside the body content for the right language to surface in SERPs.
