> This page is part of the [Customer.io documentation](https://docs.customer.io). For the complete index, see [llms.txt](https://docs.customer.io/llms.txt).
> Last updated: October 26, 2026
> To take actions in Customer.io from an agent, use the [Customer.io CLI](https://docs.customer.io/ai/cli/get-started.md) or the [MCP server](https://docs.customer.io/ai/mcp/get-started.md).
> This page has tabbed examples for: Node.JS SDK, Go SDK, Python SDK. Add `?tab=<name>` to the URL to get only that tab, and repeat it for more than one, for example `?tab=node-js-sdk&tab=go-sdk`.

# Geolocation & time zone data

Customer.io can gather geolocation and time zone data from your audience, helping you coordinate messages at times that are appropriate for them.

## How it works

Customer.io determines a person’s location from two possible sources:

*   **IP-based geolocation**: We infer location from IP addresses. This happens when you identify someone from a [supported source](#sources-that-support-ip-based-geolocation).
*   **Mobile device-based geolocation**: Our mobile SDKs ([iOS](https://docs.customer.io/integrations/sdk/ios/tracking/location/), [Android](https://docs.customer.io/integrations/sdk/android/tracking/location/), [Flutter](https://docs.customer.io/integrations/sdk/flutter/tracking/location/), [React Native](https://docs.customer.io/integrations/sdk/react-native/tracking/location/), and [Expo](https://docs.customer.io/integrations/sdk/expo/tracking/location/)) can capture GPS coordinates directly from a person’s device. This is more accurate than web-based geolocation.

We store one canonical location per person. When both sources are available, **device-based location takes precedence** because it’s more precise. The `cio_location_source` attribute on a person tells you which source provided their current location—`ip` or `device`.

You can use geolocation data to segment your audience by location or time zone. You can also use time zone data to send messages at the right time for your audience with our [recommended send time](https://docs.customer.io/messaging/send/timezones/recommended-send-time/) feature or our [time zone match](https://docs.customer.io/messaging/send/timezones/match/) features.

### IP-based geolocation

IP-based geolocation is the default source of geolocation data because we have more sources of IP address than we do for mobile device coordinates. When you enable *Automatic Geolocation Data Collection* and identify someone with a `context.ip` field, we look up their approximate location using MaxMind’s GeoIP database. Our [JavaScript client](https://docs.customer.io/integrations/data-in/connections/javascript/) and [mobile SDKs](https://docs.customer.io/integrations/sdk/) capture IP addresses automatically; you need to pass `context.ip` manually with [server-side libraries](#enable-or-disable-geolocation-for-server-side-libraries) and the [Pipelines API](https://docs.customer.io/integrations/api/cdp/).

IP-based location is accurate to roughly a city or region. That’s enough to set a person’s time zone, segment people by country or region, and localize content. It isn’t precise enough to target people at a specific address or store. For that, use [device-based geolocation](#device-based-geolocation-mobile-sdks) or our [geofencing feature](https://docs.customer.io/messaging/people/location/geofences/).

#### Sources that support IP-based geolocation

Geolocation works based on `identify` calls from the sources below. We ignore the IP address in `context.ip` when you identify someone from any other source, including sources that connect third-party tools. Every request has an IP address, but for most sources it’s the IP address of the server that sent the request, not your person’s IP address.

For sources with automatic collection, we use the IP address you pass in `context.ip`. If you don’t pass one, we use the IP address of the request, which comes from your person’s browser or device.

Source

IP collection

Additional requirements

[JavaScript client](https://docs.customer.io/integrations/data-in/connections/javascript/)

Automatic

[iOS SDK](https://docs.customer.io/integrations/sdk/ios/quick-start-guide/)

Automatic

[Android SDK](https://docs.customer.io/integrations/sdk/android/quick-start-guide/)

Automatic

[React Native SDK](https://docs.customer.io/integrations/sdk/react-native/quick-start-guide/)

Automatic

[Flutter SDK](https://docs.customer.io/integrations/sdk/flutter/quick-start-guide/)

Automatic

[Expo plugin](https://docs.customer.io/integrations/sdk/expo/quick-start-guide/)

Automatic

[Node.js library](https://docs.customer.io/integrations/data-in/connections/servers/node/)

Manual

Pass `context.ip` in your `identify` calls and [turn on **Enable geolocation**](#enable-or-disable-geolocation-for-server-side-libraries) for the source.

[Go library](https://docs.customer.io/integrations/data-in/connections/servers/go/)

Manual

Pass `context.ip` in your `identify` calls and [turn on **Enable geolocation**](#enable-or-disable-geolocation-for-server-side-libraries) for the source.

[Python library](https://docs.customer.io/integrations/data-in/connections/servers/python/)

Manual

Pass `context.ip` in your `identify` calls and [turn on **Enable geolocation**](#enable-or-disable-geolocation-for-server-side-libraries) for the source.

[Customer.io Pipelines API](https://docs.customer.io/integrations/api/cdp/)

Manual

Pass `context.ip` in your `identify` calls and [turn on **Enable geolocation**](#enable-or-disable-geolocation-for-server-side-libraries) for the source.

### Device-based geolocation (mobile SDKs)

Our mobile SDKs can provide GPS-level accuracy by capturing coordinates directly from a person’s device. This is more accurate than IP-based geolocation, which can only approximate location to a city or region.

Device-based location reaches a person through two pathways:

1.  **Identify calls**: When a mobile SDK sends an identify call with the Location module enabled, it includes GPS coordinates alongside the IP address. We check device coordinates first—if they’re present, we use them instead of the IP address.
2.  **Location Update events**: Mobile SDKs can send a `Location Update` track event with latitude and longitude. This updates the person’s geolocation attributes.

To set up device-based location tracking, see the location tracking guides for your platform:

*   [iOS](https://docs.customer.io/integrations/sdk/ios/tracking/location/)
*   [Android](https://docs.customer.io/integrations/sdk/android/tracking/location/)
*   [Flutter](https://docs.customer.io/integrations/sdk/flutter/tracking/location/)
*   [React Native](https://docs.customer.io/integrations/sdk/react-native/tracking/location/)
*   [Expo](https://docs.customer.io/integrations/sdk/expo/tracking/location/)

To message people when they enter or leave an area, like a store or a venue, use our [geofencing feature](https://docs.customer.io/messaging/people/location/geofences/). Our mobile SDKs monitor geofences on the device and send an event when a person enters or exits one, which you can use to trigger an automation. See the geofencing guide for [iOS](https://docs.customer.io/integrations/sdk/ios/tracking/geofencing/), [Android](https://docs.customer.io/integrations/sdk/android/tracking/geofencing/), [Flutter](https://docs.customer.io/integrations/sdk/flutter/tracking/geofencing/), [React Native](https://docs.customer.io/integrations/sdk/react-native/tracking/geofencing/), or [Expo](https://docs.customer.io/integrations/sdk/expo/tracking/geofencing/).

### Location precedence

We only store one set of location values per person. When we receive new location data, we compare it to the existing data and apply the following rules:

Device location is sticky

When valid device coordinates are present, we skip IP geolocation entirely—even if the device location wasn’t updated because the person hasn’t moved more than 1 km. The device source is preserved. This prevents less-accurate IP data from overwriting precise GPS coordinates.

When the source changes (for example, from `ip` to `device`), we rewrite all geolocation attributes to clear stale values from the previous source.

## Enable or disable automatic geolocation data collection

Enabling *Automatic Geolocation Data Collection* lets us gather and set location and time zone data for people you identify based on their IP addresses or device GPS coordinates. This setting is on by default in our US data center. If you’re in our EU data center, you’ll need to enable it manually.

1.  Go to [*Workspace Settings > Time Zone & Geolocation Settings*](https://fly.customer.io/workspaces/last/settings/actions/time_zone_match).
2.  Enable or disable **Automatic Geolocation Data Collection**.

 ![Automatic Geolocation Data Collection settings](https://docs.customer.io/images/automatic-geolocation-settings.png)

Note that turning this setting on doesn’t:

*   Enable geolocation for server-side libraries. You’ll need to [enable geolocation for server-side libraries](#enable-or-disable-geolocation-for-server-side-libraries) manually.
*   Backfill data for existing people. You’ll need to [identify people](#we-geolocate-people-when-you-identify-them) from our JavaScript client or mobile SDKs to get their geolocation data.

### Enable or disable geolocation for server-side libraries and the Pipelines API

To support geolocation for server-side libraries (our [Node.JS](https://docs.customer.io/integrations/data-in/connections/servers/node/), [Go](https://docs.customer.io/integrations/data-in/connections/servers/go/), and [Python](https://docs.customer.io/integrations/data-in/connections/servers/python/) libraries) and the [Pipelines API](https://docs.customer.io/integrations/api/cdp/), you’ll need to enable geolocation services. Then you’ll need to capture your users’ IP addresses and set them in the `context.ip` field in your `identify` requests.

1.  Go to **Integrations**.
2.  Go to your Node.JS, Go, Python, or Customer.io API source and click the **Settings** tab.
3.  Change the **Enable geolocation** setting.

Make sure you capture your users' IP addresses

If you don’t set the `context.ip` in your requests, we won’t be able to capture geolocation data for your users. If our libraries infer the address as your server’s IP address, it’ll look like everyone is in the same location as your server.

### Capturing IP addresses for geolocation

Automatic geolocation is based on the `context.ip` field in `identify` requests, and only [the sources listed above](#sources-that-support-ip-based-geolocation) support it. We automatically capture IP addresses from our [mobile SDKs](https://docs.customer.io/integrations/sdk/) or [JavaScript client](https://docs.customer.io/integrations/data-in/connections/javascript/).

If you use our backend libraries (like our Node.JS or Go SDKs) or our [Pipelines API](https://docs.customer.io/integrations/api/cdp/), you’ll have to capture the IP address yourself and pass it in the `context.ip` field in your `identify` requests. We’ve added some examples below showing the `context.ip` field in your `identify` requests to our backend SDKs.

SDK/Integration

context.ip field

[JavaScript client](https://docs.customer.io/integrations/data-in/connections/javascript/)

Automatic

[Mobile: iOS](https://docs.customer.io/integrations/sdk/ios/)

Automatic

[Mobile: Android](https://docs.customer.io/integrations/sdk/android/)

Automatic

[Mobile: React Native](https://docs.customer.io/integrations/sdk/react-native/)

Automatic

[Mobile: Flutter](https://docs.customer.io/integrations/sdk/flutter/)

Automatic

[Mobile: Expo](https://docs.customer.io/integrations/sdk/expo/)

Automatic

[Node.JS SDK](https://docs.customer.io/integrations/sdk/nodejs/)

Manual

[Go SDK](https://docs.customer.io/integrations/sdk/go/)

Manual

[Python SDK](https://docs.customer.io/integrations/sdk/python/)

Manual

[Pipelines API](https://docs.customer.io/integrations/api/cdp/)

Manual

<!-- tabs -->

<!-- tab: Node.JS SDK -->

#### Node.JS SDK

```
cioanalytics.identify({
  userId: '019mr8mf4r',
  traits: {
    name: 'Cool Person',
    email: 'cool.person@example.com',
    plan: 'Enterprise',
    friends: 42
  },
  context: {
    ip: '123.45.67.89'
  }
});
```

<!-- /tab -->

<!-- tab: Go SDK -->

#### Go SDK

```
func main() {
    client := analytics.New(os.Getenv("WRITE_KEY"))

    client.Enqueue(analytics.Identify{
        UserId: "user123",
        Traits: analytics.NewTraits().
            SetEmail("john@example.com").
            SetName("John Doe"),
        Context: &analytics.Context{
            IP: net.ParseIP("192.168.1.100"),
        },
    })
}
```

<!-- /tab -->

<!-- tab: Python SDK -->

#### Python SDK

```
cioanalytics.identify('f4ca124298', {
    'email': 'cool.person@example.com',
    'first_name': 'cool',
    'last_name': 'person',
    'context': {
        'ip': '123.45.67.89'
    }
})
```

<!-- /tab -->

<!-- /tabs -->

### What happens to data when you disable automatic geolocation data collection?

When you disable automatic geolocation data collection, we’ll stop gathering location and time zone data for people you identify. You can also choose to delete existing geolocation data for people you’ve already identified.

 ![Delete geolocation data](https://docs.customer.io/images/automatic-geolocation-disable.png)

If you disable automatic geolocation data collection, there’s no harm in keeping this data around. But it might clutter people’s profiles if you don’t use this data.

## We geolocate people when you identify them

We don’t add or update geolocation data until you identify someone with a `context.ip` field or device GPS coordinates in the same request, from a [source that supports geolocation](#sources-that-support-ip-based-geolocation). Remember, our [mobile SDKs](https://docs.customer.io/integrations/sdk/) and [JavaScript client](https://docs.customer.io/integrations/data-in/connections/javascript/) automatically capture IP addresses for you, but you’ll need to capture the IP address yourself if you use our backend libraries (like our Node.JS or Go SDKs) or our [Pipelines API](https://docs.customer.io/integrations/api/cdp/) directly.

Even if you’ve already identified someone, additional identify requests can update a person’s geolocation data.

Identify people in new sessions to keep geolocation data up to date

Your website and mobile app might “remember” users across sessions. But, even if you don’t need to update any information about them, you should identify them again in a new session to keep their geolocation data up to date. This can help you keep up with people as they move around the world.

### Automatic geolocation attributes

When you enable automatic geolocation data collection, we automatically capture the following attributes when you identify someone.

You shouldn’t set these attributes yourself. If you do, it’s likely that we’ll overwrite your data with our own values whenever you identify a person.

Attribute

Purpose

Editable

Data Format

`cio_city`

City name.

No, system-generated

String

`cio_continent`

Continent name, like `North America`.

No, system-generated

String

`cio_country`

Country name, like `United States`.

No, system-generated

String

`cio_iso_continent`

ISO continent code, like `NA` for North America.

No, system-generated

String

`cio_iso_country`

ISO 3166-1 alpha-2 country code, like `US`.

No, system-generated

String

`cio_iso_region`

ISO region code, like `CA` for California.

No, system-generated

String

`cio_latitude`

Latitude of the person’s location. For IP-based geolocation, this is the approximate latitude of the city. For device-based geolocation, this is the precise GPS latitude.

No, system-generated

Decimal degrees

`cio_location_source`

Which source provided the person’s current location: `ip` (IP address lookup) or `device` (mobile SDK GPS coordinates).

No, system-generated

String: `ip` or `device`

`cio_longitude`

Longitude of the person’s location. For IP-based geolocation, this is the approximate longitude of the city. For device-based geolocation, this is the precise GPS longitude.

No, system-generated

Decimal degrees

`cio_postal_code`

Postal or ZIP code, approximated from the IP address. It may not be exact.

No, system-generated

String

`cio_region`

Region name, like `California`. Usually a state, province, or administrative division.

No, system-generated

String

`cio_timezone`

The person’s time zone. Customer.io uses it for [recommended send time](https://docs.customer.io/messaging/send/timezones/recommended-send-time/) and as a fallback when `timezone` isn’t set.

No, system-generated

String, [region format](https://docs.customer.io/messaging/send/timezones/example-timezones/#region-format)

Additional fields added November 17, 2025

If you identified someone before November 17, 2025, their geolocation attributes won’t include `cio_iso_continent`, `cio_continent`, `cio_iso_region`, `cio_region`, or `cio_postal_code`. The next time you identify them with their IP address, we’ll automatically add the additional fields.

## The `timezone` attribute

You can set the `timezone` attribute (in a [recognized format](https://docs.customer.io/messaging/send/timezones/example-timezones/)) to support our [recommended send time](https://docs.customer.io/messaging/send/timezones/recommended-send-time/) feature or our [time zone match](https://docs.customer.io/messaging/send/timezones/match/) features. This attribute takes precedence over our `cio_timezone` attribute. You should set it if:

*   You don’t use automatic geolocation data collection and you want to support recommended send times or time zone match features.
*   You identify people from sources that [don’t support IP-based geolocation](#sources-that-support-ip-based-geolocation), like sources that connect third-party tools.
*   You want to set a “home” time zone for people who frequently travel across multiple time zones.

When you send someone a message using a time zone-related feature, we’ll use the `timezone` attribute if it exists and conforms to our [supported formats](https://docs.customer.io/messaging/send/timezones/example-timezones/). If it doesn’t exist, we’ll use the `cio_timezone` attribute as a fallback.

If the `timezone` and `cio_timezone` attributes don’t exist, we’ll use the fallback time zone that you set for a message. This ensures that people who don’t have time zone data still get messages.

### Test your `timezone` attribute

If you set your time zone attribute manually, you can test it to make sure that you’re using [a format we support](https://docs.customer.io/messaging/send/timezones/example-timezones/).

Go to [*Workspace Settings > Time Zone & Geolocation Settings*](https://fly.customer.io/workspaces/last/settings/actions/time_zone_match).

Enter the `id` or email address of a person in your workspace, and we’ll tell you if the `timezone` attribute is in the correct format.

![Testing the Time Zone Match feature](https://docs.customer.io/images/time_zone_match_testing.gif)
