Meta ads not tracking purchases? Debug the web and mobile signal path
Updated July 10, 2026 · 10 min read
If Meta is not tracking purchases, the ad is rarely the first thing to inspect. The failure usually sits in the signal path between the paid click, the client runtime, the checkout or app store transaction, the server verification point, and Events Manager.
The useful question is not 'did we send Purchase?' It is 'which producer emitted which economic fact, with which identity envelope, event_id, value, currency, and verification state?'
The signal path breakpoints
Work through these in order. The first failed invariant usually explains the missing or weak conversion.
- 1Event production: the actual checkout, paywall, subscription, or receipt validation branch never emits Purchase.
- 2Economic authority: Purchase fires from a button or success screen before Stripe, RevenueCat, Adapty, App Store, or Play Billing verifies money.
- 3Identity envelope: CAPI emits value and currency but lacks _fbp, _fbc, fbc derived from fbclid, external_id, IP, user agent, or app identity fields.
- 4Deduplication: client and server both emit Purchase but use different event_id values or different event_name values.
- 5Dataset routing: Pixel ID, app ID, CAPI dataset, access token, or Events Manager test code points to a different destination than the campaign optimizes against.
- 6Consent and privacy: ATT denial, cookie consent timing, ad blockers, or limited data use suppresses client signal without a server backfill.
- 7Revenue semantics: trials, renewals, refunds, discounts, taxes, and intro prices are mapped as the wrong standard event or the wrong value.
Triage matrix
If no event appears in Test Events, inspect producer reachability: is the code path executed, is the token valid, and is the event routed to the active dataset? If the event appears with low Event Match Quality, inspect user_data and click identity. If it appears twice, inspect event_id and event_name parity.
If Events Manager looks correct but Ads Manager under-attributes, inspect the upstream identity continuity: landing URL, fbclid persistence, _fbc fallback, external_id before login, checkout metadata, webhook reconstruction, and campaign optimization event configuration.
A useful debug record
Log this internally for every attempted conversion. Without this record, teams end up debugging screenshots from Events Manager instead of the actual signal path.
type ConversionDebugRecord = {
event_name: "Purchase";
event_id: string;
producer: "pixel" | "app_sdk" | "stripe_webhook" | "revenuecat_webhook" | "adapty_webhook" | "custom_backend";
transaction_id: string;
dataset_id: string;
value: number;
currency: string;
has_fbp: boolean;
has_fbc: boolean;
has_external_id: boolean;
has_ip_and_user_agent: boolean;
emitted_at: string;
};The durable architecture
Use the client path for identity and immediacy: Pixel on web, App SDK on mobile, and lifecycle events such as ViewContent and InitiateCheckout. Use the server path for authority: CAPI emitted from Stripe, RevenueCat, Adapty, app store validation, or your backend after payment is verified.
Bridge those paths with the same event_id, the same standard event name, and a persisted first party identity envelope. That is the architecture that keeps paid learning useful when browsers block scripts, iOS suppresses identifiers, webhooks retry, and users convert after redirects.
Frequently asked questions
Why are my Facebook ads not tracking purchases?
Because the verified Purchase event is not reaching the campaign's active Meta dataset with enough identity and the right event semantics. Common causes are missing CAPI, wrong dataset routing, weak _fbp/_fbc/external_id user_data, optimistic success page firing, and broken event_id deduplication.
Why does Events Manager show Purchase but Ads Manager under-attributes?
Usually the event is arriving without strong match data or without the original click context. On web, inspect _fbp, _fbc, fbclid preservation, event_source_url, IP, user agent, and external_id. On mobile, inspect ATT behavior, app identity fields, and server receipt forwarding.
Why does Events Manager show my purchase as $0?
The event is firing without verified value and currency, or it is using a trial or intro price as if it were paid revenue. Emit Purchase from the verified billing source with the actual amount paid and ISO currency.
How do I stop Meta from double counting purchases?
Persist one event_id per transaction and send it on both the client event and the CAPI event with the same event_name. Do not regenerate IDs inside the browser, mobile callback, and webhook independently.
Related guides
Not sure which signal path is breaking?
Zoruko audits your web and mobile code for broken Meta and TikTok signal chains, then ships each fix as a pull request you review.