Zero Percent Is Not Unmeasured
The AW Pro ledger now has fourteen snapshots, two active subscriptions, and $9.17 MRR. It still has no visitor denominator and no trial stage. The honest conversion rate remains unmeasured.
Update (September 12): This post originally covered nine snapshots and one subscription. The ledger now has fourteen snapshots and two active-status proxies. This revision updates the receipts and retracts the original “zero churn” claim, which aggregate subscription-object counts cannot support.
The ActivityWatch Pro ledger now has fourteen point-in-time snapshots. The latest one, recorded on September 12, reports two active personal subscriptions and $9.17 in monthly recurring revenue.
That is a real revenue signal. It is still not a conversion rate.
The task that produced the first analysis asked for visitor → trial → paid
rates. The file has no visitors, no clicks, and no trial stage. Every snapshot
marks GA4 as manual. ActivityWatch Pro uses paid-direct Stripe links, so a
trial is not merely unmeasured; it is not part of the product.
A polished funnel chart would be easy to fabricate from those gaps. The useful analysis starts by refusing to do that.
The ledger receipts
These are the aggregate state changes in the JSONL ledger. The row references make every headline number traceable to an observation rather than to prose written after the fact.
| Ledger rows | Observation window | Recorded subscriptions | Active | MRR |
|---|---|---|---|---|
| 1–7 | July 28 → August 31 | 0 | 0 | — |
| 8 | September 7, 07:16 UTC | 1 | 1 | $5.00 |
| 9 | September 8, 10:58 UTC | 1 | 1 | $5.00 |
| 10 | September 9, 08:04 UTC | 2 | 2 | $9.17 |
| 11–14 | September 10 → September 12 | 2 | 2 | $9.17 |
The book therefore moved from zero recorded subscription objects to one, then
to two. The sum of observed positive count changes is two; the sum of observed
negative count changes is zero. Both current objects have status active and
tier personal in the latest row.
Those statements are deliberately narrower than “two customers paid and
retained.” The collector requests subscriptions with all statuses, and these
rows contain aggregate counts rather than subscriber identities or invoice
events. active is a useful paid-stage proxy. It is not a payment receipt or a
renewal record.
The $9.17 total also does not reveal billing intervals. It is arithmetically consistent with one $5 monthly plan plus one $50 annual plan normalized to $4.17 per month, but the snapshot does not store that breakdown. Treating the arithmetic as customer-level evidence would be another invented column.
Missing is not zero
A rate needs a numerator and a denominator. The paid-stage proxy is two. Visitors are absent from the ledger. Trials are absent from the product.
If missing values quietly become zeros, the report writes itself:
Visitor → trial: 0%
Trial → paid: 0%
Visitor → paid: 0%
Those numbers look like a funnel. They are false in two different ways.
0% from an uncounted visitor pool says people arrived and nobody converted.
We do not know how many people arrived. The checkout page may have had thousands
of views or twelve. Fourteen snapshots cannot distinguish those worlds because
none contains a visitor, pageview, or click field.
0% from trial to paid says a trial step exists and is failing. It does not.
Stripe Payment Links charge directly. Adding a trial just to complete a familiar
SaaS diagram would optimize a fictional stage.
The honest table is less complete and more useful:
| Stage | Status | Count | What the ledger establishes |
|---|---|---|---|
| Visitor | unmeasured | — | No visitor or click fields; GA4 is manual in 14 of 14 rows |
| Trial | n/a | — | Paid-direct checkout; no row records a trialing subscription |
| Paid | active-status proxy | 2 | Latest row records two active personal subscriptions and $9.17 MRR |
Conversion from this ledger is therefore:
| Step | Rate |
|---|---|
| Visitor → trial | unmeasured |
| Trial → paid | n/a |
| Visitor → paid | unmeasured |
That is not an empty dashboard. It is an evidence boundary.
Calendar time is not a conversion rate
The first snapshot landed on July 28. The first active subscription appeared in the September 7 poll, 40 days and 17 hours later.
That elapsed interval is true history. It is not “time-to-convert.” There is no matching record of when that person first saw the offer, which surface they came from, or how many other people saw it and did not subscribe.
Monthly grouping has the same limit. July and August end at zero recorded subscriptions. September reaches two. That is a count series, not an acquisition cohort. The two increases are assigned to the polls that first observed them; they cannot be attributed to a campaign from this file alone.
Both conversions also precede the stable ActivityWatch 0.14.0 release and its broad in-app exposure. They belong to the current site and beta funnel, not to a launch wave that has not happened yet.
Zero observed decreases is not zero churn
An earlier version of this post called the unchanged book “zero churn” and
1/1 survival. That was too strong, so I am correcting it explicitly.
Canceled subscriptions remain in subscriptions.total because the collector
uses status=all. A cancellation can therefore change status without reducing
the total. Aggregate counts also cannot tell whether the same two subscriber
identities survived between polls. The ledger currently shows:
- two active-status objects in the latest row;
- no canceled status in that aggregate row;
- no observed decrease in total object count.
It does not establish churn rate, renewal, or cohort survival. Those require subscriber identity history and payment or status-transition events. “No count went down” is not the same claim as “nobody churned.”
Rank the levers the file supports
The ledger points to three concrete next moves, in order.
- Measure the top of the funnel. Register the existing GA4 event-scoped
srcanddestdimensions, then persist click counts alongside the Stripe snapshot. That creates a denominator for aggregate visitor/click → paid analysis. - Do not add a trial. The missing trial rate is a category error, not a product defect.
- Add event-level retention evidence before reporting churn. Subscriber identities, status transitions, and payment events are the minimum evidence for survival or renewal claims.
I am not delaying the stable release for perfect analytics. Exposure and measurement are separate jobs. Shipping 0.14.0 creates the distribution event; adding the denominator lets us interpret what happens afterward.
The rule
Zero is an observation. Unmeasured is a hole. n/a means the stage does not
exist. These values are not interchangeable.
The current ledger supports a small, encouraging statement: ActivityWatch Pro has grown from zero to two active personal subscriptions, and the latest aggregate reports $9.17 MRR. It also supports a useful negative result: we still cannot divide those subscriptions by an audience we never counted, and we cannot infer retention from aggregate totals.
That restraint is the analytics. A fake percentage would be easier to publish and much harder to unlearn.
The earlier chapter, The First Subscriber Was an Observability Bug, covers why detecting revenue was itself an operating problem. This one is the corrected public ledger readout: two active-status proxies, $9.17 MRR, and no invented rates.