GeoIP Lookup

Predictable, cacheable geographic IP lookup with explicit parameters

Explicit Parameters Design

ResolveDB uses explicit parameters for all GeoIP queries. The server never infers location from the client's IP address, providing predictability, cache efficiency, and privacy.

BenefitDescription
PredictabilitySame query returns same result from anywhere—CI, staging, production
Cache efficiencyNo ECS fragmentation. One cached response serves all users globally
PrivacyServer never learns your IP. You control what data is shared
CompatibilityWorks through DoH/DoT, VPNs, corporate proxies, Tor

Multi-Region DNS Cluster

ResolveDB operates authoritative nameservers across multiple geographic regions:

User (NYC)              User (LA)              User (Berlin)
        |                       |                       |
        v                       v                       v
   +---------+            +---------+            +---------+
   | Public  |            | Public  |            | Public  |
   |  DNS    |            |  DNS    |            |  DNS    |
   +----+----+            +----+----+            +----+----+
        |                      |                      |
        |    Anycast / GeoDNS routing                 |
        v                      v                      v
   +---------+            +---------+            +---------+
   |  ns01   |            |  ns02   |            |  ns03   |
   |  NYC    |            |  SFO    |            |  AMS    |
   +---------+            +---------+            +---------+

Multi-Region Deployment

ResolveDB runs authoritative nameservers across multiple strategic regions to minimize latency:

ServerLocationCoverage
ns01.resolvedb.netUS EastAmericas
ns02.resolvedb.netUS WestPacific, Asia
ns03.resolvedb.netEuropeEMEA

DNS clients automatically route to the nearest available server via the resolver infrastructure.

GeoIP Lookup

GeoIP lookups require an explicit IP address parameter. The server does NOT infer from the client's source IP.

Query Format

# IPv4: use ip- prefix with dots as hyphens
dig get.ip-8-8-8-8.geoip.v1.resolvedb.net TXT +short

# IPv6: use ip- prefix, colons as hyphens, :: becomes --
dig get.ip-2001-4860-4860--8888.geoip.v1.resolvedb.net TXT +short

# HTTP API (explicit IP required)
curl "https://api.resolvedb.io/geoip?ip=8.8.8.8"

Response Format

v=rdb1;s=ok;t=data;e=plain;ip=8.8.8.8;cc=US;cn=United States;rg=California;ct=Mountain View;lat=37.386;lon=-122.084;tz=America/Los_Angeles;isp=Google LLC

Response Fields

FieldDescriptionExample
ipIP address looked up"8.8.8.8"
ccCountry code (ISO 3166-1)"US"
cnCountry name"United States"
rgRegion/state"California"
ctCity"Mountain View"
latLatitude37.386
lonLongitude-122.084
tzTimezone"America/Los_Angeles"
ispISP name"Google LLC"

Why Explicit Parameters?

Traditional GeoDNS (Broken)ResolveDB (Explicit)
Server infers from source IPClient provides IP in query
Different results from different networksSame query = same result everywhere
Breaks through VPNs/proxiesWorks through any network path
Thousands of ECS-scoped cache entriesOne cached response serves all users
Can't test in CI (wrong location)Testable and debuggable from anywhere
Server logs reveal your locationYou control what data is shared

Location-Based Queries

For weather and other location-based data, provide explicit location parameters:

City-Based Queries

dig get.city-newyork.weather.public.v1.resolvedb.net TXT +short
dig get.city-london.weather.public.v1.resolvedb.net TXT +short
dig get.city-tokyo.weather.public.v1.resolvedb.net TXT +short

Coordinate-Based Queries

# Format: lat-<lat>.lon-<lon> where decimals use 'd' separator
# NYC: 40.7128, -74.0060
dig get.lat-40d7128.lon--74d0060.weather.public.v1.resolvedb.net TXT +short
#                       ^^ double hyphen for negative longitude

Or use Base64-encoded JSON:

// Encode coordinates as Base64 JSON
const coords = { lat: 40.7128, lon: -74.0060 };
const encoded = btoa(JSON.stringify(coords));
const query = `get.b64-${encoded}.weather.public.v1.resolvedb.net`;

Use Cases

Region-Specific Configuration

Fetch configuration for a specific region by including the region in the query:

# Fetch US-specific config
dig get.region-us.config.myapp.v1.resolvedb.net TXT +short
# Response: {"currency":"USD","language":"en-US","dateFormat":"MM/DD/YYYY"}

# Fetch EU-specific config
dig get.region-eu.config.myapp.v1.resolvedb.net TXT +short
# Response: {"currency":"EUR","language":"en-GB","dateFormat":"DD/MM/YYYY"}

Edge Server Selection

Get the nearest edge server by specifying a region:

# Get edge server for US East
dig get.region-us-east.edge.cdn.v1.resolvedb.net TXT +short
# Response: {"server":"edge-nyc.example.com","region":"us-east-1"}

# Get edge server for Europe
dig get.region-eu-west.edge.cdn.v1.resolvedb.net TXT +short
# Response: {"server":"edge-ams.example.com","region":"eu-west-1"}

Regional Feature Flags

Fetch feature flags for specific regions:

# EU features (GDPR compliance)
dig get.region-eu.features.myapp.v1.resolvedb.net TXT +short
# Response: {"analytics":false,"thirdPartyCookies":false,"dataExport":true}

# US features
dig get.region-us.features.myapp.v1.resolvedb.net TXT +short
# Response: {"analytics":true,"thirdPartyCookies":true,"dataExport":true}

Key Principle: The client chooses which region's data to fetch. The server never infers region from the client's IP.

Private IP Handling

When looking up private/local IP ranges, the GeoIP service returns a response indicating a private network:

# Looking up a private IP address
dig get.ip-192-168-1-100.geoip.v1.resolvedb.net TXT +short
# Response: v=rdb1;s=ok;t=geo;e=plain;ip=192.168.1.100;cc=--;cn=Private Network;isp=Private

Private IP detection includes:

  • IPv4: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
  • IPv6: fc00::/7 (unique local), fe80::/10 (link-local)
  • Loopback: 127.0.0.0/8, ::1

Caching

  • GeoIP responses use TTL of 300 seconds (5 minutes) by default
  • Since queries require explicit IP parameters, responses are fully cacheable
  • Same query always returns the same result (cache-friendly)
  • No ECS scope fragmentation since location is explicit in query

Privacy Best Practices

For applications handling sensitive data, use multiple layers of protection:

LayerHow to Use
Transport encryptionQuery via DoH (https://dns.google/resolve?name=...) to encrypt in transit
Client-side encryptionEncrypt data with AES-256-GCM before storing; server never sees plaintext
Token privacyUse h-<hash> prefix instead of exposing tokens in DNS query logs
Authenticated namespacesUse organization namespaces (myorg.resolvedb.net) with JWT auth
// Client-side encryption example
const key = await crypto.subtle.generateKey(
  { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, sensitiveData);

// Store encrypted - server never sees plaintext
await resolvedb.put('secrets.api-key.myapp.v1', base64(iv + encrypted));

Best Practices

  1. Explicit parameters - Always provide IP or location, never rely on implicit detection
  2. Cache responses - Default 5-minute TTL works for most use cases
  3. Handle failures - Design for cases where GeoIP data is unavailable
  4. Test anywhere - Same query from CI, staging, or prod returns same result
  5. Encrypt sensitive data - Use client-side encryption for secrets

Complete Example

// GeoIP lookup with explicit IP address
async function lookupGeoIP(ipAddress) {
  // Encode IP for DNS query (dots -> hyphens)
  const encodedIp = ipAddress.replace(/\./g, '-');
  const query = `get.ip-${encodedIp}.geoip.v1.resolvedb.net`;

  const response = await dnsQuery(query);
  return parseGeoResponse(response);
}

// Location-aware configuration with explicit region
async function getRegionalConfig(region) {
  const query = `get.region-${region}.config.myapp.v1.resolvedb.net`;
  const response = await dnsQuery(query);
  return parseUqrpResponse(response);
}

// Parse UQRP response format
function parseUqrpResponse(response) {
  const dataMatch = response.match(/d=(.+)$/);
  if (dataMatch) {
    return JSON.parse(dataMatch[1]);
  }
  throw new Error('Invalid UQRP response');
}

// Usage: Client explicitly provides the IP they want to look up
const geoInfo = await lookupGeoIP('8.8.8.8');
console.log(`IP ${geoInfo.ip} is in ${geoInfo.ct}, ${geoInfo.cn}`);
// Output: IP 8.8.8.8 is in Mountain View, United States

// Client explicitly chooses which region's config to fetch
const config = await getRegionalConfig('us');
console.log(`Currency: ${config.currency}`);
// Output: Currency: USD

Next Steps