What leaves your phone
App version 1.13.0, checked October 13, 2026. Redone with every release that adds a library, an address or a change to a server we run.
The short version. The app has no account, no analytics, no crash reporter and no advertising code. Scanning, the scam checks and the spyware check run on the phone. What does go out is listed here, address by address, with what each request carries, and for the servers we run, what each one keeps and for how long. This page is how we wrote the App Store privacy label, so you can check it rather than take our word.
How we checked
Three passes over the code that ships, not over a description of it.
- Every library’s own declaration. Apple requires each SDK to ship a privacy manifest saying what it collects. We read all fourteen in this build.
- Every address in the source. A search of the app, its extensions, the engine and the native code for anything that can be contacted, and a read of what each request carries.
- The servers we run. Their code, their database tables and their logging settings, read from the source and the setup scripts, not from memory.
Pass 1: what the libraries declare
Fourteen privacy manifests ship in the app, the same fourteen as in 1.12.0: no library was added or removed. Twelve declare that they collect nothing (React Native and its parts, the Expo modules for files, settings, notifications and background tasks, the screenshot module). The two that declare anything:
| Library | Declares | What that means here |
|---|---|---|
| react-native-maps | Precise location, for app functionality, not linked to you, not used for tracking | The map shows where you are. The app uses Apple Maps only; the Google Maps part of this library, whose manifest declares analytics, is not compiled in (no Google key exists in the build). |
| RevenueCat (react-native-purchases) | Purchase history, for app functionality, not linked to you | Payments are not switched on in 1.13.0 (the build has no RevenueCat key). Once they are, RevenueCat receives the purchase record Apple issues and an anonymous ID. No name, no email. |
There is no analytics SDK, no crash reporter, no attribution SDK and no advertising SDK in the dependency list. The full list is in the app’s package.json.
Pass 2: every address the app can contact
Each one is used only by the feature named: when you use it, or on the schedule its row gives. Your IP address reaches any server you contact; that is how the internet works and is not repeated in every row. The app’s extensions (the call directory, the text filter, the Safari blockers, the scam check in the share sheet and the Home Screen widget) make no requests of their own; the one exception is App protection, which blocks in every app and passes the lookups it doesn’t block to Quad9 (below). In the background, about every 12 hours when iOS allows, the app reaches the internet for three things by itself: the iOS update check, the scam-number list and the App protection list.
Ours (Headway Tech LLC, served by Cloudflare)
| Address | When | What it carries, and what is kept |
|---|---|---|
| headwaytech.app/data/… | The scam-number list once a day; the ad and tracker list and the App protection list once a week; the aircraft watchlist (plane-alert-db) at most once a day, when What’s flying overhead opens | Nothing about you. The same public files for everyone. From October 13, 2026 the scam-number file also carries, for each number, how many reports it had and what most of them were about, and the repeat callers from the last 12 months; the numbers of real organizations on our never-label list are taken out before it is published (call labels). Each number’s label is made on the phone from that file. |
| headwaytech.app/api/hibp/email | Email watch: when you check an address, and once a week for each address you keep | The email address, over an encrypted connection, passed once to Have I Been Pwned. The server doesn’t store the address. It keeps the answer (the list of leaks, not the address) for 24 hours, filed under a scrambled form of the address, so the same address checked again that day doesn’t go to Have I Been Pwned twice. For its limits (5 checks a minute and 30 a day from one connection) it counts checks under a scrambled form of your IP address, or of its IPv6 /64 so a phone’s changing addresses count once; the day’s count is deleted the next day. Scrambled means a one-way hash made with a secret only the server holds: it can’t be turned back into the address. No logging call in the worker, observability off, responses marked no-store. |
| headwaytech.app/api/cams | License plate cameras: when the map settles on cameras; every 2 minutes at most during a drive; when you answer “Still there?”, report a problem, add a camera or report a speed check | Map questions: the camera map IDs on screen, or the nine map squares around you, with no number (not kept). Answers and added cameras: with a random install number the server scrambles on arrival, and the day, kept 180 days. Beside that scrambled number the server keeps the day it was first seen (a day, never a time) and how often its answers matched other drivers’, which decides how much its answers count; that record goes 180 days after its last answer. A speed check: its spot to about 10 m, the direction and the minute, with no number, deleted when it ends (one to two hours). Limits: each install’s daily counts (deleted the next day); its speed checks this hour, filed so they can’t be matched to its other rows (deleted when the hour ends); and per-connection limits under a scrambled form of your IP address or its IPv6 /64, which only Cloudflare’s rate limiter holds, in memory, for a minute. No logging call in the worker, observability off, responses marked no-store. |
| roads.headwaytech.app | License plate cameras, when the map opens somewhere the phone has no road data for, or a route goes through one | Which map squares the phone needs, each about 28 by 21 km. Never a start, a destination or a route. |
| sky.headwaytech.app | What’s flying overhead, at most twice a day | Nothing about you. The same orbit file for everyone; your position stays on the phone. |
| vpn-west.headwaytech.app | Only if you turn the VPN on | To set it up: the invite code that lets it in and your choice about blocking ads. The server keeps a device record (a random ID, a scrambled copy of a token only your iPhone holds, the ad choice, which invite it came in on, the day it was added) and the device’s VPN key, until you remove the VPN in the app. Before it switches on by itself on a Wi-Fi, the phone asks the server’s health page whether it is up, which carries nothing about you. Then your internet traffic while the VPN is on. Logging on that server is off: the system journal stays in memory, the resolver logs no queries, the firewall logs nothing, and the key desk and its web server keep no request log. The privacy policy says exactly what it keeps. |
Other services
| Address | When | What it carries |
|---|---|---|
| api.adsb.lol | What’s flying overhead, while open | Your position rounded to two decimals, about 1 km, to fetch the aircraft nearby. |
| celestrak.org | What’s flying overhead, if our orbit file doesn’t answer | Nothing about you. |
| overpass-api.de, overpass.kumi.systems, overpass.private.coffee | License plate cameras, when you tap “Check the live map” | The position being checked, rounded to three decimals, about 100 m, and a radius. The built-in map needs no request at all. |
| nominatim.openstreetmap.org | What’s flying overhead, when you type a place | The place name you typed. |
| api.pwnedpasswords.com | Was a password leaked? | The first five characters of the password’s hash, with padding. Never the password. |
| gdmf.apple.com (Apple) | The iOS update check: in a scan’s phone checks, in Is my iPhone hacked? and for the update notice; at most every 12 hours, also in the background when iOS allows | Nothing about you: it fetches Apple’s public list of current iOS versions, the same request for everyone. Which version this iPhone runs stays on the phone. |
| 1.1.1.1 and internetdb.shodan.io | Who’s on my Wi-Fi?, “Check from outside” | Cloudflare is asked what this connection’s public address is; Shodan is asked what its own scans found open at that address. |
| 1.1.1.1 and one.one.one.one | Is this Wi-Fi spying on me? | Cloudflare’s public trace page, loaded once by its number and once by its name, to see whether the Wi-Fi gets in the way of secure connections. Nothing else is sent. The router on the Wi-Fi is also asked for the addresses of two well-known names (one.one.one.one, dns.google) and of one made-up name under example.com; a router passes such questions on to its own provider. |
| speed.cloudflare.com | Who’s on my Wi-Fi?, “Run speed test” | Test data up and down. |
| 1.1.1.1 (Cloudflare), 8.8.8.8 (Google), 9.9.9.9 (Quad9) | Who’s on my Wi-Fi?, “Compare lookup speed”; DNS lookup in Tools asks 1.1.1.1 only when the app doesn’t know your router | Lookups of five well-known names (apple.com, google.com, wikipedia.org, amazon.com, cloudflare.com), or the name you typed into DNS lookup. |
| The site you name | Who’s on my Wi-Fi?, Trace route | Small test messages (echo requests) toward that site; each network stop on the way answers. They carry nothing about you. |
| dns.quad9.net (9.9.9.9) | App protection, while on | The names your apps look up that the filter did not block, the way your provider’s resolver sees them otherwise: encrypted, or for a minute at a time unencrypted when the encrypted connection fails. Blocked names never leave the phone. Quad9 is a Swiss nonprofit that keeps no record of who asked. |
| u.expo.dev | When the app starts, to check for an update | The app version and platform, the IDs of the update it runs, and a random install ID (sent as EAS-Client-ID) that Expo’s update library creates and sends with every check. It is not tied to you or your device, but it is the same number each time from this install, and we cannot switch it off without replacing the update system. If the app failed while starting last time, that error’s message goes too, up to 1,024 characters. This is the one request on this page we would rather not make; it is here so you know it exists. |
| RevenueCat | Not in 1.13.0. Once payments are on: when the app starts, and when you buy or restore | An anonymous ID RevenueCat makes, the purchase record Apple issues, the device model and the app version. No name, no email. Its address will be listed here when it is switched on. |
Apple
Apple Maps draws every map, and its search and directions answer what you type and the routes you plan, as in the Maps app. The App Store handles purchases and the rating prompt. On an iPhone with Apple Intelligence, the scam check runs Apple’s on-device model; nothing leaves the phone for it. All under Apple’s privacy policy.
Links that leave the app
A flight’s track (globe.adsb.lol), the FAA registry and its drone report page, DeFlock, the Atlas of Surveillance, the FTC’s and FBI’s pages, NIST’s page for a router flaw, your router’s own settings page, and “Open in Google Maps” or Apple Maps for a route open the other site or app, which then works under its own policy. The app sends nothing to them itself.
Where device names come from
Naming happens on the phone, from tables the app carries: the IEEE registry of maker codes (39,771 prefixes, who made any Wi-Fi or Bluetooth radio), Home Assistant’s discovery matchers (Apache-2.0: which brand a broadcast, a hostname or a description belongs to, 245 brands), Amazon’s, Google’s, Apple’s and Sonos’s own model codes, and our own fingerprints for the devices that spy. Nothing about your network is uploaded to name a device.
Pass 3: the servers we run, and what each keeps
- Lists, orbit file, road squares: static files on Cloudflare. We keep no record of who downloaded what.
- Email check worker: no logging statement in its code, Cloudflare observability and Logpush off, responses marked no-store. Its database holds two tables and nothing else: a count of checks per scrambled IP address (or IPv6 /64) per day, deleted the next day, and how many calls went to Have I Been Pwned in each 10 seconds, for everyone together. Its cache holds each answer for 24 hours under a scrambled form of the address. Someone holding the server’s secret and a given address could tell whether that address was checked in the last 24 hours; nothing lets anyone read addresses back out of the cache. Have I Been Pwned’s own policy covers what it does with an address.
- Camera map worker (License plate cameras): no logging statement in its code, Cloudflare observability and Logpush off, responses marked no-store. Its database holds answers and added cameras under a scrambled install number (180 days); for each scrambled number, the day it was first seen, the day of its last answer and how its answers fared against other drivers’ (until 180 days after its last answer); problem reports with no number; daily counts per scrambled number (deleted the next day); speed checks with no number, deleted within 15 minutes of ending, and the hourly speed-check counts, deleted when the hour ends. An added camera never confirmed is deleted after 30 days; a confirmed one stays on the map and loses its scrambled number after 180 days. No IP address, no route, no time of day for a camera.
- VPN server: system journal in memory only, resolver query logging off, firewall logging off, no request log on the key desk or its web server. The privacy policy lists the one record it keeps (your device entry) and when it goes.
What someone could call a collection
Being exact matters more than being flattering, so here is the list a careful reader would write:
- The random install ID that goes to Expo with each update check, and the message of a start-up failure, once, after one happens.
- An email address, passing through our worker on its way to Have I Been Pwned when you check one; the answer, kept 24 hours under a scrambled form of the address; and the day’s count of checks, under a scrambled form of your IP address.
- Your internet traffic, while you choose to run our VPN, and the VPN’s device record.
- Purchase records through RevenueCat, once payments are on.
- Your answers on the camera map and the cameras you add, kept 180 days under a random number the app made and the server scrambles, with the day that number was first seen and how its answers fared; and a speed check you report, its spot and time, kept one to two hours with no number at all.
- A position rounded to about 100 m, sent to an OpenStreetMap server when you tap the live map check; about 1 km to adsb.lol while What’s flying overhead is open.
Apart from the camera map records, the 24-hour email answers and the day’s counters above, kept under a scrambled number or none and never with a name, an account or an IP address, and the VPN’s device record, nothing on that list is stored by us about you, and nothing on it is sold, shared for advertising or used to build a profile. The App Store label is written from this page, and it changes when this page does.
The App Store label for 1.13.0
These are the answers we give Apple for this version, in App Store Connect’s own words. Every one is for App Functionality, none is linked to your identity, and none is used for tracking.
| Category | Data type | What it is here |
|---|---|---|
| Purchases | Purchase History | Once payments are on, RevenueCat receives the purchase record Apple issues, under an anonymous ID, so the app knows you own the unlock. |
| User Content | Other User Content | The cameras you add to the License plate cameras map, which other people using the app then see. |
| Location | Precise Location | A speed check you report goes with its spot, kept to about 10 m, so drivers heading that way are warned, and is deleted when it ends. |
| Identifiers | User ID | The camera map’s install key, a random number the app makes and the server keeps only scrambled, so each phone gets one answer per camera. |
| Identifiers | Device ID | The random install ID Expo’s update service receives with each update check, and the VPN’s device record if you turn the VPN on. |
Everything else on Apple’s list is answered as not collected. The closest calls, and why they are not on it: an email address you check passes through our server as you check it and isn’t stored; the rounded positions for adsb.lol and the live map check are sent as you use those screens, and we keep none of them; the VPN’s traffic and App protection’s lookups pass through and are not kept.
The text filter’s model, measured
From October 9, 2026 the text filter adds a small model to its rules: a logistic regression over the words of a text, 16,384 weights, about 120 KB, inside the rules file the app already carries. It runs inside the filter on the phone; no text is sent anywhere. It was trained on 6,123 public texts (the UCI SMS Spam Collection and the Mendeley SMS Phishing Dataset, both CC BY 4.0, repeats removed). On the 1,225 texts held back from training:
| Where it counts | Scam texts it missed | Plain texts it flagged |
|---|---|---|
| As a sign (probability 0.90 or more) | 13.8% | 0.1% |
| As a strong sign (0.98 or more) | 20.2% | 0.0% |
The model alone never sends a text to Junk; it takes one more sign from the rules (a shortened link, a brand’s name in a stranger’s address, a gift-card line). The one independent measurement of iPhone text filters we know of found 24 to 27 percent of scam texts getting through. Our corpora are older and British, so this number will move as the training set grows; it is reprinted here each time the model is retrained.
Check it yourself
On your iPhone, Settings, Privacy & Security, App Privacy Report, then the app. iOS lists every domain the app contacted in the last seven days. Every one of them should be on this page. One that isn’t is a bug: tell us at the security page and we will fix it and update this list.
Headway Tech LLC · [email protected]