Free and Lightning-Fast IP Geolocation From a CDN Provider

Illustration of a person with an orange scarf holding a map, surrounded by various other maps including geographical and treasure maps. Some maps display location markers.
Last updated: | Published:
Illustration of a person with an orange scarf holding a map, surrounded by various other maps including geographical and treasure maps. Some maps display location markers.

Content Delivery Networks (CDNs) were traditionally used to cache content closer to users, improving download speeds and reducing the load on primary backend servers.

However, a small revolution is happening at CDN edge servers. By routing your traffic through these lightning-fast CDN proxies, you can perform additional tasks directly at the edge. This includes enhancing requests or even fully processing them without involving your backend servers, significantly improving performance and reducing server load. I'd like to bring a bit more awareness to these additional features, that might be of even bigger value than the original caching purpose of CDN services.

In this article, we'll focus on IP-based geolocation using CDNs. Previously, services like mkdev.me and claimora.com relied on third-party IP geolocation providers to identify visitor locations by country and region. We either used a third-party API, like ipinfo.io, or, when performance was a bit more critical for the use case, local geolocation databases, from MaxMind.

Performing an API request to another service requires careful consideration - we don't want to do it synchronously, when the visitor hits our pages, and we don't want to constantly shift this to background jobs. Querying local maxmind database is not significantly better, except that is faster, of course. Also, while both approaches provide a generous free tier, at some point you do have to pay for this.

Now, let's think who else, besides those geolocation api providers, is very good at determining user locations? As it happens, today, any decent CDN provider is capable of just giving you this information by passing a number of HTTP Headers to your backends.

Configuring visitor location headers in CloudFlare

Please do it via Terraform, don't do ClickOps more than you should!

To enable IP geolocation headers in CloudFlare, navigate to "Rules" → "Settings" and activate the "Add visitor location headers" Managed Transform feature.

Table of HTTP request headers with options for adding TLS client auth headers, visitor location headers, removing visitor IP headers, etc. The "Add visitor location headers" row is highlighted and enabled, adding location details to headers, including city, country, longitude, and latitude.

You also need to go to Network menu and toggle that IP Geolocation setting.

"Screenshot of an IP Geolocation setting section, showing text about including visitor country codes with requests and a green toggle switch turned on. Includes a note about retrieving IP Geolocation from the CF-IPCountry HTTP header, with API and Help links."

After doing this, CloudFlare is going to send a number of location-specific headers to your origins. You can then use these headers for any kind of backend logic, analytics and so on. Here is an example of doing this with Ahoy gem, beautiful library for simple event analytics in Ruby / Rails applications:

class Ahoy::Store < Ahoy::DatabaseStore
  def track_visit(data)


    if request.present?
      data[:country] = request.headers["cf-ipcountry"]
      data[:region] = request.headers["cf-ipregion"]
      data[:city] = request.headers["cf-ipcity"]
    end

    super(data)
  end


end

There is no need for any additional libraries or integrations on your backend - CDN takes care of IP geolocation for you, and it does it really fast.

Configuring visitor location headers in Amazon CloudFront

To send geolocation headers from Amazon CloudFront to your origin server, simply select the managed request policy named Managed-AllViewerAndCloudFrontHeaders-2022-06. This policy automatically includes viewer location headers, device type headers, and more.

Interface for configuring cache key and origin requests, showing options for cache policy, origin request policy, and response headers policy. Selected cache policy is "CachingOptimized" and origin request policy "AllViewerAndCloudFrontHeaders-2022-06," with options to create or view policies.

The only job of your backend servers is to fetch these headers and process them as you wish. In our case, it looks like this:

class Ahoy::Store < Ahoy::DatabaseStore
  def track_visit(data)

    if request.present?
      data[:country] = request.headers["CloudFront-Viewer-Country-Name"]
      data[:region] = request.headers["CloudFront-Viewer-Country-Region"]
      data[:city] = request.headers["CloudFront-Viewer-City"]
    end

    super(data)
  end

Just put a CDN in front!

IP-based geolocation is not exactly precise and tends to work worse on mobile devices. You still need either GPS or more advanced APIs capable of fetching the information of cell towers if you seek precision.

In many, if not most cases, narrowing the request down to the city or even country level is sufficient for analytics and location-restriction or tracking purposes. Placing a modern CDN between your application and your users provides an affordable, reliable, and nearly no-code solution for IP-based geolocation. This approach simplifies analytics, location-based restrictions, and user tracking.

This is just one of many examples, where having a CDN in front of all of your endpoints allows you to enhance your application, but also offload some work to CDN directly. Don't forget to subscribe to mkdev dispatch to learn about new articles in this series.