The hreflang attribute tells search engines which version of a page to show users based on their language or region. When it's misconfigured, Google might show French users your English page—or ignore your translations entirely.
Lighthouse flags two specific issues with hreflang:
1. Unexpected Language Code
Invalid or misspelled language codes mean Google can't identify the language.
<!-- Wrong: "uk" is the country code for Ukraine, not United Kingdom -->
<link rel="alternate" hreflang="uk" href="https://example.com/en-gb/" />
<!-- Wrong: invented language code -->
<link rel="alternate" hreflang="esp" href="https://example.com/es/" />
2. Relative href Value
The href must be an absolute URL. Relative URLs are rejected.
<!-- Wrong: relative URL -->
<link rel="alternate" hreflang="es" href="/es/" />
<!-- Right: absolute URL -->
<link rel="alternate" hreflang="es" href="https://example.com/es/" />
These mistakes are common because hreflang has strict syntax requirements that aren't obvious.
hreflang in the HTMLhttps:// or http://You can also check the response headers for HTTP header-based hreflang:
Link: headersRun a Lighthouse SEO audit. Look for "Document doesn't have a valid hreflang" which shows each failing element with the specific error (unexpected language or relative URL).
Language codes must follow ISO 639-1 (two-letter codes) or BCP 47 format.
<!-- Valid language codes -->
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="es" href="https://example.com/es/" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/" />
<link rel="alternate" hreflang="zh" href="https://example.com/zh/" />
<!-- Valid language-region codes -->
<link rel="alternate" hreflang="en-US" href="https://example.com/en-us/" />
<link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/" />
<link rel="alternate" hreflang="pt-BR" href="https://example.com/pt-br/" />
<link rel="alternate" hreflang="zh-TW" href="https://example.com/zh-tw/" />
Common mistakes to avoid:
en-GB not uk for UK Englishzh-TW not tw for Traditional Chinesees not esp for Spanishpt not por for PortugueseEvery href must include the full URL with protocol and domain.
<!-- Before: relative URLs -->
<link rel="alternate" hreflang="en" href="/" />
<link rel="alternate" hreflang="es" href="/es/" />
<!-- After: absolute URLs -->
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="es" href="https://example.com/es/" />
If you're generating hreflang tags dynamically, construct the full URL:
const baseUrl = 'https://example.com'
const hreflangs = [
{ lang: 'en', path: '/' },
{ lang: 'es', path: '/es/' },
{ lang: 'fr', path: '/fr/' },
]
hreflangs.map(h => ({
rel: 'alternate',
hreflang: h.lang,
href: `${baseUrl}${h.path}`,
}))
Add x-default to specify which page to show when no language matches.
<link rel="alternate" hreflang="x-default" href="https://example.com/" />
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="es" href="https://example.com/es/" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/" />
Typically, x-default points to your primary language version or a language selector page.
Every page in your hreflang set must include links to all other versions, including itself.
<!-- On https://example.com/ (English) -->
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="es" href="https://example.com/es/" />
<!-- On https://example.com/es/ (Spanish) - must have the same links -->
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="es" href="https://example.com/es/" />
If the Spanish page doesn't link back to the English page, Google may ignore the hreflang entirely.
You can implement hreflang in three places:
HTML head (most common):
<head>
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="es" href="https://example.com/es/" />
</head>
HTTP headers (for non-HTML files like PDFs):
Link: <https://example.com/file.pdf>; rel="alternate"; hreflang="en",
<https://example.com/es/file.pdf>; rel="alternate"; hreflang="es"
XML sitemap (for large sites):
<url>
<loc>https://example.com/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/" />
<xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/" />
</url>
Pick one method and stick with it. Lighthouse only checks HTML head and HTTP headers—not sitemaps.
next-intl or similar i18n library that handles hreflang automatically. Or add links in your _document.js or via the Head component with computed absolute URLs from your domain config.@nuxtjs/i18n module which generates correct hreflang tags automatically. Set baseUrl in your i18n config to ensure absolute URLs are generated.hreflang="en" pointing to itself, not just to other languages.<head> or HTTP headers. Links in <body> are ignored by Lighthouse and may be ignored by search engines.Hreflang issues often appear alongside:
Hreflang issues compound across a multilingual site. If your English-to-Spanish links are broken, every page in both languages is affected. Unlighthouse scans your entire site and identifies every page with hreflang errors, so you can fix the pattern once rather than hunting page by page.