Dilshat Rakhimov
July 2026 · 12 min read
Most "which MMP should we buy" conversations should start one question earlier: do you need one at all? Firebase is free, it's already in your app, and for a genuinely Google-only acquisition mix it does the job. I've also shipped the opposite case — a corporate banking app where the entire revenue event happened in core banking, hours after the install, and no SDK on earth was ever going to see it.
Between those two poles there's a line. This is where I've found it in practice, and what actually differs between AppsFlyer and Adjust once you're past the feature grid.

What Firebase-only genuinely gives you
More than people give it credit for. Google Analytics for Firebase collects your in-app events for free at volumes that would cost real money elsewhere, exports raw events to BigQuery, attributes Android installs through the Play Install Referrer, and — the part that matters most — feeds Google Ads App campaigns natively, including the SKAdNetwork side of iOS for Google traffic. If Google is your acquisition, that loop is closed, at zero licence cost, with the raw data in your warehouse.
What it doesn't do is arbitrate. Meta, TikTok, AppLovin, Unity and the rest don't send their install postbacks to Firebase; they send them to certified measurement partners. So the moment a second paid network exists, Firebase can tell you what happened inside your app, but it cannot tell you who to credit for the install — and it can't referee the case where two networks both claim it. It also doesn't ship the ad-fraud layer, the deep-link infrastructure, or the cross-network SKAN conversion-value management that MMPs sell.
That's the honest summary: Firebase is a very good Google-only attribution layer and an excellent app analytics store. It is not a measurement partner, and no amount of configuration makes it one.
Three tests for whether you need an MMP
Test 1: more than one paid network. With one network, that network's own reporting plus Firebase gets you close enough. With three, you need a single de-duplicated install ledger and someone whose business model depends on being neutral between them. That neutrality is most of what you're buying.
Test 2: iOS at scale. SKAN forces you to encode your funnel into a number from 0 to 63, with delayed and randomised postbacks. Someone has to own the conversion-value mapping centrally, decode it, and join it to spend — I wrote up the mechanics of that in the SKAdNetwork piece. You can do that from raw postbacks yourself. In practice nobody does, because the CV map has to be consistent across every network at once.
Test 3 — and this is the one that decides it for financial products: does the money happen off-device?
In a banking app, the SDK sees an application submitted. It does not see the loan being disbursed, the card being issued, or the deposit being opened, because those happen in core banking, sometimes days later, sometimes in a branch. So the MMP's dashboard shows applications and the ad platforms optimise toward applications — which is exactly how you end up buying enormous volumes of cheap, unqualified traffic that never converts into a single disbursement.
The fix I shipped for a corporate banking app was a server-to-server pipeline. The shape of it:
Mobile app (Flutter) → AppsFlyer SDK → appsflyer_id
↓ captured at login, stored on the client record
Core banking: loan_disbursed / card_issued / deposit_opened
↓ backend worker
POST https://api2.appsflyer.com/inappevent/{app_id}
af_revenue = the disbursed amount, af_order_id = application_id
↓
MMP dashboard: the full funnel, with real money attached
Three details carry that design. The appsflyer_id gets captured at login and stored against the client record, because the backend needs it hours later when the SDK context is long gone. af_order_id is set to the application id so the MMP de-duplicates on retry, backed by a sent-flag column on the disbursement row so a replayed job can't double-count. And events are split by completion channel — loan_disbursed versus loan_disbursed_office — so online and branch closings can be optimised separately instead of being averaged into one meaningless number.
The point isn't the endpoint. It's that an MMP earns its fee here as the join point: the one system that already holds the click, the install and the device, and will accept a revenue event from your backend and hand the result to every ad network. Firebase-only can't take that hand-off for non-Google networks.

If your revenue event lives in a core system rather than in the app, the MMP question stops being about attribution accuracy and becomes about who can receive a server-side event and forward it everywhere.
AppsFlyer vs Adjust: the differences that showed up in real work
Both do attribution, deep links, SKAN 4.0, fraud, and raw data export. Feature grids won't separate them. Three things did, for me.
Pricing shape and where the bill actually comes from. AppsFlyer publishes its numbers: a free Zero plan with a welcome package of 12,000 conversions for the first year, and a Growth plan where conversions beyond that first 12K are priced at $0.07 each. What the headline doesn't cover is that Protect360 (fraud), Data Locker (raw data), audience segmentation and the analytics APIs are separately priced add-ons — and for a bank, fraud protection and raw-data export are not optional extras, they're the reason you bought an MMP. Model the total with the add-ons in, not the per-conversion rate alone. Adjust doesn't put a comparable public rate in front of you — their pricing page wasn't serving public figures when I checked in July 2026, so it's a quote per contract. That's not a knock; it just means you can't model Adjust from a blog post, and you can model AppsFlyer.
The server-side event contract, which decides who can ship a new event. AppsFlyer's S2S endpoint takes an appsflyer_id, a free-text eventName and a JSON eventValue; adding a new backend event is a backend change and nothing else. Adjust's S2S API wants s2s=1, an app_token, and an event_token that must be minted in the Adjust dashboard first, plus an advertising id (idfa/gps_adid) or the Adjust adid to identify the device. Functionally equivalent, operationally not: on Adjust, every new server event needs a dashboard admin in the loop before a line of code ships, and your backend has to be storing an advertising identifier — a heavier lift for a bank than storing an SDK-issued id. If your roadmap is "we'll add revenue events as the core-banking team frees them up", that difference shows up every sprint.
Superapp and WebView behaviour. Both expose a native getAttribution() that returns the campaign data for the current install, which is the hook I've used to carry ad attribution into a WebView — the WebView attribution piece covers that pattern. Neither vendor's docs will warn you about the failure mode that actually costs money: stamping that attribution onto every WebView launch, including the ones that came from the superapp's own menu. Do that and already-logged-in users converting at 80% get counted as paid traffic, the paid segment's numbers become fiction, and the bidding algorithm optimises toward people advertising never brought in. The gate — attribution only on ad-origin launches — is your job in both tools.
What neither MMP will fix
Worth saying plainly, because it's sold as if they will:
- Revenue that lives in core banking. Somebody still has to write the S2S pipeline above. The MMP receives; it doesn't reach in and take.
- A dead pixel in a WebView. If most of your payments happen in a WebView where the browser ad stack is switched off, that's a server-side CAPI problem, not an MMP problem.
- Superapp traffic mixing. No vendor knows which of your own entry points is an ad. You define that.
- Your event taxonomy. An MMP with 200 inconsistently named events is exactly as unhelpful as any other tool with 200 inconsistently named events.
When to pick which
Firebase-only, when: Google Ads is effectively your entire paid mix, you're Android-heavy, your revenue events happen in-app where the SDK can see them, and your fraud exposure is low. You keep the free BigQuery export and lose nothing you were actually using. Revisit the moment a second network gets a budget line.
AppsFlyer, when: you're buying across several networks, you need Protect360-class fraud protection, you want raw data flowing into your own warehouse, and you'd like a published per-conversion price you can build a forecast on. Also when your backend team will be pushing server-side revenue events regularly — the S2S contract is the lighter one to operate.
Adjust, when: you want a single negotiated contract rather than a base rate plus a column of add-ons, your SKAN reporting and raw-data needs are straightforward, and your event set is stable enough that provisioning event tokens in a dashboard isn't friction. Get the quote before you compare — it's the only way to compare.
MMP plus Firebase together, when: you're a bank or a superapp. This is where most of my projects land. Firebase gives Google-native depth and free raw events; the MMP gives cross-network truth and the server-side entry point for real money. And the referee for any disagreement between them is the warehouse, where the MMP's raw export, Firebase's BigQuery export, and your core-banking tables sit in the same schema and can be joined on your own keys.
The takeaway
The MMP question isn't AppsFlyer versus Adjust — it's whether Google is your whole acquisition story and whether your revenue is visible to an SDK. If both are true, Firebase-only is a legitimate answer and you should stop shopping. If either is false, you're buying a neutral join point, and then the choice comes down to how you want to be billed and who has to be in the room to ship a new server-side event: AppsFlyer publishes a rate and takes any event name from your backend; Adjust quotes you a contract and wants the event provisioned in its dashboard first. Whichever you pick, the revenue event still has to be pushed from your side — and everything still has to land in a warehouse you control.
And if you're buying across several networks and still can't tell which ones produce actual disbursements, don't start with a vendor comparison. Trace one conversion end to end first — click, install, application, money — and find the step where it stops being visible. That step is almost always a missing server-side event rather than a missing feature, and no amount of switching MMPs will fill it in.
Sources
- AppsFlyer pricing — Zero plan welcome package of 12K conversions, Growth at $0.07 per conversion beyond it, separately priced add-ons (checked July 2026)
- AppsFlyer server-to-server events API —
appsflyer_id,eventName,eventValue,af_order_idde-duplication - Adjust S2S events API —
s2s=1,app_token, dashboard-provisionedevent_token, advertising id requirements - Adjust S2S security — per-request authentication tokens generated in the dashboard
- Firebase BigQuery export — raw event export used as the neutral join layer
