🌐 Hreflang Generator

📤 Output format

HTML head emits <link> tags for the document head. Sitemap XML emits <xhtml:link> tags for inside a <url> block. HTTP Link header emits one Link: … line per entry — paste them into your nginx / Apache / CDN config.

🌍 x-default fallback

Strongly recommended by Google for every cluster.

📋 Language variants

  • {{ suggestion.code }} {{ suggestion.label }}

⚠️ Validation

  • {{ w }}

📤 Generated tags

{{ output || 'Add at least one variant to generate hreflang tags.' }}

Filename suggestion: {{ downloadFilename }}. Place HTML <link> tags in <head> of every variant page; sitemap tags inside each <url> block; HTTP Link: headers in your server / CDN response config.

⚠️

ℹ️ About Hreflang Generator

What hreflang does and why search engines need it

The hreflang attribute is the canonical way to tell Google, Bing, and Yandex that a page has localized versions and which one each user should see. It is a discovery + selection hint, not a ranking signal — Google uses it to choose the right SERP entry per user (based on Accept-Language and inferred country), and to consolidate duplicate-content signals across language variants so they do not compete with each other in the index.

This tool builds the three serialisations search engines accept — HTML <link> tags for placement in <head>, sitemap <xhtml:link> elements for placement inside a sitemap <url> block, and RFC 8288 Link: response headers for non-HTML assets like PDFs. The same module powers the POST /api/tools/seo/hreflang-generator endpoint (Module-First) so what you copy from the panel below is what the API returns.

The three placements search engines accept

  • HTML <head> tags — one <link rel="alternate" hreflang="…" href="…"/> per language variant, placed in the document head of every variant page. This is the most common placement.
  • XML sitemap annotations — emit a <xhtml:link rel="alternate" hreflang="…" href="…"/> child inside every <url> block, with xmlns:xhtml="http://www.w3.org/1999/xhtml" declared on the surrounding <urlset>. Useful when the head of every variant page is hard to modify.
  • HTTP Link: response headers — set Link: <https://example.com/de>; rel="alternate"; hreflang="de" on every variant response. This is the only option for non-HTML assets such as PDFs because the <head> placement is unavailable.

BCP 47 — what a hreflang code actually is

Every hreflang value is a BCP 47 language tag — the joint IETF / ISO specification published as RFC 5646. The four canonical forms you will see in real-world hreflang are:

  • language — two-letter ISO 639-1 code in lowercase (en, fr, de, ja, zh).
  • language-region — language + two-letter ISO 3166-1 alpha-2 country code in uppercase (en-US, en-GB, fr-CA, pt-BR). The country subtag must be 2 chars — en-USA is invalid and ignored by Google.
  • language-script — language + four-letter ISO 15924 script code in title-case (zh-Hans, zh-Hant, sr-Cyrl, sr-Latn). Use this when the same language has multiple writing systems.
  • language-script-region — both qualifiers together (zh-Hans-CN, zh-Hant-TW, sr-Latn-RS). Use when both the script and the country matter.

The dedicated x-default value is not a language tag at all — it is a documented sentinel telling Google to fall back to this URL for any user whose language / country does not match an explicit entry. Strongly recommended for every hreflang cluster.

Three rules Google enforces silently

  • Absolute URLs only. Relative href values (/de/page, ./de) are silently ignored by Googlebot. This tool surfaces a warning the moment a relative URL appears.
  • Reciprocity is mandatory. If page A links to page B with hreflang="fr", page B must include a corresponding link back to page A — otherwise Google ignores both annotations. This is the single most common reason hreflang "doesn't work".
  • Every cluster needs an x-default. The fallback is technically optional but practically essential: it tells Google which URL to send users whose locale does not match an explicit entry. Without it you lose traffic from every region you didn't enumerate.

Practical use cases

  • Multilingual marketing site: emit en / de / fr / es tags on every page so Google sends each user to their language.
  • Regional storefronts: en-US / en-GB / en-AU / en-CA — same language, different currency / shipping / tax. Google picks the right SERP entry per country.
  • Simplified vs. Traditional Chinese: zh-Hans + zh-Hant (or the more specific zh-Hans-CN + zh-Hant-TW + zh-Hant-HK) so users in different regions see the correct script.
  • RTL languages: ar / he / fa variants of the same page with right-to-left layout.
  • Sitemap-only deployment: when the <head> of every variant page is hard to modify, emit the same annotations inside the XML sitemap so Google still picks them up.
  • PDF / non-HTML assets: emit the HTTP Link: header from your CDN / reverse proxy so localized PDFs are still mapped to the right SERP entry.

How this tool validates and serialises

  • Every code is parsed against BCP 47 (RFC 5646). The language subtag must be a known ISO 639-1 alpha-2 code; the region subtag must be ISO 3166-1 alpha-2; the script subtag must be ISO 15924. Anything else surfaces a warning naming the broken subtag.
  • Casing is normalised: zh-cn is accepted but the output uses the canonical zh-CN; a warning surfaces so editors can fix the source.
  • Duplicate hreflang values within a single cluster surface a warning — Google ignores duplicate annotations.
  • Missing x-default emits a warning unless the toggle is on. When the toggle is on, the tool inserts x-default automatically using the supplied default href (or the first entry's href if none is supplied).
  • Every href and every hreflang value is XML-escaped before emission, so an ampersand or quote in a URL cannot break the surrounding document.
  • The same TypeScript module that powers the in-browser preview also powers the API endpoint below (Module-First) — the output is byte-identical between the two.

Source references

API Usage Example:

POST /api/tools/seo/hreflang-generator
Content-Type: application/json

{
    "entries": [
        {
            "hreflang": "en-US",
            "href": "https://example.com/en-us/"
        },
        {
            "hreflang": "en-GB",
            "href": "https://example.com/en-gb/"
        },
        {
            "hreflang": "de-DE",
            "href": "https://example.com/de-de/"
        }
    ],
    "format": "html",
    "includeXDefault": true,
    "xDefaultHref": "https://example.com/"
}
Ready