DIAGNOSE
| Built | shotlingo.com |
|---|---|
| Shipped | 6 iOS apps: Breaker, QuickBill, Travelized, Quizzy AI, MoodGarden, Amoura |
| Published | 6 open datasets |
| Updated | 2026-08-03 |
This page is a decision tree, not a single answer. Five sections follow, each a specific, documented mechanic behind a mismatch between RevenueCat, Mixpanel or Amplitude, and App Store Connect. Work through them in order against your own numbers: each section either explains the gap or rules itself out, and you move to the next.
Every mechanic below is checked against current vendor documentation, cited inline with the date checked. Where a discrepancy depends on how your team configured an integration, that is stated plainly, and where I could not confirm something, that is stated too.
Not sure this applies to your numbers yet? send me the two numbers that disagree → and I'll tell you which section below to start with.
There is no real example under this heading. An invented app with invented monthly figures would be exactly the unverifiable claim this site was rebuilt to avoid. Instead, here is what each source is actually built to measure, and what it leaves out. Once you know that, you can pull your own three numbers and know which parts of the gap are structural.
| Source | What it measures | What it leaves out |
|---|---|---|
| RevenueCat | Revenue inferred from the subscriber record RevenueCat validates server-side against Apple. Gross by default; a per-integration "Sales reporting mode" can switch a destination to net of commission, or net of commission and tax. Booked on transaction date. | Refunds, until Apple confirms them. Sandbox and TestFlight transactions, unless sandbox data is explicitly included. The exact price charged, if the product's price changed in App Store Connect after the transaction (RevenueCat infers price from what was configured at purchase time). |
| Mixpanel / Amplitude | Whatever value the app's code passes to the revenue-tracking call, in whatever currency it passes. Fired from the device. Amplitude marks a purchase "Verified" only if the App Store shared secret and receipt data are wired in; otherwise "Unverified." Mixpanel has no built-in receipt verification for in-app purchases. | Refunds and chargebacks, by default: nothing on the device fires when Apple reverses a charge server-side. Any purchase the client never successfully reports (offline, the app killed before the call completed, the SDK's send queue never flushed). Grace-period and billing-retry renewals that succeed while the user never reopens the app. |
| App Store Connect: Sales and Trends | Apple's own next-day estimate, in USD, using a rolling average of the previous month's exchange rates. | Transactions not yet processed, collected and invoiced, which can slip into the following fiscal month. The final settlement-date true-up. |
| App Store Connect: Payments and Financial Reports | Apple's official, final payout figures: net proceeds after commission and tax, in local currency as transacted, booked on settlement date, aligned to Apple's own fiscal calendar rather than the calendar month. | Sandbox and TestFlight transactions (never billed, so never reported). Anything not yet collected by the time the report is generated, roughly five business days after the fiscal month ends. |
(App Store Connect Help, "Differences in reporting tools", checked 2026-08-03. RevenueCat, "Taxes and Commissions" and "Reconciling with App Store Financial Reports", checked 2026-08-03. Amplitude, "Track revenue", checked 2026-08-03.)
RevenueCat's dashboard has two revenue numbers, both correct for what they measure. "Revenue" is gross: the price the customer paid, before Apple's commission or tax. "Proceeds" is net: revenue minus RevenueCat's estimate of tax and commission (RevenueCat, "Taxes and Commissions", checked 2026-08-03). If you read the "Revenue" card and compare it to App Store Connect's Financial Reports, which are always net, you are comparing gross to net, and the RevenueCat number will read high by roughly Apple's commission rate.
That rate is not fixed. Apple takes 30% of a subscriber's payments during their first year of paid service and 15% after they accumulate one year of paid service, tracked per subscription group; free trials and renewal extensions do not count toward that year (Apple Developer, "Auto-Renewable Subscriptions", checked 2026-08-03). A developer enrolled in the App Store Small Business Program, open to developers who earned up to 1,000,000 USD in proceeds the prior year, pays 15% from day one regardless of subscriber tenure (Apple Developer, "App Store Small Business Program", checked 2026-08-03). A "net" figure computed with a flat 30% assumption and a "net" figure from a tool that knows about the year-two reduction, or Small Business Program enrollment, will disagree even when both are honestly reporting net revenue.
RevenueCat also lets you set that "Sales reporting mode" per integration, independently of what the main dashboard shows. An individual Mixpanel or Amplitude connection can be configured to receive gross revenue, revenue after commission, or revenue after commission and tax, while the RevenueCat dashboard itself keeps showing gross (RevenueCat, "Taxes and Commissions", checked 2026-08-03). If nobody remembers which setting was picked when the integration was first connected, the analytics-tool number and the RevenueCat-dashboard number can differ by the commission rate alone, with no real transaction-level discrepancy underneath it.
What to check: in RevenueCat, compare the "Revenue" card to the "Proceeds" card for the same period, and open Project Settings, then Integrations, to read the Sales reporting mode for whichever analytics tool you are comparing against. In App Store Connect, confirm you are reading Payments and Financial Reports, which are net, not Sales and Trends' sales figures. If the gap between two sources is close to 15% or 30% of the larger number, this is very likely your answer.
Every one of these tools converts foreign-currency transactions to USD at some point, and none of them do it the same way.
Apple's Sales and Trends report "estimates sales and proceeds in USD using a rolling average of previous month's exchange rates," though its downloadable reports also show the original local-currency amounts. Payments and Financial Reports instead finalize payments "using the exchange rate applied to convert each report's currency to your bank account's currency": a real settlement rate, applied later, not an estimate (Apple Developer, App Store Connect Help, "Differences in reporting tools", checked 2026-08-03).
RevenueCat converts using Open Exchange Rates at the purchase date; by its own account, the rate Apple actually settles at "is likely better than what's publicly quoted on that day," and the figure is not finalized until roughly 33 days after the period ends (RevenueCat, "Reconciling with App Store Financial Reports", checked 2026-08-03).
Mixpanel and Amplitude do neither. Their revenue APIs take whatever price value your app's code passes them, in whatever currency you pass. Neither performs currency conversion (Amplitude, "Track revenue", checked 2026-08-03). If the app logs the product's USD list price instead of the amount actually charged in the customer's local currency, every non-US transaction is wrong from the moment it is logged. I have not verified how any specific app's integration is implemented; this is a known risk in how these APIs are designed, not a claim about your app.
Because three sources use three different rates on three different dates, there is no single "high" or "low" direction that holds every month: it depends on whether the currencies in your revenue mix rose or fell against the dollar in that period. What is checkable is the mechanism. Pick one non-USD transaction, get its local-currency amount from the receipt or App Store Connect, and check what USD figure each source assigned it. Back out the implied rate by dividing the USD amount by the local amount, and compare it to the public rate for that currency on that date. A drift of a percent or two across a month's revenue is normal FX noise. A drift far larger than the currency actually moved is something else, most likely cause one or cause five below.
Still stuck after this section? have me look at it directly →. The rest of this page rules out the remaining causes one at a time.
RevenueCat and Apple both model a subscription as a sequence of typed events, and the two type systems do not line up one to one.
RevenueCat's webhooks send INITIAL_PURCHASE when "a new subscription was purchased," including a trial, tagged with a period_type of TRIAL, INTRO, NORMAL, PROMOTIONAL or PREPAID. When a trial converts to paid, RevenueCat sends RENEWAL, defined as "an existing subscription was renewed, or a lapsed user resubscribed," the same type used for an ordinary renewal later (RevenueCat, "Event Types and Fields", checked 2026-08-03). A downstream tool that counts every RENEWAL as new revenue without also reading period_type or price cannot separate a spike in trial conversions from a spike in ordinary renewals.
Apple's own App Store Server Notifications use a different vocabulary again: DID_RENEW when a subscription "successfully renewed," with a BILLING_RECOVERY subtype after a billing retry; DID_FAIL_TO_RENEW when a subscription "failed to renew due to billing issue and entered billing retry period," with a GRACE_PERIOD subtype while service should continue; and GRACE_PERIOD_EXPIRED when the "billing grace period ended without renewing subscription" (Apple Developer, App Store Server Notifications, notificationType reference, checked 2026-08-03). A renewal that fails on schedule and recovers four days later during the grace period is one real transaction, but it produces a DID_FAIL_TO_RENEW notification and, days later, a separate DID_RENEW notification. A system that only counts the first notification per subscriber per period misses the eventual charge; one that counts every notification double-counts it.
This is also where refunds live. RevenueCat sends CANCELLATION when "a subscription or non-renewing purchase was canceled or refunded," and REFUND_REVERSED, "a refund was reversed," if Apple later reverses it (RevenueCat, "Event Types and Fields", checked 2026-08-03). RevenueCat and App Store Connect both eventually net refunds out of revenue. A client-fired analytics event cannot: a refund happens on Apple's servers, with no moment where the user's device is involved, so nothing in a client SDK fires to subtract it. Unless a team has separately wired refund events into their analytics tool, that tool's revenue total stays high by the value of every refund, indefinitely.
What to check: pick a subscriber you know went through a billing-retry recovery, or a transaction you know was refunded. Look for that specific dollar amount in each of the three tools. If it is present in RevenueCat and App Store Connect but still counted in your analytics tool's revenue total, refunds are your gap, and the fix is a pipeline change, not a reconciliation exercise you repeat every month.
RevenueCat does not ask the device what happened. It validates the receipt, or calls the App Store Server API, against Apple directly, and only records a transaction once Apple confirms it (RevenueCat, "App Store Receipt Validation", checked 2026-08-03). App Store Connect's numbers are Apple's own record by definition. Neither depends on the app being open, the network being available, or an SDK's send queue flushing.
Mixpanel and Amplitude's revenue tracking is different in kind, not just in accuracy. A client SDK call fires from code running on the customer's device, at whatever point the app's own code calls it. Amplitude will validate a purchase if you pass it receipt data and an App Store shared secret, splitting revenue into "Revenue (Verified)" and "Revenue (Unverified)" buckets; without that wiring, everything lands unverified, meaning nothing has actually been confirmed against Apple (Amplitude, "Track revenue", checked 2026-08-03). Mixpanel has no equivalent built-in verification for in-app purchases at all.
A client-fired event can fail in three distinct, checkable ways, each moving the number in a specific direction. It can be lost: the app is killed before the network call completes, or the user goes offline and removes the app before the SDK's queue flushes, so revenue never reaches the analytics tool, and the number reads low. It can be duplicated: a purchase-completion handler that retries after a timeout, or fires again on a later launch because the transaction was never finished, sends the same revenue twice, and the number reads high. Or it can fire early: sent the moment StoreKit calls back, before the transaction has settled, counting revenue Apple may still reject, again reading high relative to RevenueCat.
There is a fourth, distinct way client-fired analytics reads high, worth checking separately since it is a configuration problem, not a device-reliability one. Every TestFlight build uses Apple's sandbox purchase environment automatically and never charges real money (RevenueCat, "Apple App Store & TestFlight", checked 2026-08-03). App Store Connect never bills or reports these transactions, and RevenueCat hides them from its dashboard by default. But RevenueCat's own webhook integrations forward sandbox events to third-party destinations unless told otherwise, and Mixpanel and AppsFlyer both have a separate sandbox API key field: leave it filled in, and every tester's purchase gets reported as real revenue. RevenueCat's own support staff confirm exactly this: "If you remove the sandbox keys from the settings pages below, that should stop sending events for sandbox purchases" (RevenueCat Community, "Disable integrations for Sandbox events", checked 2026-08-03). A team that connected an integration during development and never revisited it can have this running indefinitely.
What to check: in RevenueCat's integration settings for your analytics tool, look for a sandbox key field and check whether it still has a value. In the analytics tool, filter revenue by whatever sandbox or environment property RevenueCat attaches, and see whether the total changes when you exclude it.
Apple runs two separate reporting systems on two separate schedules, and neither is wrong: they answer different questions.
Sales and Trends is fast and approximate: daily reports the next day, monthly reports roughly five days after the month ends, USD estimates built on a rolling average of the previous month's exchange rates. Payments and Financial Reports are slow and final: local currency as transacted, a settlement-date exchange rate, and "transactions initiated in a particular month may not appear in Sales and Trends Reports until the customer's payment is processed, collected, and invoiced, possibly in the following fiscal month" (Apple Developer, App Store Connect Help, "Differences in reporting tools", checked 2026-08-03).
Financial Reports are also built on Apple's own fiscal calendar, not the calendar month: "Apple's payout schedule adheres to their fiscal calendar, which almost never identically matches a calendar month," citing a January 2025 fiscal month that ran from December 29, 2024 to February 1, 2025 (RevenueCat, "Reconciling with App Store Financial Reports", checked 2026-08-03). Compare RevenueCat's or Mixpanel's calendar-month August to App Store Connect's fiscal-month August, and you are comparing two different date ranges by construction, which alone can produce a discrepancy with no real transaction-level problem behind it.
RevenueCat also books by transaction date, the date the purchase was initiated, while Apple's Financial Reports book by settlement date, the date the payment actually cleared. The same guide gives the case that matters most in practice: a subscription "renewal that was due on November 29, but fails to renew, and then later succeeds on December 4 during its grace period, will appear in Apple's financial reports based on the settlement date of December 4, while RevenueCat will report it on November 29." Refunds move the same way in reverse: "Apple's financial reports attribute refunds to the date when they occur," while RevenueCat deducts a refund from the period of the original transaction (RevenueCat, "Reconciling with App Store Financial Reports", checked 2026-08-03).
What to check: before comparing two months, get the exact fiscal period start and end dates printed on the App Store Connect Financial Report, and compare RevenueCat's or Mixpanel's total for that same date range, not the calendar month with the same name. If that closes most of the gap, what remains is real. If a large gap remains, go back to whichever of causes one through four you have not yet ruled out.
There is no single right number, only a right number for each question.
For a bank reconciliation, a tax filing, or a figure in a financial statement: use App Store Connect's Payments and Financial Reports. It is Apple's own final, audited settlement figure, in the currency your bank account actually receives, and every other source on this page is either an estimate of it or a different measurement entirely. RevenueCat's own documentation reaches the same conclusion about its own product: "Use RevenueCat for trend analysis... Rely on Apple's financial reports for accurate payout data, financial reporting" (RevenueCat, "Reconciling with App Store Financial Reports", checked 2026-08-03).
For a same-day or same-week read on whether revenue is moving, whether a release regressed conversion, or whether a pricing test is working: use RevenueCat. It updates faster than Apple's monthly settlement cycle, validates server-side so it does not depend on the app being reopened, and does not need the fiscal calendar to close before you can trust it. Read the "Revenue" or "Proceeds" card consistently, and know which one you picked.
For correlating revenue with product usage, feature flags, or cohort behavior: use Mixpanel or Amplitude, but only as a relative signal, not an absolute dollar total. Compare cohorts inside the same tool, where the same measurement biases apply to both and mostly cancel out. Do not put the tool's total revenue figure in a document that claims to be an accounting record.
If two numbers agree and one does not, the section describing the disagreeing source's mechanic is almost always the explanation. If all three disagree, work through the sections in order: gross versus net first, since it usually accounts for the largest share, then currency, then event type, then validation method, then timing.
If you've worked through the sections above and the gap still doesn't add up, or you don't have time to check five dashboards by hand every month, that's what the diagnostic below is for.
Send me your numbers → and I'll tell you which of the causes above is yours.
[ 01 ] Get the next one
One article when the next one ships. No spam, unsubscribe anytime.
[ 02 ] Get this done
Send the product URL and what looks wrong. A real reply, not an autoresponder.