Skip to content
Metricsjar

Article · Updated August 2026

Why MRR never matches Stripe or RevenueCat

Editorial cover: separate Stripe and RevenueCat definitions reconciled to one canonical MRR bridge

Two MRR values can disagree without either system being broken. Each may use a different subscription state, normalization, discount policy, currency rate, cutoff or source history.

Do not start by averaging the totals. Reproduce each definition, reconcile the population and then choose the MRR policy used for the founder report.

MRR reconciliation bridge from source definitions through population and policy differences

MRR is a model, not a cash total

MRR estimates the monthly-normalized recurring value of a defined active subscription population. It is not necessarily:

An annual $1,200 subscription may contribute $100 MRR while creating a $1,200 transaction in one month. Expecting those columns to match creates a false discrepancy.

Write the definition for every compared number

Policy fieldQuestions
PopulationWhich products, stores, accounts and environments?
Active stateActive, trial, past due, grace, cancelled-not-expired?
NormalizationHow are weekly, monthly and annual products converted?
DiscountsIncluded at list price or net recurring price?
UsageIncluded, estimated or excluded?
CurrencySource currency, display currency and rate date?
TimeInstant snapshot, daily close or period end; which timezone?
RefundsDoes a refund rewrite historical recurring values?
IdentityHow are aliases, transfers and migrations handled?
Data sourceSubscription objects, invoices, receipts or transactions?

Without this table, “Stripe MRR” and “RevenueCat MRR” are labels, not comparable measures.

Reproduce Stripe first

Stripe Billing documents its MRR definition and configurable treatment. Record the current settings rather than assuming the default:

Export the underlying subscription/invoice population when available. Recreate the value per subscription, then total it. The first goal is to match Stripe under Stripe’s rules.

Reproduce RevenueCat separately

RevenueCat says its charts use the current snapshot of stored purchase receipts and can revise historical data when receipts change, such as after a refund. It also documents that its numbers can differ from Apple, Google or Stripe because of migrations, definition differences and estimates such as currency conversion or taxes.

Record:

RevenueCat’s overview also distinguishes gross revenue in the last 28 days from current MRR. Do not compare those two cards as if they share a basis.

Keep app-store reporting separate

App Store Connect subscription and proceeds reporting answers store-specific questions. Store fiscal/calendar boundaries, transaction state, proceeds estimates and subscription status can differ from a cross-platform normalized chart.

Use Apple for Apple transaction/proceeds facts, the billing source for its subscription states and your chosen model for canonical MRR. Name the owner per measure instead of declaring one universal source of truth.

Reconcile populations before values

Create a source comparison by subscription/product:

Difference classCheck
Missing subscriptionMigration, receipt/API coverage, account/project filter
Extra subscriptionSandbox, duplicate identity, cancelled-not-expired state
Different amountPrice change, discount, tax/gross basis, product mapping
Different intervalAnnual/monthly normalization or intro period
Different statusGrace, past due, cancellation, expiration, refund
Different currencyDisplay rate and conversion date
Different cutoffSnapshot time, timezone and source refresh

Count subscriptions in each class and total their MRR effect. Do not inspect only the grand total.

Build a subscription-level comparison file

Use one row per canonical subscription at the same snapshot time:

FieldPurpose
Canonical subscription keyJoin the same commercial relationship
Source/store and accountPreserve the owning system
Source subscription/receipt IDTrace back without relying on display name
Product and intervalNormalize only mapped recurring products
Original price/currencyPreserve source truth
Discount/intro stateExplain net recurring amount
Start, current period end, cancelled and expired timesReproduce lifecycle policy
Billing/grace stateSeparate open exposure from final loss
Source MRR contributionRecreate the displayed definition
Canonical MRR contributionApply the chosen contract
Difference codeGroup the reconciliation

Do not place payment card data or unnecessary personal fields in this file. Use stable source identifiers and restrict access.

Validate totals in this order:

  1. reproduce the number of contributing subscriptions in each source;
  2. reproduce source MRR contribution by product/store;
  3. identify unmatched or duplicate records;
  4. apply one canonical adjustment class at a time;
  5. prove the bridge arithmetic;
  6. store the snapshot and configuration used.

This prevents several small differences from being hidden inside one unexplained “other” row.

A fictional reconciliation

Bridge from RevenueCat to canonical MRRAmount
RevenueCat displayed MRR$14,080
Remove sandbox/mis-scoped product−$120
Exclude cancelled-not-expired under canonical policy−$310
Add migrated Stripe subscriptions missing receipts+$460
Apply canonical discount treatment−$95
Apply canonical currency snapshot+$35
Canonical MRR$14,050

Then reconcile Stripe:

Bridge from Stripe to canonical MRRAmount
Stripe displayed MRR$10,420
Add app-store recurring value+$3,760
Remove usage estimate excluded by policy−$170
Apply status/discount/currency differences+$40
Canonical MRR$14,050

These values are fictional. The bridge proves how each displayed total reaches the same policy; it does not claim that these adjustment classes occur everywhere.

Treat cancellation and expiration carefully

A customer can disable renewal while remaining active until the paid period ends. RevenueCat’s status and churn documentation distinguishes cancelled-not-expired subscriptions from churn at expiration. A model that removes value at cancellation will differ from one that retains it until expiration.

Neither is meaningful without a label. For operating MRR, choose the policy that reflects the recurring value question and keep cancellation-risk exposure as a separate measure when useful.

Handle grace and billing issues deliberately

Past-due and grace-period subscriptions may remain active or be treated differently by source configuration. Record:

Find failed payments before they become churn describes the incident lifecycle. Keep unresolved exposure separate from final involuntary loss.

Control product and currency mappings

Maintain:

Source productCanonical productIntervalRecurring class
price_web_pro_monthlyProMonthlyRecurring
ios.pro.annualProAnnualRecurring
android.pro.lifetimeLifetimeOne-timeExcluded from MRR

For currency, retain original amount/currency and record reporting currency, rate source, rate timestamp and rounding. A live display rate will change the total even when the subscription population is unchanged.

Diagnose common mismatch patterns

The gap equals annual-plan cash

You are probably comparing transaction revenue with normalized MRR. Reproduce annual subscription contribution as price divided by the stated monthly normalization; keep cash separate.

The gap appears after a migration

Check which historical receipts or subscriptions were imported, when customers were first seen and whether the new system can reconstruct the prior lifecycle. Keep an explicit “not represented in source chart” class.

The gap grows around cancellations

Compare cancellation time, paid-through/expiration time and each policy’s removal point. Report scheduled-to-cancel MRR separately if it matters operationally.

History changes after refunds

Identify which source restates historical revenue or subscription state from current receipts. Store published snapshots if the founder report must explain a previously reported value.

The total moves without customer events

Check currency conversion, price/product mapping, source configuration, late receipt refresh and timezone cutoff before interpreting it as growth or churn.

Only one product or store is wrong

Reconcile that segment before changing the global formula. A missing mapping or store-specific lifecycle rule is more likely than a universal MRR failure.

Freeze a canonical MRR contract

Define:

Store the source configuration snapshot beside it. If the contract changes, annotate or restate history. Do not splice two definitions into one trend line.

Put the discrepancy in the founder report

Show:

Example:

Ending canonical MRR is $14,050. RevenueCat displays $14,080 because the source view includes $310 cancelled-not-expired value, omits $460 of migrated Stripe subscriptions and applies different discount/currency treatment. The bridge reconciles fully; no ingestion incident is open.

That is more useful than “MRR is wrong.”

Frequently asked questions

Which MRR is correct?

Each can be correct under its documented policy. Choose a canonical policy for the business question and reconcile every source to it.

Should cancelled subscriptions stay in MRR?

Define whether MRR reflects currently active paid access or expected renewal. If you retain cancelled-not-expired value, show scheduled cancellation exposure separately.

Why did historical RevenueCat numbers change?

RevenueCat documents that charts are based on current receipt snapshots; refunds and other receipt changes can revise history.

Why does MRR not match this month’s revenue?

MRR normalizes recurring subscription value. Transaction revenue reflects purchases/refunds in a period and may contain annual or one-time value.

Should we build our own calculation?

Only when the business needs a policy different from source displays and can own mappings, lifecycle state, correction handling and validation.

Sources

Keep reading