The scenario we hear almost every week: a Shopify shop sells in 12 countries, each with its own subdomain, translated catalog, local currency, and local payment gateway. The team hands out 12 different links to partners and creators — one per country. One partner mixes them up, another puts the Mexican link in a German blog, a third just shares en.shop.com everywhere. Result: 18% of traffic lands on the wrong region, conversion in those sessions is 3× lower.

The fix is one rule: give partners one link and let the backend decide where to send each visitor. That is a geo-redirect. Easy from the outside, with a few traps under the hood: VPN, country-language mismatches, SEO consequences. This piece — how to do it without the pain.

TL;DR

Country-level geo-redirect works at 99.6% accuracy on a good IP database. Language fallback via Accept-Language handles edge cases. VPN breaks geo in 8% of traffic — that segment should see a country selector instead of a forced redirect. SEO is solved with canonical + hreflang. For most teams, a geo-redirect plus an explicit “wrong region?” banner is enough.

How accurate is IP-based country detection?

All commercial IP databases (MaxMind GeoIP2, IP2Location, ipinfo, our internal one at TDS) cluster around the same accuracy:

  • Country: 99.6% on good datasets. About 1 error per 250 users. Good enough for a commercial redirect.
  • Region (state): 88–92%. Already noticeably worse. Marketplaces use it for tax and shipping; usually overkill for a redirect.
  • City: 67–78%. Half of what IP service marketing claims. City-level redirects are almost always a bad idea.

Where the country-level errors come from. The main source is mobile networks. A provider with cross-border infrastructure assigns an IP that belongs to a Dutch ASN, even though the physical user is in Moscow. About 2–3% of mobile traffic falls into this, which is most of the 0.4% overall noise.

Takeaway: country-level redirects are safe. City-level — never without a language fallback.

Language fallback: when IP is not enough

There are scenarios where the IP says one country but the user speaks a different language. Switzerland is four-lingual: the IP says “CH”, the Accept-Language header says which language to greet them in. Real examples:

  • a German on a business trip in Italy (IP=IT, Accept-Language=de-DE);
  • a Russian speaker in Germany (IP=DE, Accept-Language=ru-RU);
  • an English-speaking expat in Japan (IP=JP, Accept-Language=en-US).

The rule we recommend: geo decides currency and checkout, language decides UI. The Swiss user sees Swiss prices and the Swiss checkout, but the interface in their preferred language.

The Accept-Language header is often multi-part:

Accept-Language: de-DE, de;q=0.9, en;q=0.7, *;q=0.5

The user prefers German, then English. Parse by weight (q-parameter). On the backend this is ten lines of code or one rule field in TDS.

VPN: 8% of traffic that breaks geo

On our numbers, 5–12% of visitors to commercial sites use a VPN. Higher on privacy-focused products and media, lower on marketplaces. These users see geo that is not theirs. What to do:

  1. Do not block. The temptation to “cut off VPN traffic” comes up regularly, and it is always a bad idea: real people who just want privacy go along with the bots. Especially painful on B2B audiences.
  2. Do not auto-redirect to the “detected” country. Instead, show a selector at the top: “In the Netherlands? or pick another”. The user confirms or changes manually.
  3. Persist the choice in a long-lived cookie for a year. Do not re-trigger geo-redirect when the cookie already states a preference.

Good IP databases flag VPN addresses (is_proxy, type=hosting). Use that flag as a signal “geo is unreliable, ask the user”, not as “refuse to serve”.

What we see in practice

Teams that do a hard geo-redirect with no confirmation banner lose 5–9% retention. It hurts expats and business travelers the most: the user is used to the US version, and from London gets bounced to the UK one — they assume they ended up in the wrong place. A selector at the top of the page fixes this in a day.

SEO: canonical and hreflang

Google dislikes the same URL serving different content to different visitors — it looks like cloaking. To avoid deindexing, two technical pieces matter:

  1. Canonical URL. Each localized version declares itself <link rel="canonical" href="https://es.shop.com/promo">. Google understands that the Spanish landing is a real separate page, not a duplicate.
  2. hreflang. Each version lists all the others:
    <link rel="alternate" hreflang="es-ES" href="https://es.shop.com/promo">
    <link rel="alternate" hreflang="mx" href="https://mx.shop.com/promo">
    <link rel="alternate" hreflang="en" href="https://en.shop.com/promo">
    <link rel="alternate" hreflang="x-default" href="https://en.shop.com/promo">
    Googlebot follows the links and understands the relationship. Without it, your regional versions compete with each other for ranking.

Googlebot itself is a separate story: it arrives from a US IP, and if you geo-redirect it to en.shop.com, it will only index the English version. Better: do not geo-redirect crawlers, serve them every version directly. In TDS the bot route (see how antibot works) sends Googlebot and Bingbot past the geo rules untouched.

When you do not need a geo-redirect at all

Geo-redirect is optional. Cases where it adds noise:

  • Single-country shop. If you only sell in the US — extra logic for nothing.
  • Content site without localization. Single-language blog, no regional adaptations. The visitor's browser figures it out.
  • B2B SaaS with a global interface. One English landing for the world, one currency (USD), nothing to redirect.
  • Landing tied to one ad campaign. If the campaign already targets a specific country in the ad-network settings, users are already arriving from the right geo.

What this looks like in TDS

A geo-redirect in TDS is a campaign rule with a condition list. Each rule says: “if country = X, send to URL = Y”. At the top — a special VPN route (detected as proxy → show selector); at the bottom — a required default. Every match is logged: detected country, whether the user hit the VPN flag, which rule fired.

Conveniences included: automatic hreflang generator for all your versions, a “do not redirect crawlers” toggle, long-lived cookie for confirmed country choice, and analytics on “how often users manually switched country” — the latter is a brutally honest metric of how well your geo assumptions match reality.

Conclusion

Geo-redirect is simple when done right. Three rules:

  1. Redirect by country, never by city.
  2. Do not block or auto-redirect VPN traffic — show a selector.
  3. Skip crawlers and tag your pages with canonical + hreflang.

Two or three markets and one currency? Skip the geo-redirect entirely. Twelve countries with local payments? Without one, life gets painful. Especially if you also need to route by device and source — in that case look at a full smart-link, where geo is one of six signals.