cat posts/2025-02-11-how-you-get-tracked.md
How you get tracked
Somebody installed a free stacking-blocks game on a spare iPhone, told it not to track, turned off Location Services for every app on the phone, and pointed the traffic through a proxy. Once the game started showing ads, requests went to an ad network with the phone’s IP address, its model, the carrier, the battery level, the screen brightness, how much free disk space he had, and a latitude and longitude in the same postal code as the phone.
That’s from a write-up on timsh.org, “Everyone knows your location”, which Tim posted at the start of the month and which I’ve now sent to about a dozen people. Tim went looking because of the Gravy Analytics breach in January, when someone got into the AWS environment of one of the bigger location data brokers (through what its parent company called a “misappropriated key”) and posted samples that listed thousands of apps whose users’ locations were in there. Some of those apps had never knowingly worked with Gravy. The question Tim wanted answered was how the data got there anyway.
I’ve done some of this sort of poking around, in CTFs and the odd reverse engineering project, and the mechanics aren’t secret. They’re just spread across a lot of industry specs that nobody outside ad tech reads. So this is the picture as I understand it, with one diagram.
The identifiers
To follow you across apps, an ad network needs something that’s the same in each of them. On phones that has mostly been the advertising ID: the IDFA on iOS, and the Google Advertising ID on Android. It’s a random identifier the OS hands to any app that asks, and it was designed for exactly this, so that advertisers could tie an ad you saw in one app to an install in another.
Since iOS 14.5 in 2021, apps have to ask permission (App Tracking Transparency, the “Ask App Not to Track” prompt) before they get the IDFA. Say no and the app gets all zeros. On Android you can delete the ID in settings, and apps get zeros after that.
That’s the part that works. In Tim’s capture, the zeroed IDFA was the only difference between allowing and refusing tracking. Everything else still went: the IDFV (the identifier for vendor, which is the same across all apps from one developer and isn’t covered by the prompt), the IP address, and a long list of device details. Any one of those is a weak identifier. Together, IP plus model plus OS version plus carrier plus time zone is a pretty good fingerprint, especially when the same combination turns up every day from the same two places.
Real-time bidding
The other half is how ads get chosen. When a free app wants to show an ad, the ad SDK inside it (Unity’s, AppLovin’s, Google’s) sends a request to an exchange, and the exchange runs an auction that’s over in something like a tenth of a second. It packages up what it knows about the impression and the device into a bid request and sends that to a lot of buyers at once, the demand-side platforms working for advertisers, who each decide in a few milliseconds whether to bid.
The format most of the industry uses is OpenRTB, and it’s public. A bid request has a device object with fields for the advertising ID (ifa), the IP, the user agent, the make and model, the carrier, and a geo object with lat and lon. The geo object even has a type field saying where the location came from: GPS, IP lookup, or something the user typed. So there’s room in the spec for exactly the coordinates Tim saw, and since the phone had Location Services off and was on Wi-Fi with no SIM, I’d bet his came from an IP lookup, which would explain why they were only accurate to the postal code. Tim suspects that on cellular they’d be much more precise. I don’t know that, but I wouldn’t bet against it either.
The thing to notice in that picture is the fan-out. One bidder wins and shows you an ad for a betting site. Every other bidder also received your IP, your device details and your rough location, and lost. What they do with the request after losing is a matter of contract and policy. Nothing technical stops them keeping it. The industry calls this “bidstream data”, and it’s been an open complaint from privacy regulators in Europe for years. Gravy, according to reporting on the leak, got at least some of its data this way, which is how apps that never signed anything with Gravy ended up in its files.
The second path in the diagram is older and simpler. Some apps embed an SDK whose whole job is to collect location, with the app’s location permission, and pay the developer per active user for it. That’s the weather apps and flashlight apps you’ve read about. It’s the precise, GPS-quality data, and it’s the kind that ended up in the dataset the New York Times wrote up in 2019 as “Twelve Million Phones, One Dataset, Zero Privacy”.
None of this is special to phones, by the way. A web page with ads runs the same kind of auction, with a cookie or a browser fingerprint where the advertising ID would be and the IP doing the same job for location. The phone version gets more attention because a phone goes everywhere you go and reports from all of it, and because apps can ask for GPS, which a web page mostly can’t without a prompt. On the web, the plan to get rid of third-party cookies in Chrome, which I’d been half-expecting to see for about five years, turned last July into a plan to let users choose instead, so I wouldn’t count on the browser solving this either.
Brokers, and why “anonymous” doesn’t help
A broker collects these feeds, links records that share an identifier, and ends up with something like a list of (device, time, latitude, longitude) rows. No names. The pitch is always that it’s anonymous.
It isn’t, in any useful sense, and the math on this is well known. In 2013 de Montjoye and colleagues looked at fifteen months of mobile phone location data for 1.5 million people, at the resolution of an hour and a cell tower, and found that four points were enough to single out 95% of them. People don’t move randomly. Where a phone sleeps most nights and where it spends weekday afternoons is very nearly an address and an employer, and those two together are close to a name. In 2021 a Catholic publication bought commercially available app data, matched a device to a priest’s home and workplace, and published what it showed. He resigned. Nobody had to hack anything for that. They paid for it.
The buyers are a mix. Most of it goes into ad targeting and “foot traffic” analytics for retailers and investors. Some goes further. The FTC’s complaint against Gravy and its subsidiary Venntel in December described selling data that showed visits to places like medical facilities and places of worship, and Venntel’s government customers have been reported on for years. The FTC’s proposed order, announced in early December, bans them from selling sensitive location data. That’s two companies, and the bidstream they partly fed from is still running.
What actually helps
For your own phone, roughly in order of how much they help:
- Fewer free ad-supported apps. This is the big one and the least satisfying. If the app has ads, it has an SDK making bid requests.
- Refuse tracking and location permission by default, and reset or delete the advertising ID. It won’t stop the IP and device details, but it removes the identifier that makes linking easy, and it takes the GPS-quality path away from most apps.
- A VPN changes which IP and city goes out with the request. It doesn’t change anything else in the fingerprint.
That’s a short list, and I don’t love it, because it puts the work on the people who can see the least. A proxy and an afternoon to read its output are not things most people have.
The part I can do something about is our own stuff. We don’t show ads, but our marketing site has an analytics script and two advertising pixels on it, and until last week I couldn’t have told you exactly what each one sends. So I spent an evening with the browser’s network tab on our signup page, the way I would on a CTF challenge, and wrote down every third party that got a request and what was in it. One of the pixels was sending the full page URL, including a query string that, on one page, had the customer’s email address in it from an old marketing campaign link. We can only estimate how many people that touched: the page gets about 300 visits a month, mostly existing customers following links in our emails, and the link had been like that since 2021. We fixed the link the same evening and asked the vendor to delete what it had received, which it confirmed in writing two days later. The pixel’s vendor wasn’t on our GDPR data map either, so that got fixed too, and our legal advisor assessed it as a possible breach. The conclusion was that it didn’t need to be reported, since it was email addresses and nothing else, sent to a vendor we had a contract with, which had now deleted them. I’d have been happier with that answer if we’d found it ourselves three years earlier. It’s on the data map now. The list is going into the same vendor spreadsheet as everything else, with a column for what data each one receives, because “the marketing team added it in 2019” is not an answer I want to give anyone who asks.