Day 39: fixing the MRR calculation and shipping the analytics dashboard page
Two things were wrong with the admin revenue API and neither showed up as an error. They were just silently wrong. Fixed both today, then shipped the analytics dashboard feature page.
The MRR bug hiding in the revenue API
Two problems in /api/admin/revenue:
First problem: Stripe price IDs were hardcoded as string literals at the top of the file. Not env vars — actual strings in the code. That meant at live-mode cutover (~July 23), swapping to live-mode price IDs would have required a code change, a commit, and a deploy. The whole point of env vars is that configuration changes don't touch code. Four price IDs, all now reading from the same env vars already in Vercel: STRIPE_CHAD_PRICE_ID, STRIPE_GIGACHAD_PRICE_ID, STRIPE_CHAD_ANNUAL_PRICE_ID, STRIPE_GIGACHAD_ANNUAL_PRICE_ID.
Second problem: annual subscriptions were being counted at their full annual amount toward MRR. A Chad annual subscription ($288/yr) was contributing $288 to the MRR figure instead of $24. GigaChad annual ($948/yr) was contributing $948 instead of $79. With only test data this doesn't matter much — but post-launch, one annual subscriber would make the Revenue tab look like the business had 12 paying customers instead of one.
The fix: amounts now read directly from Stripe's price object (unit_amount / 100 to convert from cents), and annual amounts are divided by 12. Two benefits to reading from Stripe's price object rather than hardcoding $30 and $99: it's always accurate, and if pricing ever changes, the MRR calculation self-corrects without a code change.
Also worth noting: the API now correctly routes annual subs into the right tier counter. A Chad annual sub increments chadCount, not unknownCount. Previously any unrecognized price ID fell through to unknownCount — which would have made the tier breakdown useless the moment an annual sub came in.
Customer portal and annual billing
Tested the annual subscription flow end to end in Stripe test mode today: checkout with billingInterval: 'annual', webhook fires, tier assignment correct, customer portal shows the annual subscription correctly with next billing date and cancellation behavior.
At live-mode cutover the process is: swap 4 env vars in Vercel dashboard, done. Zero code changes. The checkout API, webhook handler, and revenue API all read from env vars now. The pricing page toggle already works in test mode — annual checkout goes to the right Stripe price, webhook assigns the right tier, revenue API counts it correctly as monthly-equivalent MRR.
Analytics dashboard feature page
The third Product dropdown item now has a real destination: /features/analytics-dashboard.
This is the longest feature page yet — ten sections covering rating trend, response rate, review velocity, star distribution, competitor tracking, and the tier comparison. Every section has an HTML/CSS mock of what the actual UI looks like: the dashboard, a trend chart, response rate cards, a velocity bar chart, a star distribution breakdown, a competitor comparison table. All static, no JavaScript, matches the real product design exactly.
The tier comparison section is the one I'd point a new visitor to first. It answers the question directly: Noob gets a total review count and current average rating. Chad adds the full analytics dashboard — trend, response rate, velocity, star distribution. GigaChad adds competitor tracking. That hierarchy makes the pricing page make sense. The features earn the price difference.
The competitor tracking section gets its own callout because it's the feature with the clearest ROI story. Every review your nearby competitors receive is public. Their rating, their trend, whether they're responding — all visible to anyone who checks. Ominvo pulls that into a table so you're not manually checking five Google Maps listings. It's a GigaChad feature because it requires more data processing per account, but for any business where local rank is a real concern, it's the one that justifies the upgrade.
The ROI calculator is worth running if you want to see what improving your rating and response rate is actually worth in new customers per month.
Day 39 of building in public. Full changelog at /changelog. Analytics dashboard page live at /features/analytics-dashboard.
Written by
The founder of Ominvo
Building review management for single-location small businesses. Join the waitlist →