← All articles

How to set up RevenueCat with Meta ads so your purchases actually track

By default, Meta has almost no idea how much money your subscription app really makes. It sees an install, maybe a trial start if your SDK is wired up, and then nothing. The renewals, the trial conversions, the upgrades, all the revenue that actually decides whether a campaign is profitable, happens later and server side, where Meta never looks.

RevenueCat is where that truth lives. It knows every trial, conversion, renewal, and cancellation across iOS and Android. The whole job is getting that truth into Meta cleanly, so your ads optimise on real purchases instead of a guess. This is the exact step most apps get wrong, so here is how to do it properly.

Why this breaks by default

Three things work against you.

First, subscription revenue is a server side event. A renewal three weeks after install never touches the phone in a way the Meta SDK can catch. If Meta only hears about the first checkout, it is optimising against a tiny slice of the real value.

Second, iOS killed easy attribution. After ATT, most users do not grant tracking, so device level matching is gone and you are leaning on SKAdNetwork, which is delayed and aggregated. That is not a reason to give up, it is a reason to send Meta clean, server side purchase data through the Conversions API so it has something real to learn from.

Third, most setups only send installs and trial starts. Those are the cheap, meaningless events. The events that matter for optimisation are the paid ones: trial conversions, initial purchases, and renewals.

What a good setup looks like

Meta receives your real money events (trial conversion, initial purchase, renewal), tied to the right user, deduplicated between the app and your server, on both iOS and Android. When that is true, you can finally optimise campaigns toward purchases and read cost per purchase against LTV instead of guessing.

Here is how to get there.

Step 1: Wire up the Meta SDK in the app

Install the Meta SDK and connect your app inside Events Manager so installs and basic app events flow in, and so iOS SKAdNetwork is configured. This is the foundation Meta needs before any purchase data is useful. Do not skip it and try to run everything server side, you want both signals.

Step 2: Let RevenueCat collect the identifiers Meta needs

An event is useless to Meta if it cannot be matched to a user. In your RevenueCat setup, enable the collection of device and attribution identifiers and pass Meta’s anonymous ID through to RevenueCat, so every RevenueCat event carries the identifiers Meta uses for matching. Without this, your beautifully accurate purchase events land in Meta and match nobody.

Step 3: Pick one clean pipe for the events

You have two reliable ways to move RevenueCat purchase events into Meta. Pick one, do not run both blindly.

Option A, through your MMP. If you already use AppsFlyer, Adjust, or Singular, RevenueCat integrates with them natively. RevenueCat sends the purchase and renewal events to the MMP, and the MMP forwards them to Meta with attribution already handled. This is the cleanest path if you have an MMP.

Option B, RevenueCat webhooks to the Meta Conversions API. No MMP? Point RevenueCat webhooks at a small server endpoint that forwards the events to Meta’s Conversions API for app events. More control, a bit more engineering, and you own the pipe end to end.

Step 4: Send the events that actually matter

Map the RevenueCat events to Meta purchase events, and be deliberate about which ones you send:

  • Trial start: fine as a soft signal, though optimising on it is its own trap.
  • Trial conversion: this is a real purchase, send it.
  • Initial purchase: send it, with revenue and currency.
  • Renewal: send it, this is where subscription LTV is built.

Include the actual revenue and currency on each event. An event with no value teaches Meta nothing about how much a customer is worth.

Step 5: Deduplicate, or you will double count

If the Meta SDK reports a purchase from the app and your server also reports the same purchase through the Conversions API, Meta can count it twice and your numbers inflate. Send a shared event ID on both the client and server events so Meta can dedupe them. This one step saves a lot of confused reporting later.

Once you switch the SDK off purchase logging, expect your ATE True Status Rate in Events Manager to drop to zero or go blank. That is normal here and it is not the thing breaking your attribution.

Step 6: Set realistic expectations on iOS

Post ATT, iOS attribution runs through SKAdNetwork, which is delayed and aggregated. Configure your conversion value mapping so a paid conversion is captured, and accept that iOS reporting will always be coarser and slower than Android. The goal is not perfect device level truth on iOS, it is feeding Meta enough real purchase signal to optimise well.

Step 7: Test before you trust it

Do a real test purchase and confirm the event lands correctly in Events Manager, ideally through the Test Events tool, with the right value and currency. Then compare a few days of Meta reported purchases against RevenueCat. They will not match to the cent, but they should be in the same universe. If Meta shows a fraction of what RevenueCat shows, something in the pipe is broken.

The mistakes I see most often

  • Only sending installs and trial starts, so Meta optimises toward people who will never pay.
  • Purchase events with no revenue attached, so LTV is invisible.
  • No shared event ID, so client and server events double count.
  • Identifiers never passed through RevenueCat, so events match nobody.
  • Renewals ignored entirely, which is most of the actual revenue for a subscription app.

Bottom line

RevenueCat already knows the truth about your revenue. Meta does not, until you connect them properly. Get the identifiers flowing, pick one clean pipe, send the paid events with real values, deduplicate, and verify with a test purchase. Do that and your Meta campaigns finally optimise on money instead of installs.

If your subscription app is running Meta ads but the purchase data looks nothing like RevenueCat, that gap is almost always a tracking setup problem, and it is exactly the kind of thing I fix on a teardown call.

Common questions

How do I connect RevenueCat to Meta ads so my purchases actually track?

Open your RevenueCat project settings, choose Meta Ads from the Integrations menu, and use the Conversions API rather than the older App Events path. Then turn off Meta's automatic purchase logging in your app so the SDK and RevenueCat are not both reporting the same purchase, but keep the activate app call so Meta still sees installs and sessions. Finally, make sure each event carries the identifiers Meta needs to match it to a user, and send real revenue and currency values rather than empty events.

Why are my purchase events not appearing after setting up the Meta integration?

The three usual causes are missing identifiers, a sandbox or credential mismatch, and non-standard event names. Meta silently drops events it cannot match to a person, so if you are not passing Meta's anonymous ID through to RevenueCat the events arrive and match nobody. Check that your dataset ID and access token belong to the same live app rather than a test setup, and that you are sending Meta's standard event names rather than custom ones. Check the events themselves in Events Manager, not the aggregate dashboard, because a low match quality score looks a lot like nothing arriving at all.

Should I optimise for trial starts or purchases when running Meta ads for a subscription app?

Optimise for the paid event whenever you have enough volume to get out of the learning phase, because Meta buys more of whatever you feed it and cheap trials are frequently the ones that never convert. Trial starts are the right choice only when paid conversions are too rare to exit learning, typically under roughly fifty per week. If you optimise on trials, watch your trial to paid conversion rate closely, because Meta will happily find you the cheapest trials available and those are usually the worst ones.

Can I get Meta campaign and ad level attribution in RevenueCat without ATT consent?

Partly, and it is worth setting up. Even when a user declines the App Tracking Transparency prompt you can still pass Meta's anonymous identifier through to RevenueCat, which gives you some campaign level visibility without device level tracking. What you will not reliably get is deterministic per-user attribution for those users, since that is exactly what ATT removes. Treat non-consenting iOS traffic as something you read at the campaign and trend level, and lean on SKAdNetwork plus your own RevenueCat revenue as the real scoreboard.

Does RevenueCat send renewals to Meta, or only the first purchase?

RevenueCat can send trial conversions, initial purchases and renewals, and sending renewals is the entire point of doing this properly. Renewals happen server side weeks or months after the install, long after the device has stopped talking to the Meta SDK, so they are invisible to Meta unless something server side reports them. This is why accounts that only send installs and trial starts end up optimising toward the cheapest possible signup rather than toward subscribers who actually stay.

Will RevenueCat and Meta Ads Manager ever show the same revenue number?

No, and you should stop trying to make them match. RevenueCat records every dollar your subscribers pay, while Meta reports only the revenue it both received an event for and can attribute to an ad inside its attribution window. Different definitions and different dates guarantee a permanent gap, and the gap is widest on iOS because of SKAdNetwork. What you want is for the two to move together and for your real paid events to reach Meta, not for two dashboards to agree.

Ads live but the numbers do not make sense? That is what I fix.

Request a teardown call → Apply for done-for-you