• Technical SEO

Hreflang: so that language versions don't eat each other

Configuring hreflang on a site is four mutually agreed-upon things: the language code of the document, mutual tags for each version, the specified x-default, and the presence of all language branches in the sitemap. We do them together and check not the markup, but the actual answer: whether the Ukrainian page is actually given to the address declared as Ukrainian. In the store we measured with three versions, it was given in Russian — both on the Ukrainian link and on the Polish one.

See how it works
Price
after a free audit
Guarantee
30 days after project sign-off
What are we doing?
document language, mutual hreflang, x-default, canonical, language branches in the sitemap
after a free audit
Price
30
Guarantee

days after project sign-off

document language, mutual hreflang, x-default, canonical, language branches in the sitemap
What are we doing?
5-15
Term

working days - depends on the number of versions and the state of the templates

free language markup check, 2-3 business days
Before the estimate
hreflang is set twice by different mechanisms, the sets contradict each other
The most difficult case in its own dimension
two versions with mutual hreflang and x-default on a catalog of 3,565 products
Good condition from the same measurement
items in another country: markup governs version selection, not issue location
What we do not promise
Who it's for

Situations where this service delivers results

Scenario 1 of 4

Two versions of the same page compete with each other for rendering

The symptom is recognisable: one request shows a Russian page today, a Ukrainian one tomorrow, and none of them hold. For a search engine, these are two almost identical documents without an explanation of who proofreads them. Hreflang is such an explanation. Google writes directly in the documentation: it ignores asymmetric annotations - half of the work done correctly does not work at all.

We'll review your situation in a free audit
Cases

Tasks and results in numbers — all metrics measured by us

online retail underwear store, catalog of over 110,000 items

Task
Find out why the three language versions behave unpredictably in output.
Solution
We read the language markings for each version and checked what is actually provided for each declared address.
Result
Hreflang is initialized twice by two different mechanisms, and the sets conflict with each other: the first points to the root addresses, the second to the language subdirectory. Links marked as Ukrainian and Polish provide Russian content. Additionally: the Ukrainian version has an invalid language code, and the Polish version does not include variables in the template - literally lang="code". What works right there: canonical is self-referential on each of the three versions. The catalog at the time of measurement — 115,456 product items. Measurement 01.08.2026.

online retail store of heating equipment, catalog of about 3.5 thousand items

Task
Maintain two language versions of the directory without mutual competition in search.
Solution
Two versions uk and ru with mutual hreflang and given x-default, self-referencing canonical links.
Result
The language markup is correct on the catalog of 3,565 products — the number was calculated using a regular search engine. First server response 524.8ms, full load 662.7ms with 295.7KB markup. The found defect lies outside the language part: /sitemap.xml returns 200 with an empty body, and there is no structured data on the main page. That is, a correct hreflang does not save if the search engine has nothing to bypass. Measured on 07/31/2026.

a brand of natural cosmetics, a branded store for the EU market

Task
Enter the European market in three languages ​​so that the versions do not compete with each other in publishing.
Solution
Three language versions bg, en and ru with full set of hreflang; structured store, contact and work schedule data on each version.
Result
Three working language versions with hreflang, six structured data types on master, first response 512.6ms with markup weight 220.4KB. The assortment is 23 items, this is the entire catalog of the brand. The defects found are again outside the language part: the site map and robots.txt give an empty body, there is no external analytics on the site at all - not a single counter. Measured on 07/31/2026.
What's included

Complete list of work and what you get as a result

  • We bring the language codes of the document to the standard on each version — "ua" is not the Ukrainian code, the correct one is uk, and this error is silent: the browser does not show it, the validator is silent
  • Full set of mutual hreflang tags: each version names all the rest and itself - otherwise the annotation is one-sided, and one-sided ones are rejected entirely by Google
  • Given x-default - you decide what a visitor whose language does not match any of the declared ones sees, instead of the algorithm deciding it
  • The second, parallel set of language markup is found and removed - precisely because of two mechanisms at the same time, the tags begin to contradict each other
  • Self-referential canonical within each version, no cross-references between languages: canonical from minor language to major overrides hreflang and excludes version from index
  • Running the actual response for each declared address as a list, not a sample - this is where the discrepancy between the tags and what the server returns
  • Language branches in the sitemap: all in one file or a separate map for each language, with a Sitemap directive in robots.txt so that the bot knows where they lie
  • Unique title and description on each version instead of copied from the main one - a translated interface with untranslated meta tags gives a duplicate output
  • Map and report analysis of international targeting in Search Console after implementation
  • "before and after" document with the date of measurement: declared language, actually given language, presence in the site map - for each version
When this service isn't right

What's not included — so there are no surprises at delivery

  • Content translation is a separate job, and we do not recommend machine translation of the directory
  • Local payment and delivery methods for the new market
  • Legal texts under the legislation of another country
  • Promises regarding items in the extradition of another country
Process steps

Transparent stages with approval at every step

Total duration:5–15 days

  1. A snapshot of the language markup

    1-3 working days

    We read the code of each version: document language, hreflang, canonical, meta tags. At the same time, we drag the site map and count how many addresses of each language there are in it. Everything with the date of measurement is a basis for comparison after the works.

  2. Solutions for languages ​​and x-default

    1 working day

    It's your decision, not ours: which versions stay, which is the main one, which x-default gets. Here we screen out languages ​​for which there is neither a market nor a person to support. You can change this later only with the addresses.

  3. Edits in templates

    1-5 working days

    Language codes, full set of reciprocal tags with x-default, self-referential canonical. We turn off the second, parallel set of markup in the place where it comes from - in the theme or in the module, and do not cover it with the third one.

  4. Site map and version meta tags

    1-3 working days

    All language branches in the map: one file or separate maps per language, with a directive in robots.txt. At the same time, we dilute the title and description on the versions so that they cease to be copies of the main language.

  5. Address scanning and transmission

    1-3 working days

    We take the list of declared addresses and read the language of the actual answer to each one. We submit the maps in Search Console, analyze the international targeting report, give the "before and after" table with the same lines that were taken at the first stage.

Free language markup check

Language versions break quietly: the site looks correct, the switch works, but in the search, one version replaces the other, or the wrong language opens at all. It is visible only from the code of the pages and the site map, so we do the first check ourselves and for free — access is not required for it.

What we measure

  • Document language attributeWhat is in html lang on each version. Found both invalid language codes and template variables that did not match - literally lang="code" on the Polish version of the live store.
  • The hreflang setAre all versions listed, are cross-references, or is x-default specified. Separately, we check whether the set is not started twice by different mechanisms: the topic and the module together give a direct conflict.
  • Which is given by the linkThe most important point. We take the address declared as Ukrainian and read the language of the answer. Russian content was delivered to Ukrainian and Polish addresses in the dimension of the underwear store.
  • Language branches in the site mapHow many addresses of each language got there and whether the map is declared in robots.txt. There have been cards that give 200 with an empty body — formally, the answer is there, the address in it is zero.
  • Meta tags on versionsAre the title and description translated or copied from the main language? A translated interface with untranslated meta tags is a duplicate, not a language version.
  • Canonical linksIs canonical on every version and does it lead to itself and not to another language. In the underwear store, canonical turned out to be self-referencing on all three versions, the only thing that worked correctly there.

What you get

  • Table for each version: declared language — actual response language — presence in the site map.
  • List of conflicts with specific addresses where they are visible.
  • A fix plan with a split between what is done in the template and what is done in the CMS settings.
  • A 30-minute conversation on the document, where you can argue with the conclusions.

Timeline: 2-3 working days

Why is it free

Because the check is short - a few requests and code analysis - and the price of a mistake is high: incorrect language markup divides your own traffic between versions, and it costs more than any audit.

What's next

After the inspection, we name the list of works and the term by stages. If the language marking is correct, but the problem is something else, we will say it directly and show you exactly where to look.

Short form: your contact and site URL

  • Contract, act and 30-day warranty

    Every project gets a written contract: scope, deadlines, amount, acceptance procedure. After delivery — act and invoice, then 30 calendar days of warranty.

  • Sole proprietor & bank transfer

    The contractor is a registered sole proprietor. Payment by invoice with closing documents.

  • Rights & access — yours

    Code, design and materials transfer to you after full payment. Domain, hosting, repository and analytics are registered to you.

  • Client portal instead of email chains

    During the project you get access to a portal: contracts, invoices, acts and project status in one place.

  • European clients

    Among our work — projects for Norway, Bulgaria, Moldova and Spain.

  • Verifiable numbers

    Every case in the portfolio comes with a link to a live site and a technical measurement.

  • Audit first, then pricing

    There is no price list on the site intentionally: the scope of the same work differs multiples between clients.

  • We say "no" when unsure

    If the task isn't ours or the deadline is unrealistic — we tell you upfront.

Did not find your case?

Describe how it works on your side — we will tell you whether “Configuring hreflang and language versions” fits and what it means in your situation. No brief and no call: one question, one answer.

What affects the price

Why two seemingly identical tasks are priced differently

  • How many places in the code start the language markupA prime factor, and it is never visible from the problem description. One site gives tags from the theme template, the second from the module, the third from both at the same time, and then first you have to figure out which set to keep and which to turn off without breaking the switch for people.
  • Number of versions and whether all of them are neededThe number of pairs grows faster than the number of languages: three versions are already nine mutual references, which must be checked one by one. Sometimes the cheaper answer is to remove a version that no one supports.
  • Where versions liveA subdirectory of one address is the simplest case, everything is done in one template. Subdomains and individual domains add rights confirmation in Search Console to each resource: reciprocal tags cannot be set on one side.
  • Site map statusA map that has all branches is zero extra work. A map that returns an empty body or contains one of two languages ​​means that it needs to be regenerated and declared in robots.txt, which is an adjacent amount of work.
  • Meta tags on minor versionsIf the title and description are copied from the main language, the markup alone will not solve the problem: the versions will remain identical in output. Volume is calculated by the number of templates and categories to be expanded, not by the number of languages.
  • Who implements the editsWe have access to templates - we work by ourselves. Edits are made by your team - we prepare accurate fragments and check the result; it is not technically more difficult, but calendar-wise longer.
Technologies & integrations

What we build on and what it connects to

Stack

  • hreflang in head is the main way, it is fixed in the template. Limit: Google rejects one-sided annotations entirely
  • hreflang in the sitemap — when getting into the template is expensive. Limit: the map should be generated automatically, such a file should not be held by hand
  • x-default - controls the selection for those whose language did not match. Boundary: This is a hint, not a redirect
  • html lang with ISO 639-1 codes. Limit: "ua" is not a Ukrainian code, the correct one is uk, and the browser will not warn about it
  • rel=canonical self-referential. Boundary: canonical between languages ​​overrides the entire hreflang with a single line
  • Search Console, International Targeting Report. Limit: delayed data, rights to the resource are confirmed by the domain owner
  • OpenCart, WPML and Polylang multilingualism. Boundary: A theme often adds its own set on top of the module's - hence the double sets
  • nginx language routes. Border: geolocation redirect hides part of the versions from a bot that comes from the same country

Integrations

  • Google Search Console
  • Bing Webmaster Tools
  • GA4
  • Cloudflare
Hreflang in head vs hreflang in sitemap

How this option differs from the alternative

Where is it fixed?in the page template - requires access to the theme code
How much does a page weigh?each version adds a line to the head of each page
How it breaksquiet: theme and module give two sets that contradict each other
How many versions can withstandup to three or four it is read normally, then the head swells
How to checkindividually by page - it is immediately visible in the code
What we need from you

We can't start without this — best to prepare in advance

  1. The list of languages ​​and markets for which you actually work is not "let it be", but where you sell.
  2. Access to templates: language markup lives in the code of the page, it is mostly invisible from the admin.
  3. Access to Search Console per version if they are on different domains or subdomains.
  4. The decision which version is the primary one for a visitor without a specific language is what x-default is.
  5. A person from your side who will say "yes" to the list of languages: technically, this decision is not accepted.
  6. The translated title and description for secondary versions, if they are not available now, are your texts, the arrangement is ours.

If something is missing — let us know, we'll help you gather it or do it as a separate task.

FAQ

Most frequently asked questions — with concrete answers

Why hreflang if I just have two versions with a switch?

The switch is for a person. Hreflang is for the search engine: it says that these two pages are not duplicates, but versions of the same content, and which one to show to whom. Without it, two versions compete with each other in the same issue, and the search engine chooses itself. Another nuance, because of which half of the settings do not work: the annotation must be mutual. If the Ukrainian page names the Russian one, and the Russian page does not name the Ukrainian one, Google rejects such a pair and remains with its choice.

What is x-default and is it required?

This is the default version for a visitor whose language did not match any of the declared languages. Formally not mandatory, but practically required if you want to manage this choice yourself, and not give it to an algorithm. In the heating equipment store we measured, the x-default is set, and the speech pair is the only thing there, about which there were no complaints. It's important to understand the boundary: x-default is a hint about which version to show, not a redirect. He does not carry anyone anywhere.

How to tell if hreflang is broken?

The most reliable way is to open the address declared as Ukrainian and see in what language the reply came. Markup can be valid and yet lie. In the underwear store, we found exactly this: the hreflang was set up twice by different mechanisms, the first set leads to the root addresses, the second to the language subdirectory, and the links marked as Ukrainian and Polish give Russian content. No validator shows this, because both sets are syntactically correct.

We have lang="ua" in our code - is this an error?

Yes. The language code "ua" does not exist: Ukrainian is uk, and ua is the country code in another standard. The error is silent, the page opens normally, no one highlights anything in red. In the same lingerie store, the Ukrainian version gave exactly lang="ua", and the Polish version - lang="code", that is, the variable simply did not fit into the template. Therefore, we check the language of the document on each version separately, rather than looking at one page and assuming that the rest are the same.

Do language versions have to be in the sitemap?

All must be included, otherwise the second language exists for the visitor and does not exist for the bot. Just don't expect more from a sitemap than it delivers: Google documents it as a way to find pages, not as a promise to index them. And it should not be checked based on the fact of having an address. In the heating equipment store, the card returns an HTTP 200 - looks good - and the response body is empty: zero addresses in both languages.

Is it necessary to translate the entire site or is the interface enough?

Translation of the interface without translation of metatags gives a duplicate, not a language version: the output has the same page title and the same description. The minimum that should be translated on each version is the title, description, page header, category names, and payment, shipping, and returns service pages. Product cards can be filled in queues. We do not recommend machine translation of the catalog: the buyer sees it in the first second, and the search engine does not from the first, but sees it.

How many languages ​​does it make sense to keep?

As many markets as you truly serve - with payment, delivery and support in that language. The site closes only the shop window, and this is not a figure of speech: in the company store of the Bulgarian cosmetics brand, there are three versions, bg, en and ru, with correct marking - and behind each of them there is a real market. Each extra version multiplies the amount of content someone has to maintain with each new product. Therefore, at the first stage, we more often suggest removing the language than adding it.

Will traffic increase after fixing the markup?

Directly - no, and it would be dishonest to promise such a thing. The fix does another thing: your custom pages stop competing with each other, and the search engine shows the version you assigned to that visitor. Growth from a new market does not follow from this - it requires content, demand and local sales conditions. What will appear for sure: controllability and the ability to check. Announced language, actually given language and presence in the site map are three numbers that we take before and after the work, and then the reaction is visible in your Search Console with a delay of several days.

Send the address of the site and the list of languages ​​that are announced on it.

The answer is a table for each version: what is written in the markup, what is actually given, what is in the site map. If the language part is correct, we will write it and show where the real reason is.

From measured casesThe language markup is correct on the catalog of 3,565 products

View cases
  • Reply within 2 hours
  • No commitment
  • We work under a contract

There is no price list on the site on purpose: the same work differs several times over between two clients, and a “from” figure explains nothing in that case. First a free audit — we count your pages, duplicates and speed — then we name the sum and the deadline and fix both in the contract.