IP Geolocation for iGaming — Licence-Jurisdiction Enforcement, Anti-Circumvention, and Self-Exclusion

Why iGaming is its own axis: every licensed operator in the EU (MGA Malta, UKGC, KSA Netherlands, DGOJ Spain, ANJ France, ADM Italy, DAS Germany, MGCB Michigan / DGE NJ on the US side) carries a licence-condition that requires technical measures to prevent play from non-licensed jurisdictions. Failure to demonstrate those measures is a six-to-seven-figure fine and a clawback of every euro of NGR generated from the wrong jurisdiction. The IP layer is the first and cheapest of those measures, ahead of GPS, SIM-card MCC/MNC, or device-graph fingerprinting.

The country an IP resolves to, the ASN it belongs to, and whether it’s a known datacenter, VPN, proxy, or Tor exit are inputs to three separate iGaming control surfaces:

  1. Licence-jurisdiction enforcement — every game session, deposit, withdrawal, and bonus claim is gated on country_code ∈ licensed_jurisdictions AND is_vpn = false AND is_proxy = false. A single IP-classification miss can void an entire month’s NGR retroactively when the regulator audits the session log.
  2. Anti-circumvention (VPN / proxy / residential-relay) — UK players hopping a residential-proxy network to claim an MGA-only €500 welcome bonus is the canonical fraud pattern. ASN reputation + is_proxy + is_relay + risk score catches the vast majority pre-deposit.
  3. Self-exclusion register cross-checks — GamStop (UK), CRUKS (Netherlands), ROFUS (Denmark), Spelpaus (Sweden), OASIS (Germany) all expose self-exclusion lists keyed off identity, but IP-country is the precondition for which register to consult. Hit the wrong register because of a stale IP-country resolve and you have a safer-gambling violation in the audit trail.

A single REST call to IP Geo API returns all three signal classes — country/region, ASN, threat-flags (VPN/proxy/Tor/hosting/relay) — on every plan, no add-on SKU, ≤40 ms median in EU.

What iGaming buyers care about (in order)

  1. Latency budget ≤40 ms. Live in-play markets (football, tennis, basketball) re-price every 200-500 ms; the licence-check + VPN-check hop must finish in ≤40 ms or the bet gets rejected after the odds have already moved. IP Geo API runs on EU edges (Hetzner Frankfurt) for ≤30-40 ms median across DE/NL/FR/IE/ES/IT/UK.
  2. EU residency + GDPR + EGBA posture. European Gaming and Betting Association (EGBA) members are scrutinised by the German Joint Gaming Authority (GGL), the Dutch KSA, the French ANJ, the Spanish DGOJ, the Italian ADM, and the Malta MGA. Customer IPs cannot be transferred to a US vendor without §28 GDPR DPA + SCCs + TIA. IP Geo API is EU-only data-flow, signed DPA in 24h, no SCCs required, and GGL-friendly out of the box.
  3. Threat fields on every plan, not a separate SKU. Most US incumbents (MaxMind, ipinfo.io, ipstack) split datacenter/VPN/proxy classification into a paid Security Module or Privacy add-on. IP Geo API ships is_vpn, is_proxy, is_tor, is_hosting, is_relay, and a numeric risk_score on the free tier — critical when the regulator asks for proof of VPN-blocking on every session.
  4. ASN-level granularity for residential-proxy detection. The dominant iGaming circumvention vector in 2025-2026 is residential-proxy networks (Bright Data, Oxylabs, Smartproxy, IPRoyal) renting consumer IPs from compromised home routers. Country-only checks pass these through; ASN + is_proxy flag catches them. We expose asn, asn_org, and is_proxy as first-class fields so your KYT (Know Your Transaction) filters can reject at ASN granularity without maintaining a list yourself.
  5. Predictable EUR billing. iGaming operator P&L is EUR-denominated for EU licensees; USD-billed vendors create FX surprises at quarter-end and complicate licence-fee + gaming-tax filings. IP Geo API is monthly EUR, no annual prepay, no FX line item.

The three iGaming control surfaces, in code

1. Licence-jurisdiction enforcement at session-start, deposit, and bet-placement

// /api/session/precheck.js — Node 20 / fastify
// Called at login, deposit-init, withdrawal-init, and every bet placement.
// Hard-fail closed: any classification error rejects the session.
const fetch = require('undici').fetch;

const LICENSED = {
  // licence-id → ISO-2 country list (operator must hold a live licence in each)
  'MGA-B2C-1234': ['MT', 'IE', 'FI', 'NO', 'BG', 'RO', 'HR', 'GR', 'CY'],
  'KSA-NL-001':   ['NL'],
  'UKGC-039123':  ['GB'],
  'DGOJ-ES-987':  ['ES'],
  'ANJ-FR-456':   ['FR'],
  'ADM-IT-789':   ['IT'],
  'DAS-DE-321':   ['DE']
};

async function precheckSession(req, res) {
  const ip = req.ip;
  const geo = await fetch(`https://api.ipgeo.10b.app/v1/lookup/${ip}`, {
    headers: { Authorization: `Bearer ${process.env.IPGEO_KEY}` },
    signal: AbortSignal.timeout(40)
  }).then(r => r.json()).catch(() => null);
  if (!geo) return res.code(503).send({ reject: 'ipgeo_unavailable' });

  // Reject ANY circumvention signal — regulators expect hard-fail-closed.
  if (geo.is_vpn || geo.is_proxy || geo.is_tor || geo.is_hosting) {
    await audit.write({ session: req.id, ip, geo, reject: 'circumvention_flag' });
    return res.code(403).send({ reject: 'vpn_proxy_tor_blocked' });
  }

  // Match country to operator's active licence catalogue.
  const eligible = Object.entries(LICENSED).filter(([_, list]) =>
    list.includes(geo.country_code));
  if (eligible.length === 0) {
    await audit.write({ session: req.id, ip, geo, reject: 'unlicensed_jurisdiction' });
    return res.code(451).send({ reject: 'jurisdiction_not_licensed' });
  }

  req.licenceId  = eligible[0][0];   // attach for downstream wallet + bonus logic
  req.geoCountry = geo.country_code;
  req.geoAsn     = geo.asn;
}

Why hard-fail-closed: every EU regulator (UKGC LCCP 17.1.1, KSA Kansspelautoriteit beleidsregel 5.1, MGA Player Protection Directive) treats an unclassifiable IP as the same risk class as a foreign-jurisdiction IP. “We couldn’t determine the country” is not a defence in an enforcement hearing.

2. Anti-circumvention scoring at deposit + bonus claim

# /risk/deposit-scoring.py — invoked synchronously before card-auth or APM hold
RESIDENTIAL_PROXY_ASNS = {  # Major commercial residential-proxy operators (2025-2026)
    212238, 401116,         # Bright Data / Luminati
    396982, 60068,          # Oxylabs / Cyberghost
    62240, 16276,           # Smartproxy / OVH-mixed
    35916, 174,              # IPRoyal / Cogent-mixed
}

def score_deposit(geo, deposit_eur, account_age_days, prior_country):
    risk = geo['risk_score']  # 0-100 baseline from IP Geo API

    # Hard rejects (already caught at session, but defence-in-depth)
    if geo['is_tor']:                         return ('hard_reject', 100, 'tor_exit')
    if geo['is_hosting']:                     return ('hard_reject', 100, 'datacenter_ip')
    if geo['asn'] in RESIDENTIAL_PROXY_ASNS:  return ('hard_reject',  95, 'known_residential_proxy_asn')

    # Soft signals
    if geo['is_vpn']:                          risk += 25
    if geo['is_proxy']:                        risk += 30
    if geo['is_relay']:                        risk += 10   # iCloud Private Relay etc — softer
    if prior_country and geo['country_code'] != prior_country: risk += 20
    if account_age_days < 7 and deposit_eur > 500:           risk += 15

    if   risk >= 80: return ('manual_review',      risk, 'high_aggregate_risk')
    elif risk >= 60: return ('step_up_kyc',         risk, 'medium_aggregate_risk')
    elif risk >= 40: return ('flag_for_audit',     risk, 'low_aggregate_risk')
    else:            return ('approve',             risk, 'pass')

Why ASN-block at deposit, not just country-mismatch: a UK self-excluded player using Bright Data’s residential proxy in MT gets country_code: MT, is_proxy: true — country-only filters approve, ASN-aware filters block. The Bright Data ASNs are publicly attributable; we expose them in asn_org so your filter can match on either the numeric ASN or the org-name pattern.

3. Self-exclusion register routing — call the right register

// /risk/self-exclusion-check.js — fires before bonus-claim or first deposit
async function selfExclusionCheck(playerIdentity, geo) {
  const registries = {
    GB: { name: 'GamStop',  endpoint: 'https://gateway.gamstop.co.uk/...' },
    NL: { name: 'CRUKS',    endpoint: 'https://api.cruks.nl/check/...' },
    DK: { name: 'ROFUS',    endpoint: 'https://rofus.dk/api/check/...' },
    SE: { name: 'Spelpaus', endpoint: 'https://spelpaus.se/api/check/...' },
    DE: { name: 'OASIS',    endpoint: 'https://oasis.gluecksspiel.de/api/...' }
  };
  const r = registries[geo.country_code];
  if (!r) return { check: 'no_registry_required', country: geo.country_code };

  const hit = await fetch(r.endpoint, {
    method: 'POST',
    body: JSON.stringify({ id: playerIdentity.nationalId, dob: playerIdentity.dob }),
    headers: { Authorization: `Bearer ${process.env[r.name.toUpperCase() + '_KEY']}` }
  }).then(r => r.json());

  if (hit.excluded) {
    await audit.write({
      player: playerIdentity.id, registry: r.name,
      country: geo.country_code, ip: geo.ip, ts: Date.now()
    });
    return { check: 'self_excluded', registry: r.name, reject: true };
  }
  return { check: 'cleared', registry: r.name };
}

Why IP-country routes the registry call: consulting GamStop for a Dutch player is a GDPR data-export to a UK-based register without lawful basis (the Dutch CRUKS is the legal route). Hitting the wrong registry costs you the §28 GDPR processor relationship AND the safer-gambling audit-trail. The IP-country resolve is the cheapest, fastest signal for which register to query — before any document-KYC is collected.

Pricing math for a typical EU iGaming stack

Stage Volume Tier Cost / month Cost per check
Pilot integration (single-licence) < 30 K sessions/checks per mo Free € 0 € 0
Single-jurisdiction operator (e.g. NL-only) < 1 M req/mo Starter €29 € 29 € 0,00003-0,001
Multi-licence EU operator < 10 M req/mo Business €99 € 99 € 0,00001-0,0001
Tier-1 EGBA operator > 10 M Custom on request < € 0,00001

An iGaming operator running 5 M session-precheck calls/mo with an average NGR of € 30 per active player who would otherwise have been allowed to play via a residential-proxy hop recovers the entire Business tier (€ 99) by blocking ~4 such sessions per month — and that is before counting the regulatory fine avoidance, which dwarfs the SaaS fee by 3-4 orders of magnitude.

Honest limits — what IP geolocation is not for in iGaming

IP geolocation’s job in an iGaming stack is to cheaply route and gate so the expensive verifications (document-KYC, PEP screening, third-party AML providers) only activate for players the IP layer has already pre-cleared as in-jurisdiction and non-circumventing.

Related use-cases

The iGaming surface composes from these IP Geo API use-case patterns:

Compare IP Geo API to the providers iGaming operators evaluate

If you’re shortlisting vendors for a licence-renewal IT-controls audit (MGA, UKGC, KSA, DGOJ, ANJ, ADM, DAS), these head-to-heads cover the providers most often shortlisted in the IP-geolocation market:

Read also — narrative deep-dives

Seven 2026-dated comparison articles with code-level migration sketches and latency / pricing math at 100K / 1M / 10M req/mo:

Migration walkthroughs — drop-in code-level guides

Already on an incumbent? These step-by-step migration guides ship with field-by-field maps, code diffs, shadow-mode validation, and rollback notes:

Industry deep-dives

Other vertical-specific surfaces using the same IP Geo API primitives:


Get started — iGaming-friendly procurement

Sign up at https://ipgeo.10b.app/pricing and start with a sandbox key today.


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.