Tracking Geolocation with Server-Side Implementation

Mixpanel’s client-side libraries send certain properties (like location data) automatically. However, it is still possible to store users’ location data when sending server-side updates.

Geolocation data ($city, $region, mp_country_code) is actually set from the IP address on the incoming request when data connects to Mixpanel’s servers.

As all server-side calls will originate from the same IP (that is, the IP of your server) this can have the unintended effect of setting the location of all of your users to the location of your datacenter.

Geolocation and events

Here’s an example event call to our REST API that will send an event (Level Complete) with a single property (Level Number).

The REST API won’t do any geolocation by default (as it assumes you’re sending these calls server-side), though you can force it to by sending in a property called “ip.”

This request will use the value sent with the “ip” parameter for geolocation, so this event will appear to have come from New York:

    "event": "Level Complete",
    "properties": {
        "Level Number": 9,
        "distinct_id": "13793",
        "token": "e3bc4100330c35722740fb8c6f5abddc",
        "time": 1409259110,
        "ip": ""

Geolocation and People Profile Updates

People profile updates present more issues with geolocation because they are often batch-updated server side or over the REST API. But calls to engage assume that you want to use the IP address of the request if no IP property is given.

As a result, calls will appear to have come from wherever the machine that generated the request is located. In other words, each user would appear to be located wherever the server sending the requests is located. You can override this behavior by including “ip=0” as a URL parameter, for example:

This action forces Mixpanel to ignore the IP on the request, leaving the geolocation information untouched so that it will reflect whatever was previously set with another library instead of overwriting it.

Pass in Your Own IP Address (Javascript/HTTP)

If you want to pass in your own IP address similar to the way you can with track, leave out the URL paramenter “ip=,” and add a property called “$ip” to the message payload:

    "$token": "e3bc4100330c35722740fb8c6f5abddc",
    "$distinct_id": "13793",
    "$ip": "",
    "$set": {
        "Address": "1313 Mockingbird Lane"

Notice that you need to set “$ip” outside of the “$set” dictionary. This action overwrites the geographic data on the profile with distinct_id = 13793 with New York, NY.

Pass in Your Own IP Address (Node.js)

If you want to pass in your own IP address similar to the way you can with track, leave out the ip= URL parameter, and add a property called “ip” to the message payload:

mixpanel.people.set(req.session.user._id, { 
ip: req.param('ip') 

Ignore Last Seen

The “$last_seen” property reflects the timestamp of the last update to any people property, so server-side calls will also overwrite and result in all your users showing the same timestamp for Last Seen). To avoid an overwrite, add in the “$ignore_time” property to the people call.

"$token": "e3bc4100330c35722740fb8c6f5abddc",
   "$distinct_id": "13793",
   "$ip": "",
   "$ignore_time": "true",
   "$set": {
       "Address": "1313 Mockingbird Lane"

This request updates the profile without updating “$last_seen” (To be safe, all server-side updates to people records should ignore time.)

Force the IP and Last Seen

All Mixpanel server-side libraries have parameters that allow you to force the IP and “last seen” behavior you want. Here is an example in Ruby:

def set(distinct_id, properties, ip=nil, optional_params={})

Uses the IP in the Property for Geo-location

tracker.people.set('Drew', {'$first_name' => 'Drew'}, '')

Does not Geo-locate

tracker.people.set('Drew', {'$first_name' => 'Drew'}, '0')
tracker.people.set('Drew', {'$first_name' => 'Drew'}, 0)

Geo-locates from the IP on the Request

tracker.people.set('Drew', {'$first_name' => 'Drew'}, nil)
tracker.people.set('Drew', {'$first_name' => 'Drew'})

You can ignore time by passing “$ignore_time” => “true” into the optional_params dict:

Does not Geo-locate or update “$last_seen

tracker.people.set('Drew', {'$first_name' => 'Drew'}, 0, {'$ignore_time' => 'true'}
Is this article helpful?
7 out of 18 found this helpful



Article is closed for comments.