Insights
Privacy Map
Since 0.2.1 Requires Cloak Proxy 0.2.1 or later.
See which outside companies an app sends its users' data to, what each receives (email, phone, location, IDs, tokens) and where, with privacy label hints.
Privacy Map shows where one app’s users’ data goes. For every outside company the app talks to, such as analytics, attribution, advertising and crash-reporting services, it lists the personal data and identifiers that company received: email addresses, phone numbers, names, locations, advertising and device IDs, user IDs, the app’s own auth tokens, and IDs the app’s own servers issued, such as order numbers. For each one it shows exactly where in the request it was sent.
Use it to review what your app’s SDKs collect before a release, to fill in the App Store privacy label or the Google Play Data safety form, or to catch an SDK that receives something it shouldn’t, such as a login token.
Map an app
Section titled “Map an app”-
Capture the app while you use it, with SSL Proxying on for it, so its HTTPS requests are decrypted. Sign up, log in and go through the screens you want to check.
-
Open Privacy Map:
- Choose Tools › Privacy Map… (⌥ ⌘ P). If an app is selected in the sidebar, the map opens for it.
- Or right-click the app in the sidebar and choose Privacy Map for app….
- On Linux, press Ctrl Alt P, or right-click a request from the app and choose Privacy Map for app….
-
If needed, choose the app from the App menu. The map is built right away.
-
Check Own domains. Remove domains that aren’t the app’s, and add any of its servers that are missing.
-
Optionally, under Test account, type the Email, Phone and Name you tested with and press Return, so Cloak Proxy finds them wherever they were sent.
-
Read the summary, then the details for each company. Click a company or a request count to select those requests in the traffic list.
One app's requests to outside companies, colored by the most sensitive data each received.
- The app to map. Rescan to include new traffic.
- The app's own domains. Click × to treat one as a third party, or add one.
- Your test account: found wherever it was sent.
- Fix: an outside company received the app's auth token or a card number.
- Each company that received data, with what. Click to select its requests.
- Mark as the app's own: stop treating this domain as a third party.
The window
Section titled “The window”| Control | What it does |
|---|---|
| App | The app to map. Lists every app in the captured traffic except Cloak Proxy itself. |
| Rescan | Builds the map again from the traffic captured so far. |
| Copy Report | Copies the map as Markdown. Reads Copied until the map changes. Only when the app talked to at least one outside company. |
| Own domains | The domains that belong to the app. Everything else is an outside company. Click × on a domain to treat it as a third party. |
| Add a domain | Type one of the app’s domains and press Return. It’s reduced to its registrable domain, so api.shopapp.example adds shopapp.example. |
| Test account (optional): Email, Phone, Name | Values to look for in every request to outside companies. Press Return in any of them to save them and rescan. |
The map is rebuilt whenever you choose another app, change the app’s domains or press Return in a test account field. It doesn’t update by itself as new traffic arrives; click Rescan.
Privacy Map reads decrypted requests only. If the app’s HTTPS isn’t decrypted yet, the window says how many encrypted connections it made and offers Decrypt app’s HTTPS, which turns on SSL Proxying for every domain the app connects to. Use the app again, then click Rescan.
Privacy Map for an app whose HTTPS isn't decrypted yet.
- Turns on SSL Proxying for every domain the app connects to
When the app has no requests, the window says No requests from app: use the app with Cloak Proxy capturing, then rescan.
The app’s own domains
Section titled “The app’s own domains”Privacy Map needs to know which servers are the app’s, so it can tell what the app’s backend sends from what outside companies receive. It works with registrable domains, such as shopapp.example for api.shopapp.example and cdn.shopapp.example.
The first time you map an app, Cloak Proxy suggests its domains:
- Domains whose name shares a word of 4 or more letters with the app’s name or bundle identifier (ignoring words such as
com,app,ios,mobile,clientandprod), or contains the app’s name. ShopApp’s requests toapi.shopapp.examplemakeshopapp.exampleits own. - Domains you captured for the app because it ignores the proxy.
Domains of known SDK companies are never suggested. Once you change the list, by removing a domain, adding one or clicking Mark as app’s Own, Cloak Proxy remembers it for that app.
Your test account
Section titled “Your test account”Personal data in SDK payloads doesn’t always sit under a recognizable key. Type the email, phone number and name of the account you used while capturing, and Privacy Map finds them in any value sent to an outside company:
| Field | Matches |
|---|---|
| The address anywhere in a value, ignoring case. | |
| Phone | The last 10 digits of the number anywhere in a value. Needs at least 7 digits. |
| Name | The name anywhere in a value, ignoring case. Needs at least 3 characters. |
Cloak Proxy remembers these values per app, in its preferences on this Mac. Use a test account, not your own details.
Read the map
Section titled “Read the map”The summary
Section titled “The summary”| Part | Shows |
|---|---|
| Headline | App sends personal data or identifiers to N of the M outside companies it talks to, or that none was found. |
| Request count | N of M requests from app went to outside companies. |
| Fix: banner | In red, when an outside company received the app’s auth token or a card number: Nothing outside your own servers should get these. |
| Chips | One per kind of data, in its severity color, followed by → and the companies that received it. |
Colors
Section titled “Colors”Each kind of data has a severity, shown by color on the chips, the map’s lines and the details:
| Color | Meaning | Data |
|---|---|---|
| Red | Fix it: no outside company should get this | Your app’s auth token, card number |
| Orange | Personal data: declare it, and check the company needs it | Email address, phone number, name, precise location |
| Blue | Identifiers that link activity to a user or device | Approximate location, advertising ID, device ID, user ID, IDs from your backend |
The map
Section titled “The map”On the left, the app with its own servers. On the right, under Outside companies that received data, a card for each company that received something, most sensitive first, then by how many findings and how many requests. Each card shows:
- The company’s name and category, such as Analytics or Attribution, when Cloak Proxy knows it; otherwise the domain.
- How many requests went to it, and up to three of its hosts.
- A chip for each kind of data it received.
The line from the app to each card takes the color of the most sensitive data that company received, and is thicker for red. Under the cards, Also talked to, with no personal data found: lists the other outside companies. Click a card to select every request that sent it data.
What each one received, and where
Section titled “What each one received, and where”Below the map, a section per company lists every finding:
| Column | Shows |
|---|---|
| Data | The kind, in its severity color. |
| Where | The exact place in the request: query phone, header X-User, cookie uid, body $.events[*].user_properties.email, body email. Array positions are shown as [*]. |
| From | For values the app’s own servers issued or the app authenticates with: where they came from, such as From POST api.shopapp.example/v1/orders response $.data.user.id, or From the Authorization header of POST api.shopapp.example/v1/orders. |
| Example | The value, partly hidden. |
| N req | How many requests sent it there. Click to select them in the traffic list. |
Mark as app’s Own next to a company moves its domain into the app’s own domains and rescans. Use it for the app’s servers on another domain, such as a separate API or CDN domain.
For your privacy label
Section titled “For your privacy label”For your privacy label lists each kind of data sent to outside companies (except auth tokens, which are a problem to fix rather than something to declare), the App Store privacy label category it usually falls under, and the companies that received it:
| Data | App Store category |
|---|---|
| Card number | Financial Info › Payment Info |
| Email address | Contact Info › Email Address |
| Phone number | Contact Info › Phone Number |
| Name | Contact Info › Name |
| Precise location | Location › Precise Location |
| Approximate location | Location › Coarse Location |
| Advertising ID | Identifiers › Device ID |
| Device ID | Identifiers › Device ID |
| User ID | Identifiers › User ID |
| IDs from your backend | Depends on what it identifies (often Purchases or Other Data) |
What Privacy Map looks for
Section titled “What Privacy Map looks for”Privacy Map reads every request from the app (except encrypted tunnels) and splits them into requests to the app’s own domains and requests to everyone else.
Values the app’s own servers issued
Section titled “Values the app’s own servers issued”First, it learns from the app’s own traffic:
- The app’s auth tokens in its requests. The value of each
Authorizationheader, any header withtokenin its name, andX-API-Key, without aBearer,TokenorBasicprefix, when it’s at least 12 characters. - Values in its JSON responses that look like IDs: at least 4 characters with no spaces, containing a digit or at least 20 characters long, and not a timestamp, a date or a version number. Each one is sorted by its key:
- under keys such as
access_token,refresh_token,id_token,jwt,session_tokenandapi_key: Your app’s auth token; - under keys such as
user_id,customer_id,account_id,member_id,distinct_id,external_idandprofile_id: User ID; - anything else: IDs from your backend. Order numbers, cart IDs and payment references land here.
- under keys such as
Any of these values sent to an outside company is a finding, with where it came from. A value of more than 24 characters is also checked piece by piece, so a token inside a URL or a longer string is found too.
Data in requests to outside companies
Section titled “Data in requests to outside companies”Then it checks every value in each request to an outside company: query parameters, the path, headers (except standard ones such as Host, User-Agent, Accept, Content-Type, Origin and Referer), each cookie, and the body. JSON bodies are read field by field, including JSON packed inside a string (common in analytics SDKs) and JSON inside a form field. Form bodies are read field by field, and other text bodies as a whole.
Most kinds are found by the key name together with the shape of the value. Key names ignore case and punctuation, so customer_user_id, customerUserId and CUSTOMER-USER-ID are the same key.
| Data | Found when |
|---|---|
| Your app’s auth token | A value matches one of the app’s own tokens. |
| Card number | Any value contains a 13 to 19 digit number that passes the Luhn check. |
| Email address | A key such as email, email_address, mail or user_email holds an email address; or any value contains one. Outside email keys, mailboxes such as noreply@, support@ and info@, and addresses at example.com, are ignored. |
| Phone number | A key such as phone, phone_number, mobile, msisdn or tel holds 7 to 15 digits with only +, -, spaces and parentheses besides; or any value contains a + followed by 10 to 14 digits. |
| Name | A key such as first_name, last_name, full_name, display_name, given_name or family_name holds 2 to 80 characters with a letter and no @. |
| Precise location | A lat or latitude key has a lng, lon, long or longitude key next to it in the same JSON object, with valid coordinates and at least 3 decimal places. |
| Approximate location | The same, with fewer decimal places. |
| Advertising ID | A key such as idfa, advertising_id, gaid, adid or aaid holds a UUID that isn’t all zeros. |
| Device ID | A key such as idfv, vendor_id, device_id, android_id, install_id or installation_id holds at least 8 characters. |
| User ID | A user-ID key, as above, holds a value other than 0, -1, anonymous or guest; or a value matches a user ID the app’s servers issued. |
| IDs from your backend | A value matches an ID the app’s servers issued. When the same value is sent under a more specific key, such as user_id, it’s listed as that kind instead, with where it came from. |
Your test account’s email, phone and name are found anywhere, whatever the key.
Known companies
Section titled “Known companies”Cloak Proxy recognizes the domains of more than 40 common SDK companies and shows their name and a category: Advertising, Analytics, Attribution, Engagement, Push notifications, Crash reporting, Monitoring, Session recording, Support, Chat, Payments, Sign-in or Google services. Any other outside domain is shown by its registrable domain, such as sdk-collector.example.
Partly hidden values
Section titled “Partly hidden values”Examples are partly hidden everywhere, in the window, the report and the MCP tool, so you can recognize a value without exposing it:
| Data | Shown as |
|---|---|
| Email address | a•••@example.net |
| Phone and card numbers | +••••••••••23: every digit but the last two hidden |
| Location | 12.9…, 77.5…: one decimal place |
| Name | A••• |
| Anything else | tok_…56: the first 4 and last 2 characters, or the first 2 for values of 8 characters or fewer |
Copy the report
Section titled “Copy the report”Copy Report puts the map on the clipboard as Markdown, for a privacy review, a ticket or your release checklist:
- A heading with the app, how many of its requests went to outside companies, and the domains treated as its own.
- Summary: each kind of data and the companies that received it.
- A section per company with a table of Data, Where, Example and Requests, including where backend values came from.
- The companies that received no personal data.
- Privacy label starting point: the table of data types, App Store categories and companies.
It ends with a note that values are partly hidden and only decrypted HTTPS traffic was checked.
Limits
Section titled “Limits”- Only decrypted traffic. Requests that pass through as encrypted tunnels can’t be read. Turn on SSL Proxying for the app, and capture it through DNS if it ignores the proxy. Apps that pin certificates can’t be decrypted at all.
- Only what you captured. Data sent on screens you didn’t open, or by SDKs that send in batches later, isn’t on the map. Use the app thoroughly, then wait a moment before you rescan.
- Only plain HTTP payloads. SDKs that encrypt or encode their payloads before sending them, or send data over something other than HTTP, such as raw sockets, don’t show their contents.
- Heuristics can miss or misclassify. Data under unusual key names isn’t recognized unless it has a recognizable shape or matches your test account. A value can also be flagged that isn’t personal data. Check findings against the request before you act on them.
- Your own servers aren’t checked. Data sent to the app’s own domains doesn’t appear, even though it may still belong on a privacy label.
Map from an AI assistant
Section titled “Map from an AI assistant”The MCP server has a read-only privacy_map tool. It takes the app name (as list_apps shows it) and optionally first_party, a list of the app’s own registrable domains. Without first_party, it uses the domains you saved for the app in the window, or the suggested ones. It returns each kind of data with its recipients and App Store category, and each company’s findings with partly hidden examples. It doesn’t use the test account values. See the MCP tools reference.