Location data
How Intempt derives country, region, and city from a connection at ingestion, the three ways to set location yourself, and why the IP address is never stored.
Overview
Intempt tags events and profiles with the location they came from, so you can segment and report by geography without collecting anything extra.
Location is derived from the connection the request arrived on. The IP address is used to look up a country, region and city, then discarded before the record is stored. Intempt never keeps it, never lets you query it, and never includes it in an export.
How it works
What gets attached
Three location properties are set on events, and the same three on user profiles:
| Property | Description |
|---|---|
country | Country the request came from |
region | State, province or equivalent |
city | City |
They behave like any other property: filter on them, group by them, use them as segment conditions.
📘 Good to know
Intempt uses Intempt-native property names rather than the $-prefixed convention some analytics tools use. country, region and city are the same reserved attributes that already exist on the customer profile, so location set by ingestion and location you map from a source land in the same place.
Order of operations
This is the exact sequence, and the fifth step is the one that matters:
- A request arrives at the ingestion API.
- Intempt reads the connection's IP address.
- The address is looked up against a geolocation database Intempt hosts. No outside service is contacted, and no request leaves Intempt.
- Country, region and city are attached to the event or profile.
- The IP address is discarded. It does not enter the queue, the store, or any export.
- The record continues to ingestion carrying location and no address.
Profiles and events are timestamped differently
An event's location is fixed at the moment it was captured. A profile's location is rewritten every time you update the profile.
So a user who signs in from Berlin and then travels shows Berlin on their profile until something updates it, while their events show wherever each one happened. The two disagreeing is expected, not a bug.
Location is never derived for opted-out users
A user who has called optOut() isn't collected from at all, so no location is derived and nothing is looked up. See Protecting user data.
Setting location yourself
The derived value is a fallback. Anything you send explicitly wins.
There are three ways to set it, in the order Intempt prefers them.
1. Send the properties directly
The most precise option, and the one to use when your own systems already know where a customer is.
{
"event": "Subscription started",
"properties": {
"country": "United States",
"region": "Texas",
"city": "Austin",
"plan": "growth"
}
}The same properties work on a profile update.
📘 Good to know
If your CRM or billing system holds each customer's address, that's a better source than anything inferred from a network connection. Map it once and it stays correct even when someone travels or uses a VPN.
2. Send coordinates
If you have latitude and longitude, send them as floating-point decimal degrees and Intempt resolves the nearest city.
{
"event": "Store visit",
"properties": {
"latitude": 30.27,
"longitude": -97.74
}
}Records resolved this way carry geo_source: "reverse_geocoding", so you can tell them apart from network-derived values later.
Coordinate resolution runs server-side only. It isn't available from the client SDKs.
3. Send the address yourself
When you track from your backend, every request arrives from your servers. Left alone, that would put all of your users in your data center's city.
Pass the end user's address instead, and Intempt looks that up rather than the connection:
{
"event": "Invoice paid",
"properties": {
"ip": "203.0.113.7"
}
}The address you pass is discarded after lookup exactly like a connection address. It is never stored.
Most frameworks expose the client address directly:
| Framework | Where |
|---|---|
| Django | request.META['REMOTE_ADDR'] |
| Flask | request.remote_addr |
| Go | http.Request.RemoteAddr |
| Node (Express) | req.socket.remoteAddress |
| Nginx | $remote_addr |
Turning location off
For one record
Set ip to 0 and Intempt skips the lookup. No location is attached.
{
"event": "Batch import",
"properties": {
"ip": "0"
}
}For a whole request
Append ip=0 to the request URL and every record in that request skips the lookup.
For everything
Disable it when you initialize the SDK.
intempt.init('YOUR_PUBLIC_KEY', { location: false });Nothing is looked up, nothing is attached, and no address is read.
FAQ
Why does a profile's location differ from that user's recent events?
They're set at different times. An event's location is fixed when the event was captured. A profile's location is rewritten whenever the profile is updated.
Someone who signs in from Berlin and then travels keeps Berlin on their profile until something updates it, while their events show wherever each one happened. The two disagreeing is expected.
A user is definitely in one country but shows up in another. Why?
Network location is an approximation. VPNs, corporate proxies and privacy browsers all present a connection from somewhere other than where the person is, and there's no way to tell from the request which is which.
If you know where your customers are, send it. Explicit values always win over anything derived, and your own records are a better source than a network lookup. See Setting location yourself.
Use cases
- Report signups by country without asking users where they are.
- Route a journey by region using location your billing system already holds, mapped rather than inferred.
- Send a campaign in local business hours by segmenting on the city an account's events come from.
- Track from your backend without every user appearing in your data center's city, by passing the client address.
- Import a year of historical events without every one of them being tagged with your import server's location, by setting
ipto0. - Attach precise location for a physical retail event using coordinates from the till system.
- Tell an auditor exactly what happens to an IP address, using the six-step sequence above.
- Turn location off entirely for a project handling sensitive categories where geography isn't worth collecting.
Data attribution
IP Geolocation by DB-IPLocation is resolved against the IP to City Lite database, made available by DB-IP under the Creative Commons Attribution 4.0 International License.
The database is used unmodified. Intempt hosts a copy of each monthly release and resolves against it locally, so this derivation sends no address to DB-IP or anyone else.
That is scoped to the automatic location described on this page. It is not a statement about the product as a whole: IP enrichment is a separate, metered feature. On standard plans it resolves against a GeoIP database Intempt hosts, so no address leaves for that tier either. MaxMind is available as an enterprise add-on. If you enable enrichment, it is billed per lookup.
Where to go next
Manage personal data
Submit, track, download, and cancel data subject requests through the Intempt API: endpoints, request types, identity formats, and error responses.
Blocking unwanted traffic
Keeping bots, crawlers, and your own team's testing out of your analytics: what Intempt filters automatically, and how to exclude internal traffic yourself.
