Locale Map

Detects mismatches between the Accept-Language header and the visitor's geolocation country.

The locale map checker compares the Accept-Language header against the visitor's IP geolocation. Real browsers send a language preference that matches the country where the user is located. Bots and automated scripts commonly hardcode a generic locale (en-US, *, or none at all) regardless of where the request originates.

This is a cheap-phase checker. It reads geolocation data that was already resolved from the MMDB database and inspects a header. No additional I/O is needed.


How It Works

The checker parses the Accept-Language header according to RFC 7231, extracting the language tag with the highest quality value (q-factor). It then extracts the language code and optional region subtag from that tag.

The resolved geolocation provides a country ISO code and an ISO 639 language code for that country. The checker compares the two values. A mismatch between the declared locale and the geo-resolved country applies the ipAndHeaderMismatch penalty.

The checker also penalizes independently for:

  • Missing header: the Accept-Language header is absent entirely.
  • Missing geo data: the geolocation lookup returned no country or language data for the IP.
  • Malformed header: the header value does not conform to the locale tag format.

Configuration

server.ts
await defineConfiguration({
  store: { main: { driver: 'sqlite', name: './bot-detector.db' } },
  checkers: {
    localeMapsCheck: {
      enable: true,
      penalties: {
        ipAndHeaderMismatch: 20,
        missingHeader: 20,
        missingGeoData: 20,
        malformedHeader: 30,
      },
    },
  },
})

All weights live inside the penalties: {} sub-object.

ipAndHeaderMismatch
number
Penalty when the Accept-Language locale does not match the geolocation country and language. Default: 20.
missingHeader
number
Penalty when the request carries no Accept-Language header. Default: 20.
missingGeoData
number
Penalty when the geolocation database returns no country or language data for the client IP. Default: 20.
malformedHeader
number
Penalty when the Accept-Language header value does not conform to the expected locale tag format. Default: 30.

Reason Codes

CodeTrigger
LOCALE_MISMATCHThe Accept-Language locale does not align with the geolocation country. Also applied for missing header, missing geo data, or malformed header.

This checker produces a moderate penalty by default (20). It contributes most value when combined with other cheap-phase signals such as proxy detection or missing headers. Visitors using VPNs may legitimately trigger this check because their IP resolves to a different country than their browser locale.
If your application serves a global audience with many VPN users, consider lowering ipAndHeaderMismatch and keeping malformedHeader at its default. Malformed locale headers are a much stronger bot signal than simple country/language mismatches.
Logo