How do I get accurate location data, like city, region, and country, with server-side updates?

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 hits Mixpanel’s servers. As all server-side calls will likely 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": "72.229.28.185"
    }
}

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:

http://api.mixpanel.com/engage/?data=ew0KICAgICIkdG9rZW4iOiAiZTNiYzQxMDAzMzBjMzU3MjI3NDBmYjhjNmY1YWJkZGMiLA0KICAgICIkZGlzdGluY3RfaWQiOiAiMTM3OTMiLA0KICAgICIkc2V0Ijogew0KICAgICAgICAiQWRkcmVzcyI6ICIxMzEzIE1vY2tpbmdiaXJkIExhbmUiDQogICAgfQ0KfQ==&ip=0

This will force 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": "72.229.28.185",
    "$set": {
        "Address": "1313 Mockingbird Lane"
    }
}

Notice that you need to set “$ip” outside of the “$set” dictionary. This will overwrite 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, { 
$email: req.session.user.email, 
$first_name: req.session.user.name, 
$created: req.session.user.date, 
ip: req.param('ip') 
});