Using Cloudflare Geolocation Headers Instead of a Local Database
Applies to SlimStat 5.5.0 and SlimStat Pro 2.0.0 · checked
SlimStat reads the visitor country from Cloudflare’s CF-IPCountry request header when Geolocation Provider is set to Cloudflare Header, so no GeoIP database file is stored on your server. The site must be proxied through Cloudflare: CloudflareGeolocationProvider::locate() returns null unless the same request also carries a CF-Ray header.
| Geolocation Provider | Local database file | License key | Resolves an arbitrary IP |
|---|---|---|---|
| Cloudflare Header | None | Not required | No, current request only |
| DB-IP City Lite (free) | wp-content/uploads/wp-slimstat/ | Not required | Yes |
| MaxMind GeoLite2 (recommended) | wp-content/uploads/wp-slimstat/ | Required | Yes |
| Disabled | None | Not required | No country recorded |
All four options ship in the free plugin, and fresh installs default to DB-IP. Cloudflare Header is the only enabled provider that needs no file on disk, which is why the Geolocation Database row, with its Update Database and Check Database buttons, hides itself the moment you select it.
Enable IP Geolocation in Cloudflare First
Cloudflare sends CF-IPCountry only when IP Geolocation is enabled in the Cloudflare dashboard and the request genuinely passes through the Cloudflare proxy. City-level fields need a second switch, the Add visitor location headers Managed Transform, under Rules > Transform Rules > Managed Transforms. Without that transform, only country is available.
SlimStat checks the proxy before trusting any value. CloudflareGeolocationProvider::locate() builds a lowercased copy of $_SERVER, returns null when HTTP_CF_RAY is missing or empty, and only then reads the location headers. A staging copy of the site that answers requests directly, bypassing Cloudflare, therefore records no country at all even with Cloudflare Header selected.
Select the Cloudflare Header Provider
The Geolocation Provider select lives at SlimStat > Settings > Tracker, inside the Third-party Libraries section. Picking Cloudflare Header stores geolocation_provider as cloudflare and syncs the legacy enable_maxmind flag to no, and because Cloudflare is not one of the two database providers, saving schedules no background download.
- Open SlimStat > Settings > Tracker in the WordPress admin.
- Scroll to Third-party Libraries and set Geolocation Provider to Cloudflare Header.
- Ignore the MaxMind License Key field, which hides itself for this provider.
- Leave Geolocation Precision, under Advanced Options on the same tab, on Country.
- Switch that toggle to City only when the Add visitor location headers Managed Transform is active.
- Click Save Changes.
Which Headers SlimStat Reads and Stores
Three values reach the wp_slim_stats table: country VARCHAR(16), city VARCHAR(256) and location VARCHAR(36). CF-IPCountry fills country, lowercased. CF-Region is appended to the city in parentheses, and latitude plus longitude are joined with a comma into location. Two further headers are read and then dropped.
| Cloudflare header | PHP $_SERVER key | Stored in wp_slim_stats |
|---|---|---|
| CF-IPCountry | HTTP_CF_IPCOUNTRY | country, lowercased |
| CF-IPCity | HTTP_CF_IPCITY | city, at City precision only |
| CF-Region | HTTP_CF_REGION | Appended to city in parentheses |
| CF-IPLatitude, CF-IPLongitude | HTTP_CF_IPLATITUDE, HTTP_CF_IPLONGITUDE | location, as latitude,longitude |
| CF-Postal-Code | HTTP_CF_POSTAL_CODE | Not stored |
| CF-IPContinent | HTTP_CF_IPCONTINENT | Not stored |
City, region, latitude and longitude are read only when Geolocation Precision is set to City. At the default Country setting the provider returns no city-level fields at all, so the city and location columns stay empty no matter which Managed Transforms are enabled in Cloudflare.
How the Country Code Is Validated
SlimStat validates the header before storage: a country survives only if it matches /^[A-Z0-9]{2}$/ after uppercasing, so the XX placeholder is discarded and any longer string is rejected. Cloudflare’s T1, A1 and A2 codes, for Tor, anonymous proxy and satellite, pass that check and are kept.
The country check shipped in version 5.5.0 on 24 June 2026, after a stored XSS reported via WPScan: a crafted CF-IPCountry header could previously be saved as a visitor country and run script when an administrator opened the Audience or Access Log report. Reports draw each country as a 16-pixel SVG from /admin/assets/images/flags/, falling back to /admin/assets/images/unk.png when no matching file exists.
Verify the Country Is Being Recorded
Two reports show the result. Top Countries appears on the Overview, Audience and Traffic Sources screens; the Access Log appears on Real-time. The flag falls back to unk.png whenever the stored code has no matching SVG in that folder, which covers both an empty country — pointing back at the CF-Ray check or the consent gate — and the T1, A1 and A2 codes, which ship no flag file of their own.
- Set Geolocation Provider to Cloudflare Header and click Save Changes.
- Load any page on the proxied domain from a device your exclusion filters do not skip.
- Open SlimStat > Real-time and look at the newest Access Log row for a flag.
- Open SlimStat > Audience and confirm Top Countries lists that same country.
- Repeat over the live hostname if the first attempt bypassed the Cloudflare proxy.
Limits Worth Knowing Before Switching
Cloudflare Header resolves the current request only, so it cannot look up an arbitrary test IP such as 8.8.8.8 the way DB-IP and MaxMind can. In SlimStat Pro, the Advanced Whois panel refuses to run under this provider for that reason and asks you to switch to MaxMind or DB-IP.
Geolocation also runs behind the consent gate in src/Tracker/Processor.php, which calls the lookup only when Consent::piiAllowed() returns true, so a pageview can be stored with no country while Cloudflare Header is selected. With Respect Do Not Track (DNT) enabled, a DNT: 1 request is refused earlier still and no pageview is recorded at all. For provider comparison see setting up visitor geolocation, for blank values see fix missing or wrong country codes, and for a silent tracker see the diagnostic checklist.