Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 16 min read

EU Geo-Blocking Regulation: Redirects, Forms, Payments

The EU Geo-Blocking Regulation (Regulation (EU) 2018/302) doesn't care whether you block EU shoppers with a firewall rule, a redirect or a postcode validator. All three count. The third is the one most teams still ship w

EU Geo-Blocking Regulation: Redirects, Forms, Payments

The EU Geo-Blocking Regulation (Regulation (EU) 2018/302) doesn't care whether you block EU shoppers with a firewall rule, a redirect or a postcode validator. All three count. The third is the one most teams still ship without noticing.

The twist arrived in July 2026. In a case involving a work that was public domain in some member states but still protected in another, the EU's top court held that the publisher needed effective technological measures to exclude users in the protected territory. State-of-the-art IP geo-blocking can qualify even though some users can circumvent it with a VPN. Same lookup, opposite legal answer. What separates them is the reason behind the check.

Heads up: this is a developer's reading of the regulation and the Commission's own guidance, with links to both. It isn't legal advice.

TL;DR

  • Article 3 (page access): you can't block or auto-redirect EU customers by IP address. Redirects need explicit consent, and the version they asked for has to stay one click away.
  • Article 4 (forms and terms): for goods you deliver or let people collect, e-services like hosting and cloud, and services at a physical venue, EU customers buy on the same terms as locals. Address and phone fields count.
  • Article 5 (payment): if you accept a card brand and category from one EU country, you accept it from all of them.
  • Copyright carve-out: software, games, e-books and music escape Article 4 only. Audiovisual, financial, transport, healthcare and gambling are outside the regulation entirely.
  • Legal blocks are fine: if EU or applicable national law requires the restriction, block and explain why. In the 2026 copyright ruling, the CJEU said state-of-the-art IP geo-blocking can qualify as an effective technological measure even though VPN circumvention remains possible. In short: the regulation follows the customer through your whole flow, not just the front door. Treat every country check as a decision that needs a legal reason. If the only reason is "they live in another EU country", the check probably has to go. If EU law, applicable national law, a court order, or the territorial scope of copyright itself legally requires the restriction, keep it and explain the reason to the user.

What the EU geo-blocking regulation actually covers

The regulation has applied since 3 December 2018. It protects "customers", which the text defines as consumers who are nationals or residents of an EU member state, plus businesses established in one when they buy for their own end use. Reselling, processing or subcontracting isn't covered.

It binds traders, not just EU traders. Recital 17 says it applies equally to traders established outside the EU, online marketplaces included, when they operate in the Union. A US SaaS company selling to Spanish customers is in scope.

Three things put a situation outside it:

Situation Covered?
Customer in another EU member state buying from you Yes
Every element of the sale inside one member state (purely domestic) No
Someone who is neither an EU national nor an EU resident No, this regulation only protects EU customers
Audiovisual, financial, transport, healthcare, gambling, electronic communications No, excluded sectors
Non-audiovisual copyrighted content (software, games, e-books, music) Partly: Articles 3 and 5 apply, Article 4 doesn't

That third row matters for anyone running country allow-lists. Blocking non-EU countries is mostly outside this regulation, with one wrinkle: an EU national travelling or living abroad is still a protected customer. It's one more reason an IP country is a poor stand-in for anyone's legal status.

The regulation is short. Articles 3, 4 and 5 do almost all the work, and each one lands on a different part of your stack.

Three articles, three places in your stack

Article 3 is your front door

Article 3 bans blocking or limiting access to your "online interface" for reasons related to a customer's nationality, residence or place of establishment, "through the use of technological measures or otherwise". Online interface means websites, parts of websites and apps. Recital 18 spells out which technological measures it means: tracking location "by means of an IP address or coordinates obtained through a global navigation satellite system". It names our tools specifically.

Redirects are the part developers trip over. You can run de.example.com and fr.example.com with different layouts, languages and prices. You can't bounce a visitor from one to the other because of where they are, unless they've explicitly agreed. Recital 20 and the Commission's Q&A on the Geo-blocking Regulation fill in the details: consent doesn't need to be asked on every visit, a preference saved to an account counts, the customer can withdraw it at any time, and the version they originally asked for must stay easily reachable. The Commission's example is literally "an easily accessible button to take the customer back".

The ban isn't limited to IP. The same Q&A says you can't block app versions based on the country where someone's card was issued either.

App stores are where this is playing out now. In November 2024 the Commission and the consumer protection (CPC) network notified Apple of practices across the App Store, Arcade, Music, iTunes Store, Books and Podcasts. They covered country-specific storefronts users couldn't easily switch, payment limited to cards from the account's country, and downloads limited to the account's country. In a September 2026 answer to a Parliament question, the Commission said the action is still in progress and confirmed that restricting access to apps from other EU countries is one of the practices the regulation potentially prohibits.

Article 4 is your checkout form

Article 4 is the "shop like a local" rule. In three situations you can't apply different general conditions of access (prices, payment terms, delivery terms) because of where a customer is from:

  1. Goods delivered to a place you already deliver to, or collected at a pickup point you already offer.
  2. Electronically supplied services, which recital 24 illustrates with cloud services, data warehousing, website hosting, firewalls, search engines and internet directories.
  3. Services at a physical location: hotel rooms, car rental, event and theme-park tickets. You don't have to deliver everywhere. A German shop that only ships within Germany can keep it that way. What it can't do is refuse a Belgian customer who wants it shipped to a German address or picked up in Germany.

Here's why this belongs in a developer article. The European Court of Auditors' special report on geo-blocking compares the Commission's mystery-shopping surveys from 2015 and 2019, stage by stage. Cross-border shoppers blocked or redirected at the front door were already rare and got rarer: 3.4% to 2.9%. Blocks at registration fell from 26.9% to 14.0%. Shoppers who registered fine and then got stopped before the delivery stage rose from 37.8% to 43.0%.

ECA mystery shopping, 2015 vs 2019: cross-border shoppers blocked at access, registration, delivery and payment

Read that again with your codebase in mind. The geo-blocking that's left mostly isn't a firewall rule. It's a postcode regex that only accepts five German digits, a phone field that rejects anything but +49, a country dropdown with one entry. The Commission's Q&A addresses this directly: a form that requires a residence address but only accepts national formats, with no way to enter a foreign one, "would need to be adapted". Germany's enforcer, the Bundesnetzagentur, lists billing address, IP address and telephone number as the signals traders use to spot foreign buyers.

The audits find exactly that. As the auditors' report recounts, when Sweden's consumer agency checked 78 online shops in 2021, 24 of the 32 that offered in-store pickup required a Swedish postal address.

Two things Article 4 doesn't touch. Article 4(2) lets you set different prices per country or per storefront, as long as anyone can buy at any storefront's terms. And the Q&A says dynamic pricing based on things unrelated to residence, like demand or past purchases, is outside the regulation. Price experiments are fine. Pricing keyed on the visitor's country is the problem.

Article 5 is your payment step

Within the payment methods you accept, you can't refuse a payment or change its conditions because of the customer's nationality or residence, the location of their payment account, where their payment provider is established, or where their card was issued in the EU. It applies to electronic payments by credit transfer, direct debit or card within the same brand and category, where strong customer authentication is met and the currency is one you accept.

You still choose what you accept. Visa debit only? Fine. Visa debit only if it's from a French bank? Not fine.

Article 5(2) lets you hold delivery until you've confirmed the payment went through, but only "where justified by objective reasons". That isn't a licence for a fraud rule that declines every card issued outside your home country. Stripe's guidance on the regulation reads it the same way: fraud tools shouldn't auto-decline accepted cards from particular EU countries. Score risk on many signals. Issuer country alone is a location proxy, and the regulation is about location proxies.

The copyright carve-out most developers misread

"We sell software, so geo-blocking rules don't apply." It's the most common misreading of the regulation, and it's half right.

Article 4(1)(b) excludes services whose main feature is access to copyright-protected works. The Commission's Q&A names e-books, software (updates included), music streaming and online games. Those services are exempt from Article 4's equal-terms rule, so a games publisher can decline to sell in a country where it doesn't hold the rights. But the same Q&A says they stay subject to everything else: no blocking access to website, marketplace or app-store versions by IP or payment details, no redirecting without consent, and no discriminating on where an accepted card was issued.

So a software seller can say "we don't sell this edition in Portugal". It can't stop a Portuguese visitor from loading the page.

Hosted products are murkier. Recital 24 puts cloud services, hosting and firewalls squarely inside Article 4. Whether a given SaaS counts as "mainly access to copyrighted works" or as a cloud service isn't settled, and the Court of Auditors notes that enforcement bodies themselves find the "main feature of which" wording unclear. My take: if you sell a hosted product on public terms to anyone who signs up, build as if Article 4 applies. Being wrong in that direction costs a country dropdown. Being wrong in the other costs an enforcement letter.

Two smaller notes. Traders covered by their country's VAT exemption scheme for small businesses don't have to follow Article 4(1)(b) for e-services (Article 4(4)). And audiovisual streaming is out of the regulation altogether, which is why streaming services' licence maps, not this law, decide what you can watch from another country.

When is geo-blocking legal in the EU?

Short answer: when the visitor isn't an EU customer, when the sector is excluded, or when another law requires the block. That third case is where developers need to get the details right.

When another law requires it

Articles 3(3) and 4(5) carve out blocking, limiting or redirecting that's needed to comply with EU law, or with national law that's consistent with EU law. Think gambling licences, court orders, national book-pricing laws, products that are banned in one country.

There's a condition people skip. When you block for a legal reason, you must give "a clear and specific explanation" of why, in the language of the interface the customer was trying to reach. A bare 403 Forbidden doesn't do that.

HTTP already has a status code for this. RFC 7725 defines 451 Unavailable For Legal Reasons and says the response body should explain the legal demand: who made it, which law, and who it applies to. It also defines an optional Link header with rel="blocked-by" to identify the entity actually implementing the block, not the law or rights holder behind the demand. The regulation doesn't mention 451, but the two fit together well.

What the July 2026 Anne Frank ruling changed

The case: parts of Anne Frank's manuscripts are still under copyright in the Netherlands until 2037 but are public domain in Belgium and elsewhere. A scholarly edition was published free on a website that blocked Dutch IP addresses. The rights holder argued that Dutch users could just use a VPN, so the work was still being "communicated to the public" in the Netherlands.

On 9 July 2026 the CJEU disagreed. Someone publishing a work that's protected in some member states and public domain in others must make sure it's only accessible from the public-domain ones, and must use effective technological measures to do it. State-of-the-art geo-blocking can qualify as effective even though a VPN can get around it, with the national court ultimately assessing whether the particular implementation meets that standard. If the blocking isn't effective, the publisher is responsible, not the VPN provider.

The Commission's IP Helpdesk summary adds two details builders should note. IP-address geo-blocking was the technological measure at issue. And the site's extra "please confirm you're in a country where this is public domain" prompt didn't count, because it depended entirely on the user's honesty.

So in a copyright situation like this one, effective technological geo-blocking can be necessary to keep access outside the protected territory. An IP-based measure can satisfy that standard; a checkbox based only on the user's declaration cannot substitute for it.

What nobody knows yet is how high "state of the art" sets the bar. The Dutch Supreme Court still has to decide whether this site's blocking met it, weighing available technology, how easily it's circumvented and what better measures cost. Whether that will eventually mean VPN or proxy detection on top of a country lookup is an open question. I wouldn't tell you it does, and I wouldn't bet on it never mattering.

Patterns that keep your country checks legal

Decision flow for EU geo-blocking: legal duty, customer location, sector and consent decide block, suggest or redirect

Start by finding every place your code makes a decision by country. A quick search catches most of them:

# List every line that branches on a country, a geo header or a geo database.
# Skip vendored code so the results stay readable.
rg -n -i "country_?code|cf-ipcountry|geoip|geo_?block|allowed_?countries" \
  --glob '!node_modules' --glob '!vendor'

CF-IPCountry is the header Cloudflare adds with the visitor's two-letter country code (Cloudflare docs), so it shows up in a lot of edge-routing code. Go through each hit and write the reason next to it in a comment. If the honest reason is "the customer is in another EU country", that check is the one to remove or rewrite.

Suggest, don't redirect

Detecting the country is fine. Acting on it without asking is what Article 3 forbids. The fix is a banner instead of a redirect.

The examples use an IP geolocation API from ipgeolocation.io, because the v3 lookup returns the country code alone when you ask for just that field. ipinfo, MaxMind GeoIP2 or a CDN country header give you the same input. First, a small server-side helper:

// geo.js: Node 18+ (built-in fetch). Set IPGEO_API_KEY in the environment.
const API_URL = 'https://api.ipgeolocation.io/v3/ipgeo';

export async function lookupCountry(ip) {
  if (!ip) return null;
  const url = new URL(API_URL);
  url.searchParams.set('apiKey', process.env.IPGEO_API_KEY ?? '');
  url.searchParams.set('ip', ip);
  // Ask for one field: smaller response, and the only thing we use.
  url.searchParams.set('fields', 'location.country_code2');

  try {
    const res = await fetch(url, { signal: AbortSignal.timeout(1500) });
    if (!res.ok) {
      console.warn(`geo lookup failed: HTTP ${res.status}`);
      return null;
    }
    const data = await res.json();
    return data?.location?.country_code2 ?? null;
  } catch (err) {
    // Timeouts and network errors land here. Callers decide what null means.
    console.warn(`geo lookup error: ${err.message}`);
    return null;
  }
}

Then an endpoint that only suggests a storefront. It never redirects. Before reusing req.ip for an enforcement control later in this article, make sure your proxy trust configuration cannot be bypassed through a shorter or direct path to the application.

// server.js
import express from 'express';
import { lookupCountry } from './geo.js';

const app = express();
// Illustrative only: this is safe when every request reaches Express through
// exactly one trusted proxy and clients cannot reach the origin directly.
// If request paths vary, trust the exact proxy IPs/CIDRs you control instead.
app.set('trust proxy', 1);

const STOREFRONTS = { DE: '/de/', FR: '/fr/', NL: '/nl/' };

app.get('/api/store-suggestion', async (req, res) => {
  const country = await lookupCountry(req.ip);
  // Fail open: no country means no banner, and the visitor keeps browsing.
  res.json({ country, storefront: STOREFRONTS[country] ?? null });
});

app.listen(3000);

And the browser side. It shows a banner only if the visitor hasn't already chosen, and remembers the choice:

// banner.js: runs on every storefront page.
const CHOICE_COOKIE = 'store_choice';

function savedChoice() {
  const match = document.cookie.match(/(?:^|; )store_choice=([^;]*)/);
  return match ? decodeURIComponent(match[1]) : null;
}

async function maybeSuggestStore() {
  if (savedChoice()) return; // They already decided. Don't ask again.

  try {
    const res = await fetch('/api/store-suggestion');
    if (!res.ok) return;
    const { storefront } = await res.json();
    if (!storefront || location.pathname.startsWith(storefront)) return;

    const banner = document.getElementById('store-banner');
    if (!banner) return;
    banner.querySelector('a.go').href = storefront;
    banner.hidden = false;

    // Both buttons record an explicit choice; only "go" navigates.
    banner.querySelector('a.go').addEventListener('click', () => remember(storefront));
    banner.querySelector('button.stay').addEventListener('click', () => {
      remember(location.pathname.split('/').slice(0, 2).join('/') + '/');
      banner.hidden = true;
    });
  } catch (err) {
    console.warn('store suggestion unavailable', err);
  }
}

function remember(path) {
  document.cookie = `${CHOICE_COOKIE}=${encodeURIComponent(path)}; path=/; max-age=31536000; SameSite=Lax`;
}

maybeSuggestStore();

Keep a visible store switcher in the header on every page, so the original version stays one click away even after someone picks. Storing the choice in a cookie brings GDPR and the ePrivacy rules into play, which the Commission's Q&A flags too, so run it past whoever owns your cookie policy.

Forms, payments and legally required blocks

Forms are where most remaining geo-blocking lives, so they get the most attention:

  • Split residence from delivery. Restrict the delivery address to the places you ship. Accept any EU billing or residence address, with a free-text fallback for formats you don't validate.
  • Phone fields accept every EU prefix. If you need a local number for the courier, ask for it on the delivery step, not at signup.
  • Accept payments by brand and category, not by issuer country. If your PSP lets you block by BIN country, don't point that at EU countries for methods you accept. For blocks another law really does require, answer with a 451 and say why, in the language of the page:
// legal-block.js: a public-domain edition still protected in some countries.
// Mount on a route with a language segment, e.g. app.get('/:lang/edition', copyrightBlock, handler).
import { lookupCountry } from './geo.js';

const PROTECTED_IN = new Set(['NL']); // from your rights research, not a guess
const EXPLANATION = {
  en: 'This edition is still protected by copyright in your country, so we cannot make it available there.',
  nl: 'Deze editie is in uw land nog auteursrechtelijk beschermd en is daar daarom niet beschikbaar.',
};

export async function copyrightBlock(req, res, next) {
  const lang = req.params.lang === 'nl' ? 'nl' : 'en'; // the page's language, not Accept-Language
  const country = await lookupCountry(req.ip);

  // Fail closed: a block that law requires shouldn't vanish when the lookup does.
  if (country === null) {
    return res.status(503).set('Retry-After', '60').send('Location check unavailable. Please try again shortly.');
  }
  if (PROTECTED_IN.has(country)) {
    return res
  .status(451)
  .send(EXPLANATION[lang]);
  }
  return next();
}

Note the fail-closed choice. The suggestion banner fails open because a missing banner hurts nobody. A legally required block fails closed because that's where an outage turns into an infringement.

How seriously is this enforced?

Unevenly, so far. The Court of Auditors' audit found that fines vary wildly by member state: minimum fines from €26 to €900,000, maximums from €1,448 to €5 million. Between December 2018 and June 2024 there was exactly one coordinated EU-level enforcement action under the regulation, and only two of the 18 national enforcement bodies that answered the auditors' survey had ever penalised a trader. A 2023 study for the Commission found 37% of traders didn't know the regulation existed.

It would be easy to read that as permission to ignore it. I wouldn't. The auditors recommended an EU-wide enforcement mechanism by the end of 2026, the Apple case shows the CPC network going after app-store mechanics specifically, and the Commission is preparing a revision of the CPC Regulation for the fourth quarter of 2026. Fixing a postcode validator now is cheaper than doing it under a deadline.

What's changing in 2026

The regulation is under its five-yearly evaluation. The Commission's first round of feedback ran in February and March 2025 and drew more than 500 responses, mostly about whether to bring audiovisual services into scope, then a public consultation from 6 October 2025 to 5 January 2026, per the Bundesnetzagentur's summary. The Court of Auditors asked the Commission to study extending the scope to the excluded sectors by the end of 2026.

Two related proposals are due this quarter: the CPC Regulation revision, and the Digital Fairness Act, which the European Parliament's research service says is scheduled for mid-November. Nothing published so far ties the Digital Fairness Act to geo-blocking, so I wouldn't plan around it. If the evaluation does propose widening the scope, streaming and copyrighted content are where it would hit hardest.

Run the search above on your repo this week. Put a legal reason next to every country check that survives it, and fix your address and phone fields before you touch the firewall rules, because that's where the auditors found the blocking.

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.