pixellint

Mobile · PMs · engineers

Device graphs got worse. Probabilistic got noisier.

If your MMP still offers probabilistic, treat the numbers as directional. Bidding as if they were IDFA-era truth is how CPI looks cheap and cohorts look empty.

What it used

A click on a network, then an install from a device that looks like the click: IP, user-agent, clock, maybe a fingerprint. No advertising id. The MMP scores it and may claim the install. That claim is not a click id you can put on CAPI. It is a modeled join. Treat it like modeled conversions on the web, not like gclid.

Device graphs that mapped extra ids across apps got worse as ATT cut the raw IDFA supply. More users look like more other users. A graph that still emits a match is not proof the match is the same person. Carrier NAT, campus Wi-Fi, and iCloud Private Relay make many devices look like one IP. A short UA on iOS makes many devices look like one UA.

IP and UA stay plaintext

Hashing those fields makes them useless for the MMP. Sending your data-center IP on S2S makes every install look like your office. Leave IP in the clear, send the device IP, and still do not bet the company on it. Pixellint will flag a hashed IP on Adjust and AppsFlyer (vendor.adjust.hashed_plaintext_field, vendor.appsflyer.body.hashed_plaintext_field). It will not tell you the unhashed IP was CGNAT.

Look at the MMP's method (deterministic versus probabilistic) on the raw export, not only at the campaign total. iCloud Private Relay is a blunt instrument against this method. Those signals still exist. They also collide in offices, NATs, and privacy relays.

https://s2s.adjust.com/event?s2s=1&event_token=f0ob4r&app_token=4w565xzmb54d&idfa=D2CADB5F-410F-4963-AC0C-2A78534BDF1E&ip_address=a85e9ca18f34935ab9b0381b25bfad2455444112b0149270fd88e3da172fe196

What to prefer

ATT authorized IDFA when you have it. SKAN conversion values for paid iOS. MMP links that carry a click id through install. Web-to-app click ids stored and sent on first open. Logged-in hashed PII when you have a basis. Probabilistic as a fallback you disclose internally, with a tighter window than deterministic, not as the default you optimize toward.

If two networks both claim probabilistic credit for one install, that is the model, not theft you can pixel-debug. Do not add a third fingerprint SDK to break the tie. You will make the graph noisier and the privacy review longer. Tighten the window, prefer SKAN, and accept unmatched. Write the mix in the measurement spec so UA does not keep a probabilistic number in the KPI slot.

Not a pixel debug

You cannot paste a probabilistic claim into pixellint validate url and get a verdict. There is no click id on that hop. There is an MMP row that says method=probabilistic. Debug with the raw export, not with a Floodlight HAR.

The Adjust and AppsFlyer packs still matter: tokens, device ids, clocks, unhashed IP. A hashed IP makes probabilistic matching worse and deterministic matching worse. Fix the contract first. Then distrust the probabilistic totals on purpose.

POST https://api3.appsflyer.com/inappevent/id123456789
{
  "appsflyer_id": "1234567890123-1234567",
  "eventName": "af_app_opened",
  "eventValue": "",
  "eventTime": "2026-08-21 18:04:00.000",
  "ip": "192.0.2.1"
}

SKAN and consented IDFA are the plan

SKAN is a conversion value and a delayed postback, not a better fingerprint. Consented IDFA is still the deterministic advertising id when ATT authorized it. Those two plus MMP click ids are what you can defend in a review. Probabilistic is the remainder.

Do not describe SKAN as user-level ROAS. Do not describe probabilistic as IDFA-quality. Do not describe a hashed IP as privacy-preserving matching. Send the device IP in the clear because the MMP said to, then treat the join as weak. Pixellint will not score the join. It will score the field.

Check the artifact

Paste the pixel URL or JSON body into the playground. Same engine as pixellint validate. Nothing leaves the tab.