How Luseri calculates MRR, churn and retention
Luseri replays each store's Shopify Partner API events in time order: MRR is the sum of the monthly price of every subscription paying that day, in the currency of your plans, without trials, usage charges or one-time purchases, and the money actually collected is shown apart, in the currency of your payouts, with no conversion. Below is every rule as the code applies it on October 21, 2026, including the cases it does not handle yet.
By Arthur Renard, updated
What Luseri reads from Shopify
Everything comes from the Shopify Partner API, read-only, through an API client you create for Luseri (see how access is protected). Three kinds of data are read:
- App events, from your app's
eventsfield: installs and uninstalls (with the reason and the comment the merchant left), store deactivations and reactivations, subscription charges activated, canceled, expired, frozen and unfrozen, usage charges, one-time charges and credits. Each charge event carries the charge's ID, name, amount, currency, next billing date (billingOn) and test flag. - Payouts, from the
transactionsquery when your API client has the "View financials" permission: subscription, usage and one-time sales, adjustments and credits, each with its gross amount, net amount, Shopify's fee and, for a subscription, its billing interval (EVERY_30_DAYSorANNUAL). - Without "View financials", the same payouts come from your organization's historical events (the root
eventsquery,Earningevents), which need "Manage apps" only. This route gives no billing interval.
The first sync copies your app's whole history. Each later sync starts from the latest event already known, minus six hours, in case Shopify publishes an event late. Numbers refresh when you open the dashboard and they are more than an hour old, when you ask for it, and once a day in the background. Other event types, such as charges accepted or declined, are kept but change no number. What Luseri keeps, and for how long, is in its privacy policy.
How MRR is built
- Group the events by store and replay each store's events in time order. Events with the same timestamp follow a fixed order, from install to uninstall.
- Keep each store's current subscription and its state: on trial, paying, or suspended.
- Bring the charge's amount back to a month: an annual plan is divided by 12, any other plan is taken as it is.
- MRR on a day is the sum of these monthly amounts for every subscription paying at the end of that day. The dashboard keeps 730 days of daily values; older history still sets the starting level.
MRR leaves out free trials until their first payment, usage charges and one-time purchases (counted in cash collected only), test charges (every event whose charge has test: true is ignored), and the credits you give a store, which appear in that store's history.
Annual plans. A charge counts as annual once a payout read through the transactions query gives its billing interval as ANNUAL; its amount is then divided by 12. Until that payout has been read, and always without "View financials", an annual plan counts at its full price as if it were monthly, and a note in the settings says so. If you sell annual plans, tick "View financials" on your API client.
Discounts. Luseri applies no discount of its own and does not read Shopify's discount fields: MRR uses the amount Shopify gives on the subscription charge, and Shopify's Partner API reference does not say whether a discount is taken off that amount. Cash collected, read from payouts, is what merchants were actually billed.
Currencies. MRR is in the currency of your plans, the one found most often on your subscription charges. Cash collected is in the currency of your payouts, the one found most often on your payouts. The two are never added together and nothing is converted. If your plans, or your payouts, mix several currencies, the amounts are added as they are and the settings warn that the totals are approximate.
What moves MRR, event by event
Each movement is dated on the day it happens. On the Revenue page, new subscribers, upgrades and returning subscribers sit above the line, downgrades and cancellations below it, with the net for the period.
| Shopify event | Condition | Effect on MRR | Shown as |
|---|---|---|---|
SUBSCRIPTION_CHARGE_ACTIVATED | The store has never paid, and its next billing date is missing or less than 12 hours away | + monthly amount | New subscribers |
SUBSCRIPTION_CHARGE_ACTIVATED | The same, for a store that has paid before, even before an uninstall | + monthly amount | Returning subscribers |
SUBSCRIPTION_CHARGE_ACTIVATED | The store is not paying, and its next billing date is more than 12 hours away | None until that date, then + monthly amount | Trial, then new or returning subscriber |
SUBSCRIPTION_CHARGE_ACTIVATED | The store is already paying for another charge | + or − the price difference | Upgrades or Downgrades (nothing at the same price) |
SUBSCRIPTION_CHARGE_CANCELED, SUBSCRIPTION_CHARGE_EXPIRED | The store's current charge ends, and no other charge is activated within 10 minutes | − monthly amount | Cancellations |
SUBSCRIPTION_CHARGE_CANCELED, SUBSCRIPTION_CHARGE_EXPIRED | Another charge is activated within 10 minutes, or the event concerns a charge that is no longer the current one | None | Plan change, priced by the activation |
RELATIONSHIP_UNINSTALLED | The store was paying | − monthly amount | Cancellations |
SUBSCRIPTION_CHARGE_FROZEN, RELATIONSHIP_DEACTIVATED | The store was paying | − monthly amount | Cancellations; the store is listed as Closed or suspended |
SUBSCRIPTION_CHARGE_UNFROZEN, RELATIONSHIP_REACTIVATED | The subscription was suspended while paying | + monthly amount | Returning subscribers |
USAGE_CHARGE_APPLIED, ONE_TIME_CHARGE_ACTIVATED | Any | None | Cash collected |
CREDIT_APPLIED | Any | None | The store's history |
Any charge event with test: true | Any | None | Ignored |
Trials. Shopify's app events do not flag a trial, so Luseri infers it from the next billing date: a subscription whose billingOn falls more than 12 hours after its activation is a free trial until that date, whatever its length. On that date, if the subscription is still there, its first payment is counted, and the store's history marks it as a calculated trial end. Changing plan during a trial does not start a new trial. A trial that ends with a cancellation or an uninstall before that date never enters MRR, nor the revenue lost to cancellations: it shows as a trial stopped before the first payment.
Cash collected and Shopify's fees
Cash collected adds up the gross amount of each payout, on the day Shopify recorded it; Shopify defines that amount as what the merchant paid, excluding taxes. It is split into subscriptions (adjustments, credits and refunds included), usage charges and one-time purchases. Shopify's fee on each sale is shown apart, as Fees taken by Shopify. A refund read through the Earning route always counts as negative.
When no payout can be read at all, cash collected is estimated from the subscriptions: each paying subscription counts as billed every 30 days from its first payment, plus the usage and one-time charges found in the events. That estimate is in the currency of your plans, Shopify's fees are unknown, and the settings say so.
The Revenue page also estimates your next payout: gross revenue of the last 15 days minus Shopify's fees. What Shopify keeps from each charge is explained in Shopify's app revenue share.
Subscribers, installs and churn rates
Each metric below is computed day by day from the replay. A rate is read on the last day of the period you pick; a total, such as uninstalls or revenue lost, is summed over the period.
| Metric in the dashboard | How it is calculated |
|---|---|
| Active subscribers | Stores whose subscription is paying at the end of the day. Trials and free plans are left out. |
| Active installs | Stores that have the app at the end of the day, paying or not, minus the stores Shopify reports as deactivated (closed or paused). |
| New subscribers | Stores that start paying during the period: after a trial, without a trial, or as a former subscriber who subscribes again. A subscription resumed after a freeze does not count. |
| Trials started | Stores whose subscription starts with a trial during the period. A plan change during a trial does not count again. |
| Trials turned into subscribers | Trials that ended with a first payment ÷ all trials that ended during the period, with a payment or without one. Each trial is followed from its start to its end, whatever its length. |
| Abandoned trials | Trials that ended without a first payment during the period: stopped, uninstalled, or canceled after a suspension. |
| Recurring revenue lost to cancellations | The monthly amount of every paying subscription that ended during the period: cancellation, expiry, uninstall, freeze or store deactivation. Downgrades are counted apart. |
| Share of recurring revenue lost per month | Recurring revenue lost to cancellations over the last 30 days ÷ MRR 30 days earlier. |
| Subscribers who cancel per month | Paying subscribers who stopped paying over the last 30 days (cancellation, expiry, uninstall, suspension by Shopify) ÷ subscribers 30 days earlier. A plan change does not count. |
| Stores that uninstall per month | Uninstalls over the last 30 days ÷ active installs 30 days earlier. |
| Average revenue per subscriber (ARPU) | Cash collected over the last 30 days ÷ active subscribers. |
| Subscriber lifetime value (LTV) | ARPU ÷ share of recurring revenue lost per month. |
| Recurring revenue growth over a month | The change between MRR on a date and MRR 30 days earlier. |
Revenue churn here leaves downgrades out, while how to measure churn for a Shopify app adds them to the loss; add the Downgrades movement to get that version. A subscription that Shopify freezes counts as lost on the day of the freeze, and comes back as a returning subscriber if Shopify unfreezes it.
Retention by install cohort
A cohort is the set of stores whose first install falls in the same calendar month (UTC). The grid covers the last 12 months: for each later month, a cell gives the share of the cohort that has the app installed on the first day of that month.
- Only the first install places a store in a cohort. A store that uninstalled and installed again counts as retained if the app is installed on the checkpoint day.
- Month 1 is read on the first day of the next calendar month, so a store installed on the last day of a month is checked the next day.
- A store Shopify reports as deactivated keeps its install, so it counts as retained until it uninstalls.
- This is install retention, paying or not. Paying stores lost show in the churn rates above.
- The three headline figures, still installed after 1, 3 and 6 months, are the plain average of the cohorts old enough to have that age, not weighted by their size. The number of stores behind each figure is shown under it.
Uninstall timing: for the uninstalls of the last 365 days, the time since the store's latest install, in six bands (under 1 hour, 1 to 24 hours, 2 to 7 days, 8 to 30 days, 1 to 3 months, over 3 months). The share under 24 hours is shown as Uninstalls on the first day.
Uninstall reasons
Shopify returns the reason as a comma-separated list, plus an optional comment. Each reason is matched to a plain label: Too expensive, I was just testing, I don't use it anymore, I don't need it anymore, A feature is missing, Too hard to set up, Switched to another app, Technical problem, Not enough support, or Store closing or pausing. "Other" becomes Other reason, an empty reason becomes No answer, and text that matches no label shows as its own line.
A reason written in another language is translated by Claude, the AI model made by Anthropic, and joins a label when its translation matches one. A reason that mentions a store closing or pausing, and Shopify's scheduled_cancellation, are grouped under Store closing or pausing.
The shares cover the last 365 days. A merchant who gives two reasons counts once in each, and each share is that reason's part of all the reasons given. The comment never counts in the shares. It is kept with the uninstall and shown after the reason in the store's history and in the event feed, translated when it was written in another language. What each reason usually means is in why merchants uninstall your app.
Edge cases
- Closed stores:
RELATIONSHIP_DEACTIVATEDalso removes the store from active installs untilRELATIONSHIP_REACTIVATED; a frozen charge alone does not. A trial frozen before its end resumes as a trial, and if its end has passed by then, the first payment is counted on the day it is unfrozen. - Development stores: nothing in the app events tells them apart, so their installs count in installs, active installs and cohorts like any other store. Test charges are left out, whatever the store.
- Scheduled store closures: since April 2026, when a store closure scheduled by the merchant takes effect, Shopify uninstalls the store's apps with the reason
scheduled_cancellation, according to Shopify staff on the developer forum. Luseri groups them under their own reason, Store closing or pausing, so they do not read as a verdict on your app. They still count in uninstalls, in the uninstall rate and in cohorts like the others, and a paying store's MRR leaves as a cancellation. - Plan changes: Shopify cancels the old subscription when the new one is activated. A cancellation followed within 10 minutes by the activation of another charge is read as a plan change, and the cancellation of a charge that is no longer the current one is ignored.
- An uninstall with no install on record, when the history starts after the install, counts as an uninstall without lowering active installs.
Why the numbers differ from Shopify's dashboards
Shopify's dashboards count other things, at other moments. The full comparison of the Dev Dashboard and the Partner Dashboard is in Dev Dashboard vs Partner Dashboard.
| Question | Shopify's dashboards | Luseri |
|---|---|---|
| How many stores have the app? | Dev Dashboard Installs: every store whose install is still on record, development, closed and frozen stores included. Partner Dashboard Merchants with your app: active stores only. | Active installs: installed stores minus those Shopify reports as deactivated. Development stores and free-plan stores count. |
| How much money came in? | Dev Dashboard revenue: after revenue share, fees, refunds and chargebacks. Partner Dashboard earnings: paid out and pending, after revenue share and app credits. | Cash collected: the gross amount of each payout, excluding taxes, with Shopify's fees shown apart. |
| What is the recurring revenue? | Neither dashboard shows MRR. | MRR from subscription events, before Shopify's cut. |
| Why do merchants leave? | Partner Dashboard: each uninstall with its reason. | Reasons counted over 365 days and grouped into plain labels. |
Timing differs too: MRR moves the day a subscription starts or ends, while a payout appears only once the merchant has paid Shopify.
What has been checked, and what has not
Luseri ran on OptiDress, its maker's own app, before it opened to other developers: the revenue and installs it showed were compared with Shopify's own figures for that app (see who makes Luseri). On October 20, 2026, on the same app, the payouts read without "View financials" were compared with those read with it: same payouts, same dates, same gross amounts and same Shopify fees.
That is one real account. As of October 21, 2026, annual plans and plans or payouts in several currencies have not been checked on a real account, and the speed of the calculation was measured on simulated accounts only, up to 63,000 stores.
Three rules are Luseri's own reading of the events, because Shopify's documentation does not settle them: the 12-hour gap that marks a trial, the 10-minute window that marks a plan change, and treating a frozen subscription as lost until it is unfrozen. If one of your numbers looks wrong, write to the address on who makes Luseri. The meaning of each term is in the Shopify app metrics glossary, and the general method, tool aside, in how to calculate MRR for a Shopify app.
Questions
- Does Luseri count trials in MRR?
- No. A subscription whose next billing date falls more than 12 hours after its activation is treated as a free trial until that date. It enters MRR on that date if it is still active, and a trial canceled before then never counts.
- How does Luseri handle annual plans?
- It divides the annual price by 12 once a payout read with the View financials permission says the plan is annual. Without that permission, Shopify gives no billing interval, so an annual plan counts at its full price, as if it were monthly.
- Does Luseri convert currencies?
- No. MRR stays in the currency of your plans and cash collected in the currency of your payouts. If several currencies are mixed within one of them, the amounts are added as they are and the dashboard warns that the totals are approximate.
- Are frozen stores counted as churn in Luseri?
- Yes, from the day of the freeze: the subscription's monthly amount leaves MRR under cancellations. If Shopify unfreezes the subscription, the amount comes back as a returning subscriber.
- Why is Luseri's MRR different from my Partner Dashboard earnings?
- MRR is the monthly price of the subscriptions paying today, before Shopify's revenue share and fees. Earnings are payments made or scheduled after those deductions, and they appear only once merchants have paid Shopify.
Sources
- Shopify Partner API: app event types
- Shopify Partner API: AppSubscription (amount, billingOn, test)
- Shopify Partner API: AppSubscriptionSale (gross amount, billing interval)
- Shopify Partner API: RelationshipUninstalled
- Shopify Partner API: historical events
- Shopify developer community: the scheduled_cancellation reason (April 2026)
- Luseri: who makes Luseri
- Luseri: privacy policy