Kamaankamaan
Free tool · No login

Hreflang tag generator and checker

Generate correct hreflang tags as HTML, an XML sitemap block, or an HTTP header, then paste your existing tags to catch missing x-default and return-tag errors. Everything runs in your browser, nothing is uploaded.

URL structure
Target languages (5 selected)
HTML head tags
<link rel="alternate" hreflang="en" href="https://example.com/blog/my-post" />
<link rel="alternate" hreflang="es" href="https://example.com/es/blog/my-post" />
<link rel="alternate" hreflang="de" href="https://example.com/de/blog/my-post" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/blog/my-post" />
<link rel="alternate" hreflang="it" href="https://example.com/it/blog/my-post" />
<link rel="alternate" hreflang="x-default" href="https://example.com/blog/my-post" />

Paste these inside the <head> of every language version of the page. Each version must list the full set, including a self-referencing tag.

XML sitemap variant
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://example.com/blog/my-post</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="it" href="https://example.com/it/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/blog/my-post" />
  </url>
  <url>
    <loc>https://example.com/es/blog/my-post</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="it" href="https://example.com/it/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/blog/my-post" />
  </url>
  <url>
    <loc>https://example.com/de/blog/my-post</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="it" href="https://example.com/it/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/blog/my-post" />
  </url>
  <url>
    <loc>https://example.com/fr/blog/my-post</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="it" href="https://example.com/it/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/blog/my-post" />
  </url>
  <url>
    <loc>https://example.com/it/blog/my-post</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="it" href="https://example.com/it/blog/my-post" />
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/blog/my-post" />
  </url>
</urlset>

Prefer keeping hreflang out of your <head>? Put it in your sitemap instead. Never do both for the same set.

HTTP Link header
Link: <https://example.com/blog/my-post>; rel="alternate"; hreflang="en", <https://example.com/es/blog/my-post>; rel="alternate"; hreflang="es", <https://example.com/de/blog/my-post>; rel="alternate"; hreflang="de", <https://example.com/fr/blog/my-post>; rel="alternate"; hreflang="fr", <https://example.com/it/blog/my-post>; rel="alternate"; hreflang="it", <https://example.com/blog/my-post>; rel="alternate"; hreflang="x-default"

Use this when the page is not HTML, for example a PDF, or when you set hreflang at the CDN / edge instead of in markup.

Do this automatically
Kamaan emits the full reciprocal hreflang set and a clean canonical for every language, automatically, the moment you publish.
Start free trial30 days free on all plans. No credit card. Publish once, ship every language.
The basics

What hreflang tags do (and why they are so easy to get wrong)

Hreflang is an HTML attribute that tells search engines a page has equivalent versions in other languages or regions. When someone in Mexico searches for your product, hreflang is how Google knows to show your Spanish page instead of your English one, without treating the two as duplicate content competing against each other.

The concept is simple. The execution is where most sites fail. hreflang has to be reciprocal: if your English page points at the Spanish version, the Spanish page must point back. It has to be self-referencing: every page lists itself in the set. And it has to use absolute URLs: relative paths are silently ignored. Miss any one of these on any one page and search engines throw out the entire cluster.

How to use it

Generate hreflang tags in four steps

  1. Paste your page URL. Use the URL of your source-language page, for example your English blog post.
  2. Pick your URL structure. Subdirectory (/es/), subdomain (es.), query parameter, or enter each URL by hand. The tool builds the localized URLs for you.
  3. Select your target languages. Your default language is always included and self-references automatically. x-default is added on by default.
  4. Copy the output. Grab the HTML head tags, the XML sitemap block, or the HTTP Link header, whichever fits your stack, and add it to every language version of the page.
Common errors

The five hreflang mistakes that break your rankings

  • No return tags. Page A references page B, but B does not reference A. Fix by shipping the full set on every page. Use the checker tab above on each live page.
  • Missing self-reference. A page forgets to list its own URL. Every page must include itself.
  • Relative URLs. hreflang requires fully-qualified https URLs. A path like /es/page is ignored.
  • Wrong or invented region codes. Use ISO 639-1 language codes and ISO 3166-1 Alpha 2 region codes only. en-UK is wrong, the code is en-GB.
  • Conflicting canonical. A translated page canonicalizes to the source language, which tells Google to drop it. Each language canonicalizes to itself.
For headless + multilingual blogs

Hreflang in a headless CMS is a maintenance problem, not a syntax problem

If you run a Next.js, Astro, or Nuxt blog on a headless CMS, generating the tags once is the easy part, this tool does it in seconds. The hard part is keeping the reciprocal set correct across dozens of posts and languages as you publish, translate, and re-slug over months. Every new translation you ship silently invalidates the return tags on all of its siblings until you go back and update them.

That is the exact busywork Kamaan is built to delete. You publish a post once. Kamaan auto-translates it into every language on your plan, serves each at its own URL, and emits the complete reciprocal hreflang set plus a correct per-language canonical, every time, with no manual step. The tool above shows you what correct output looks like. Kamaan makes correct output the default, at scale, across every product blog you run.

FAQ

Frequently asked questions

When do I actually need hreflang tags?

You need hreflang when the same page exists in more than one language or regional variant and you want Google to serve the right version to the right searcher. If you only publish in one language, you do not need hreflang at all. It is specifically for multilingual and multi-regional sites.

Do I need a self-referencing hreflang tag?

Yes. Every page in the cluster must list the full set of alternates, including a tag that points at itself. A Spanish page that lists English, German, and French but forgets to list its own Spanish URL is invalid, and Google will likely ignore the whole cluster.

What is the x-default value for?

x-default tells Google which URL to fall back to when none of your listed languages match the searcher. It usually points at your default or language-selector page. It is recommended, not strictly required, but adding it removes ambiguity for locales you do not explicitly target.

What is the difference between hreflang and canonical?

A canonical tag says "this is the single authoritative URL for this content." Hreflang says "these URLs are the same content in different languages, rank each one in its market." They work together: each language version should have a self-referencing canonical AND the full hreflang set. Never point a canonical from your Spanish page to your English page, or you will de-index the Spanish version.

Should I use just a language code or a language plus country?

Use language-only (like es) when the content targets all speakers of that language. Use language-region (like es-MX or en-GB) only when you have genuinely different content per country, for example different pricing or spelling. Do not add a region code you do not actually differentiate, it just creates more return-tag surface to get wrong.

Where should hreflang tags go: the head, the sitemap, or an HTTP header?

Pick one, not several, for the same URL set. HTML head tags are simplest for most blogs. The XML sitemap variant keeps your markup clean and scales to thousands of URLs. The HTTP Link header is for non-HTML files like PDFs. This tool outputs all three so you can choose.

Why do I get a "no return tags" error in Search Console?

That error means page A points at page B as an alternate, but page B does not point back at page A. hreflang must be bidirectional across every page in the cluster. The most common cause is publishing the source language first and forgetting to add the source URL to the translated pages once they go live.

How do I handle hreflang in a headless or multilingual CMS?

In a headless setup the tags are emitted by your frontend from data your CMS returns. The failure mode is manual: you translate a post, ship it at a new URL, and forget to update the return tags on every sibling. Kamaan removes that step entirely, it emits the full reciprocal hreflang set and a per-language canonical automatically every time you publish.

More free tools