A native revenue dashboard for macOS

One dashboard for App Store, Google Play and Stripe revenue

App Sales Dash reads your App Store, Google Play and Stripe reports straight from the stores and keeps everything on your Mac. Subscriptions, paid apps and one-time purchases count side by side, for one app or all of them. Daily figures start as estimates and switch to the stores' own finals, and the change is named in the notes, never applied quietly. Gaps are drawn as gaps, not zeroes. When a payout reaches the bank, you tick it off and export the statement your accountant needs.

Made for Macs running macOS 15 or later.

The App Sales Dash Overview for the last 30 days, with sample data. The toolbar shows the app filter set to All apps, the timeframe and the money basis; the window subtitle names the period the figures are compared with, and a dot per store sits at the right. Revenue shows revenue with its estimate label, the subscriptions, one-time sales and refunds inside it, and MRR as a measured rate. Sales shows Downloads, Net units sold and Sales revenue, each with its change. Subscribers shows Paid subscriptions, Trials, New subscriptions, Cancellations, Churn and Trial conversion. Below, the revenue trend shades the stretch that will be restated, and revenue by store stacks App Store, Google Play and Stripe per day, with refunds drawn below zero.
The Overview screen, running on the app's built-in sample data.
  • Native macOS app
  • Local data, no server
  • No account, no analytics
  • Read-only store connections
  • Every figure labelled estimate or final

What it's for

Store dashboards disagree with each other, restate figures without a word, and none of them matches the bank statement on its own. App Sales Dash exists for the moment those numbers have to be accounted for. It consolidates all three sources into one local ledger with one set of definitions, for one app or all of them. Figures use your consolidation currency, by default the one your stores pay out in, converted at ECB daily reference rates.

You can always tell which figure you are looking at. A figure on screen always says what it is: the store's own final, an allocation of a final across days, an estimate that will be restated, or no figure at all, so a day the stores never reported shows up as missing, and you do not go hunting for a slump that never happened. A figure with nothing behind it reads No data, never 0. A quiet day inside a reported period reads 0, because that is what happened.

  • App Store

    Apple's daily figures are estimates, and its settled total arrives weeks later, for a month that starts and ends mid-calendar. So an Apple number rarely matches the month you were asked about. App Sales Dash swaps in the final when it lands and shows the calendar month beside Apple's own, so August means August. The app also reads what your customers paid: first as an estimate, then as Apple's settled figure from the monthly report.

  • Google Play

    Play's most recent days keep moving: its figures are estimates, and subscriber counts arrive a few days behind. A dip at the end of the month can be nothing but reporting that has not caught up. App Sales Dash marks those days provisional, so you can tell a quiet week from a late one. It also fetches the reports for you.

  • Stripe

    Stripe settles immediately, so its figures never change, but they sit apart from your store numbers, counted a different way. App Sales Dash puts them beside the other two under one set of definitions, and its payouts are the quickest to match against a line on your bank statement.

You connect each store once in Settings, and from then on the figures arrive on their own.

How the three stores compare

The Stores panel of Settings. App Store, Google Play and Stripe each read Connected with a green dot and the time of the last test, with a Test button and a ··· menu, and under each the day its data runs through. A footer says the credentials are kept in your login keychain and sent only to each store.
Settings, Credentials, running on the app's built-in sample data.

Feature overview

  • One timeframe, every screen: set the period once and every screen answers for the same days.
  • Estimate or final: every figure says how settled it is.
  • Revenue you can take apart: by store, by plan, by country, by app, and subscriptions set against one-time sales.
  • Sales and downloads: first installs from the App Store, paid apps and one-time purchases from every store, by version and by country.
  • One app or all of them: pick an app once and every screen, and every statement, follows.
  • Refunds in plain sight: every total shows what it includes; every refund is listed on the statement.
  • Subscriptions in motion: active, trials, churn, and where MRR moved.
  • MRR from what you were paid: measured, not read off a price list.
  • Plan names you recognise: not store identifiers.
  • Restatements named: when finals replace estimates, the notes say which period changed and when.
  • A payout ledger: what each store owed against what the bank credited, with the expected payouts filled in for you.
  • Statements for accounting: PDF and CSV, per store and consolidated.
  • History kept: every report archived, past the year Apple keeps its own.
  • A backup that is one file: database and archive in a single zip.

More than one app? Pick one, or see them all

A picker beside the timeframe offers all your apps, one app, or what is not assigned yet, and every screen follows it, from the Overview to the statement export. The same app on the App Store and Google Play counts as one app. Name, merge or split your apps in Settings, and tell the app which Stripe prices belong to which product. From then on, which app carried the quarter is a one-click answer.

The Revenue screen

Revenue by store, plan and country

Revenue over any span you choose, split by store or by product, with a per-country table beside it. When someone asks which app carried the quarter, you pick that app and every screen answers, even when it sells on two stores.

Fees, tax and refunds per store, where the store reports them, and subscriptions set apart from one-time sales. Downloads and sales have a screen of their own, so a country with two hundred downloads and two purchases reads as exactly that. Every figure says whether it is settled or still moving.

The Revenue screen, split by plan. Revenue over time stacks each plan and one-time product per day, with Store, Plan and Type and Day, Week and Month in the chart’s header. Settled days are solid, estimated days lighter, and refunds are drawn as red bars below zero. The range totals list each plan, then Refunded and Net.
The Revenue screen, running on the app's built-in sample data.

Refunds in plain sight

Your totals do not change, but you can see what is inside them. The Overview shows revenue including refunds and how many units came back. The Revenue screen lists refunds per store and draws them below zero in red. The statement lists every refund and prints gross, refunds and net, so nobody has to ask why a month came in lower than the sales suggested.

The Subscriptions screen

Subscribers, trials and where MRR moved

Active subscribers and trials over time, new and cancelled set against each other with the net between them, and a trial funnel from started to converted. A month that added forty and lost thirty-eight reads as the flat month it was.

MRR movements split the change into new, upgrades, downgrades, cancellations and returning customers. The per-plan table uses the names you use with customers, so you can quote a plan without translating an identifier first.

The Subscriptions screen. Active subscriptions draws paid subscriptions and trials as two charts on their own scales, with the most recent stretch shaded as provisional. New and cancelled shows new subscriptions as green bars above the line and cancellations as red bars below it, with a net line. Below, the trial funnel and MRR movements.
The Subscriptions screen, running on the app's built-in sample data.

When something changes

Nothing changes quietly

A store that refuses a key or keeps failing turns its dot red in the toolbar, and its row in Settings says what went wrong and what to do about it.

When the stores’ finals replace the estimates, the chart’s notes name the period and the day the finals landed. When an app update reads your stored reports more accurately, Notifications says what moved.

Settings with App Store and Google Play reading Connected and Stripe reading Needs attention, with a Fix permissions… button. Under Stripe the full message says the key authenticates but no longer carries one permission, so payouts cannot be reconciled until it is granted again. In the toolbar above, Stripe’s dot is red.
A store that needs attention, running on the app's built-in sample data.

The Reconciliation screen

Match store payouts to your bank statement

A payout lands in the bank and the old routine starts: find the store's report, rebuild the expected figure, work out whether the gap is a fee, an exchange rate or a mistake. Here the expected amount is already there, and Stripe's payouts arrive already matched. For the App Store and Google Play you type what the bank actually credited, and within a minute you know whether the payment is right.

When a payment is short, the shortfall stays on the record instead of being absorbed into a total. And you start from your first full month with the app, so there is no year of old bank statements to match up first.

The Reconciliation screen’s Payout ledger, covering all store accounts and every period since July 2026. Above the table sit Record bank credit, Mark selected and Select before Jul 2026, and a note that 18 ignored rows are hidden, with a Show ignored switch. Each row gives the period, store, expected and received amounts, the date received, the difference and a status: Expected, Mismatch, Matched or Matched by hand.
The Reconciliation screen, running on the app's built-in sample data.

Estimates and finals

Every figure is labelled estimate or final

Every monetary answer in App Sales Dash carries a basis, drawn so the difference is visible at a glance:

How a run of days is labelled A row of bars across a timeline: settled days, including days apportioned from a settlement total, are drawn solid, unsettled days are drawn in a lighter shade, and a day no store reported is left empty and marked rather than drawn as zero.
Settled days are solid, including days apportioned out of a settlement total. The lighter stretch is still estimates and will be restated when the store settles it, and the app says so in advance. The break is a day nobody reported, marked rather than drawn as a zero.
  • Final: the store's own settled figure for those days. It will not change.
  • Allocated: a settled total spread across its days. Exact for the period as a whole, an inference for the individual day. Apple settles over spans that start and end mid-month, which makes this the normal case for a calendar view.
  • Estimate: no finals have landed yet. Drawn in a lighter shade, because it will be restated when the store settles the period.
  • Part estimate: the span covers settled and unsettled periods both.
  • No figure: nothing was reported. It is marked as missing rather than drawn as a zero, so you can tell a day with no sales from a day the store has not sent yet.

Three more places where you would otherwise be guessing: rows whose currency has no exchange rate for the day are left out and counted, and the chart says by how much the total is short. Days nobody reported break the line instead of being drawn through zero. And the app states when each period's finals are due, and says so plainly when they are overdue.

See how estimates become finals

For your accountant

Monthly statements your accountant can file

Close the month in one export. Choose the month and what it covers, and App Sales Dash writes a PDF your accountant can read and a CSV with the same figures for their spreadsheet or bookkeeping software. A consolidated statement gives each store its own section and subtotal, then the totals across all stores.

  • Per store, per app or consolidated: a statement for each store, one across all three, or one for a single app.
  • Every sale in its own currency: each product per storefront currency, totalled in yours.
  • Refunds listed one by one: gross sales, refunds and net proceeds, each refund with its date, product and country.
  • The payout beside your bank: what each store owes you and when, next to the credit you recorded.
  • The store's own period, stated: the calendar month and the settlement period, so nobody guesses which days a total covers.
  • Your letterhead, or none: your company, address and logo on every page, and nothing of ours.
The first page of a consolidated statement for September 2026 from an invented company, Harbor Lane Apps Ltd. Its letterhead and title sit above the period, September 2026 with the settlement period of 30 August to 30 September 2026, a basis line saying every figure is summed from the stores’ own final reports, and the document name. Below, the App Store section begins: its sales lines for amounts in CHF, EUR and GBP list each subscription and one-time product with units, customer spend, fees, tax, refunds and proceeds.
Page 1 of a consolidated statement: letterhead, period and the App Store’s section, the first of one section per store.
Page 5 of the same statement. The Stripe section ends with its subtotal per currency and the Stripe total in CHF. Totals by currency, all stores, give gross sales, refunds, net proceeds and the figure in CHF for CHF, EUR, GBP, JPY and USD, followed by the total across currencies, all stores: CHF 46,772.93. A Refunds table lists three refunds with date, store, product, country, units and amount.
Page 5: the last store’s subtotal, the totals across all stores with gross sales, refunds and net proceeds, and every refund listed.
The payout table from a consolidated statement for September 2026. One row per store: the App Store with its settlement period of 30 August to 26 September, proceeds of CHF 31,060.14 expected on 29 October; Google Play, CHF 12,540.19 expected on 15 October; Stripe, CHF 3,172.59. Each row has a bank credit column, none recorded yet, and the status expected.
From the consolidated statement: what each store owes you for the month, when it is due, and the bank credit you recorded against it.

HARBOR_LANE_Statement_2026-09_AppStore.csv

SectionSKUUnitsCurrencyCustomer spendRefundsProceedsProduct kind
Sales linelite.monthly99CHF566.280.00396.00subscription
Sales linelite.monthly170EUR1021.000.00714.00subscription
Sales linelite.monthly98GBP509.64-3.60352.80subscription
Sales linelite.yearly96CHF4667.520.003264.00subscription
Sales linesales.mac47CHF940.940.00658.00oneTimePurchase
Sales linesales.unlock96EUR1310.76-9.45907.20oneTimePurchase
The App Store statement for the same month as CSV, ready for a spreadsheet or a bookkeeping import. An excerpt: eight of its columns and six of its lines. Company and figures are invented; the PDF and CSV were written by the app's own renderers.

Your data

Everything stays on your Mac

App Sales Dash stores its database and raw report archive on your Mac. There is no server, no account, and no analytics. Credentials go straight into the macOS Keychain and are sent to the three stores' own APIs and nowhere else.

Every store connection is read-only: the app can read your reports and can do nothing else to your store accounts. It writes nothing, anywhere, ever: the credentials it asks for cannot.

Read about safety and privacy

Who it's for

Solo developers

You sell one app on three stores, as a subscription, a paid download or a one-time unlock, and the only revenue picture you have is three dashboards that disagree. You want one figure per month, and to know when it is still going to change.

Small studios

A few apps, a few people, one person who does the books. Everyone runs the dashboard locally; the statements are what get handed over. Pick an app and every screen answers for it; the statement for one app goes to whoever needs it.

Whoever reconciles the payouts

You match store payouts against bank statements. You need expected amounts per period, a place to record what actually arrived, and a difference that is written down instead of ignored.

Anyone doing this by hand today

You have been rebuilding this from CSV downloads every month. The app fetches, archives, normalises and restates so you stop doing it by hand.

Anyone who has reported a month and then watched it change

You have watched a store restate last month without a word. Here, figures are labelled estimate or final, and every restated period is named in the notes.

How it's built

  • Native macOS interface built with Swift and SwiftUI.
  • Local SQLite ledger plus an immutable raw report archive; when a report reader improves, the archive is re-read locally and changed figures are announced. Nothing is re-downloaded.
  • Estimate/final merge with five figure bases; restatements surfaced, never silent.
  • Normalisation into your consolidation currency — by default the one your stores pay out in — at ECB daily reference rates. Rows with no rate are excluded and counted, never converted at a guess.
  • Read-only connections to all three stores; the app writes nothing to any store account.
  • Credentials in the macOS Keychain, sent only to the stores' own APIs.
  • Statement exports read one consistent snapshot, so a sync mid-export can never mix figures.
  • Updates through the Mac App Store; requires macOS 15 or later.

App Sales Dash for Mac

Consolidate, label, announce, reconcile and export, without your figures ever leaving your Mac.

App Sales Dash keeps its data and credentials on your Mac. No account is required.

Last updated