Geoblocking & Compliance (GDPR, OFAC, Export Controls)
Block, allow, or warn — legally, auditably, and with a paper trail.
If you handle regulated data (healthcare, finance, defense), operate under export controls, or need to honour EU digital-services rules, you must be able to prove which jurisdiction each request came from. IP geolocation is the cheapest, fastest first-layer check for all of this.
The business problem
Four compliance regimes commonly force geoblocking:
- OFAC / sanctions lists — Cuba, Iran, North Korea, Syria, occupied regions of Ukraine, etc. US-incorporated companies risk secondary sanctions for serving these regions.
- GDPR / NIS2 — data-localization or EU-only cohorts of personal data.
- US export controls (EAR, ITAR) — crypto libraries, defense tech, dual-use goods.
- Content licensing — streaming, gambling, and content platforms with per-country licenses.
Missing the block = fines, license revocation, or criminal liability. Blocking incorrectly = lost revenue and reputational damage. IP geolocation gives you a defensible, logged decision at request time.
Implementation
Express / Node.js middleware
import { ipgeoLookup } from "./lib/ipgeo.js";
const OFAC_BLOCKED = new Set(["CU", "IR", "KP", "SY"]);
const EU_ONLY_ROUTES = ["/eu/patients", "/eu/finance"];
export async function complianceMiddleware(req, res, next) {
const ip = req.headers["x-forwarded-for"]?.split(",")[0] || req.socket.remoteAddress;
const geo = await ipgeoLookup(ip);
// Log every compliance decision for audit
req.log.info({ ip, country: geo.country_code, is_eu: geo.is_eu, path: req.path }, "geo_check");
if (OFAC_BLOCKED.has(geo.country_code)) {
res.status(451).json({ error: "Service unavailable in your region" });
return;
}
if (EU_ONLY_ROUTES.some(p => req.path.startsWith(p)) && !geo.is_eu) {
res.status(403).json({ error: "EU residents only" });
return;
}
req.geo = geo;
next();
}
Python / Flask
from flask import request, abort
import requests, os
BLOCKED = {"CU", "IR", "KP", "SY"}
@app.before_request
def geoblock():
ip = request.headers.get("X-Forwarded-For", request.remote_addr).split(",")[0]
geo = requests.get(
f"https://api.ipgeo.10b.app/v1/lookup/{ip}",
headers={"Authorization": f"Bearer {os.environ['IPGEO_API_KEY']}"},
timeout=2
).json()
app.logger.info("geo_check ip=%s country=%s path=%s", ip, geo["country_code"], request.path)
if geo["country_code"] in BLOCKED:
abort(451) # 451 Unavailable For Legal Reasons — RFC 7725
Return HTTP 451 Unavailable For Legal Reasons for regulated blocks — it’s the RFC-7725 status code explicitly designed for legal blocks and search engines respect it.
Why IP Geo API for this use case
- ISO-3166 country codes — match the codes used in OFAC, EU sanctions lists, and export-control regs verbatim.
- EU membership flag (
is_eu) — single field, no maintenance of your own member-state list (removes Brexit-style bugs). - Continent, subdivision, and timezone included — covers more than half of geoblocking policies (“EU except UK”, “EMEA”, “APAC”) with one lookup.
- Logged responses — every API call is logged server-side for 90 days; your compliance auditor can request a raw-response audit trail.
- No third-country data transfer — all lookups processed on EU infrastructure (Hetzner Nürnberg + Cloudflare EU edge). No US processor = no Standard Contractual Clauses required.
Pricing math
| Your volume | Tier | Cost/mo |
|---|---|---|
| < 30 K requests/mo | Free | € 0 |
| < 1 M requests/mo | Starter | € 29 |
| Regulated / SLA needed | Business | € 99 |
A compliance check at the edge (Cloudflare Workers, Vercel Edge, Netlify Edge) is cached aggressively, so 10 M requests/mo may only translate to ~100 K IP lookups. Most compliance deployments fit in Starter.
Honest trade-offs
- IP geolocation is not a sanctions-grade identity check. A user in a blocked country can use a VPN; a user in a clean country can still be on the sanctions list by name. Use IP geo as a layered control, not the only control. For KYC/AML, combine with name-screening (OFAC SDN list) and document verification.
- Maps are subject to political change. Disputed territories (Crimea, Western Sahara, Taiwan) have politically-loaded codes. If your counsel has an opinion, document the mapping rule in your compliance manual.
- IPv6 coverage. Ensure your provider resolves IPv6 — IP Geo API does, but some legacy providers fall back to country-only for IPv6.
- The right tool for streaming/content licensing is a dedicated anti-VPN provider. IP geolocation alone will leak ~1-3% of determined users through residential proxies. For DRM-grade enforcement, add a residential-proxy detection layer.
Related use cases
- Bot / WAF security —
./bot-security.md - Fraud detection —
./fraud-detection.md - Geo-pricing / localization —
./geo-pricing.md
Related comparisons
../seo-pages/vs-maxmind.md— many compliance teams use MaxMind; our TCO comparison shows when we win.../seo-pages/vs-ipinfo-io.md— ipinfo’s US processing may require SCC paperwork for EU customers; our EU-only processing removes that.
Get started
Free tier: 1 000 lookups / day → /pricing. Sign up at https://ipgeo.10b.app/pricing.
Get early access — 50% off for 12 months
First 100 signups lock in 50% off any paid plan for the first year. No credit card required — we’ll email you at launch.