For years we treated analytics as a place we visited. Open Firebase on Monday. Open RevenueCat when a refund ticket appeared. Argue about a paywall on Friday. Ship something the following week, maybe.
That is not a production cycle. It is a museum of dashboards.
This year we put xAI Grok on the same side of the glass as the data. Grok talks to Firebase Analytics (GA4) and RevenueCat through MCP servers in one session, writes a ranked ship list, and hands the work to agents that edit the React Native app. Humans still review conversion-sensitive diffs. Everything else — diagnosis, scaffolding, tests, store metadata — runs inside that loop.
The headline on PushUP Challenges is simple. Daily active users sat around 30. They now live in a 200–270 band. Firebase is the DAU we quote internally. RevenueCat’s daily active-customer series, pulled through the same MCP, tells the same story with dates attached.

Dashboards were not a production loop
PushUP is a small habit app — push-ups, squats, challenges, camera counting, Screen Time Rewards — with a real store presence on iOS and Android. Subscriptions are a monthly and a yearly package on one RevenueCat offering. None of that is exotic.
What was exotic, in the bad sense, was the gap between “we can see the number” and “we changed the binary.”
A typical week used to look like this:
- Firebase: DAU is flat,
first_openis fine, workout completion is not. - RevenueCat: new customers keep arriving, paying conversion is a different conversation.
- Slack: a screenshot, a theory, no owner.
- The app: unchanged until someone carved out a “data day.”
We already had the two systems every serious mobile shop runs. Firebase Analytics for product events. RevenueCat for customers, trials, offerings, and money. They just did not talk to the people writing the code in the same hour.
MCP is the boring piece that fixed that. Grok can call tools. We pointed those tools at the same Analytics and RevenueCat projects we already pay for.
What Grok actually reads
Two MCP servers sit in the Grok session we use for PushUP.
Firebase Analytics, via the Google Analytics Data API. Firebase events land in GA4. From Grok we run reports and funnels: DAU, first_open → onboarding → first completed set → challenge join → paywall view. We do not paste CSV into chat. We ask, the tool returns rows, Grok keeps going.
RevenueCat. Overview metrics for the last 28 days, daily active customers, new customers, offerings, packages, and category benchmarks. Same session, same customer identity space as the stores.
A stripped config looks like this — keys stay in the MCP client, never in the repo:
{"mcpServers": {"analytics": {"command": "npx","args": ["-y", "@google/analytics-mcp"]},"revenuecat": {"url": "https://mcp.revenuecat.com/mcp","headers": {"Authorization": "Bearer $REVENUECAT_API_KEY"}}}}
The prompt we start most mornings with is not clever. It is specific:
Pull PushUP Firebase DAU and the workout / challenge funnel for the last 28 days.Pull RevenueCat overview metrics and daily active customers for the same window.Join them. Tell me whether the problem is acquisition, first session, return habit, or paywall.Give me at most three shippable changes, ranked by expected DAU, with the event names we should watch after release.
Grok does not “have a feeling about engagement.” It reads both sources, notices when they disagree, and has to explain the disagreement before it is allowed to recommend a diff.
The diagnosis that changed the ship list
The joined picture in July was uncomfortable, and useful.
Acquisition was not the fire. RevenueCat recorded more than 4,000 new customers in 28 days across App Store and Play. People were finding PushUP.
The fire was what happened after day zero. Firebase DAU sat near 30. RevenueCat’s daily active-customer series opened on 19 July at 24. For the next ten days it bounced in the 60–130 range — a live product with no daily reason to open it.
That is a habit-loop problem, not a user-acquisition problem. Shipping another paywall experiment would have been the wrong next move. The ranked list Grok came back with was, in order:
- Shorten time-to-first-rep. Camera counting so a session is a set, not a form.
- Pay the user for coming back tomorrow. Screen Time Rewards — reps become minutes of selected apps.
- Give the day a social object. Challenges, not just a private counter.
- Stop the paywall from eating the first workout. Let someone complete a set before they see a wall.
That ordering is the whole point of joining Firebase to RevenueCat in one model. If you only look at RevenueCat, you reach for conversion. If you only look at Firebase, you reach for “more notifications.” Together, the recommendation was: earn the second day before you sell the month.
The loop we run now
1. Observe. Grok pulls GA4 reports and RevenueCat charts. No tab-hopping. The session holds both payloads.
2. Diagnose. One ranked list, with the event or metric that will prove each item. If Grok cannot name the event, the item does not ship.
3. Ship. Specialized agents take the list into the React Native repo. One agent implements. A second reviews. A third updates store copy when the change is user-facing. We still type the last “yes” on paywall and pricing.
4. Measure. The next morning the same MCP calls run again. Keep, iterate, or revert. The chart below is that loop, not a campaign spike.
We described the camera and rewards work when it landed — Screen Time Rewards and camera rep counting. What that post did not say is that those features were not a brainstorm. They were the first two items on a Grok ship list that started with a 24-user Tuesday.
What the agents actually changed
Agents are not a vibe. They are scoped workers with the repo, the simulator, and a done condition.
For PushUP the useful ones were:
- A mobile agent for React Native screens, VisionCamera pose counting, and the rewards award path.
- A review agent that is not allowed to be the one that wrote the diff.
- A store agent for App Store / Play text when the habit loop changed.
The code that fell out is ordinary. That is the compliment. Camera counting is an elbow-angle state machine, not a manifesto:
if (phaseRef.current === "down" && elbowAngle >= UP_ELBOW_ANGLE) {countRef.current += 1;setCount(countRef.current);}
Rewards only fire when the session was real and the entitlement is real:
if (Platform.OS === "ios" && isPremium && screenTimeEnabled) {awardMinutes(Math.round(value * minutesPerRep));}
Grok’s job was not to invent that logic. It was to insist this logic was the next production change, because Firebase said first-rep was the drop-off and RevenueCat said new customers were already walking in the door.
We still refuse a few automations on purpose:
- No agent may change prices, package lookup keys, or offering mapping.
- No agent may merge to
productionwithout a human. - No agent may “fix” a funnel by deleting an event.
Those rules are why we can run this loop on a live store app instead of a demo.
The numbers
Firebase DAU is the number we used internally: about 30, then a stable 200–270.
RevenueCat daily active customers — customers seen that day, purchased or not — is the series we can date. Pulled live from the same MCP this article is about:
| Window | What we saw |
|---|---|
| 19 Jul | 24 RevenueCat active customers. Firebase DAU ~30. |
| 19–28 Jul | Noisy 60–130. Product is alive; the daily habit is not. |
| 29 Jul onward | Step change: 196, then a 200–270 band (avg ~229). Spike of 311 on 31 Jul. |
| Last 28 days | 4,400+ new RevenueCat customers. Acquisition was never the bottleneck. |
A 7–9× DAU move on a fitness habit app is not “we ran ads.” Ads would have shown up as new customers without a second-day return. We already had the new customers. The loop spent them on a reason to open the app tomorrow.
Monetization is the next loop, not this one. Monthly and yearly packages exist. Conversion is still a health-and-fitness-benchmark problem. We will not pretend DAU and ARPU moved together. They did not. That is why the next Grok prompt is about trial start and first-paywall after a completed set — not about another onboarding animation.
Why Grok, specifically
We have used other coding agents. The reason this loop lives in Grok is mechanical:
- MCP in the same turn as the code. Analytics rows and a React Native file are one conversation, not an export plus a paste.
- Long enough context to hold a funnel table, a 30-day series, and the current screen without losing the event names.
- Agents as a second pair of hands, not as a replacement for the session that understood the data.
xAI is in the production development cycle the same way EAS and RevenueCat are: as infrastructure. We do not prompt Grok to “make the app grow.” We prompt it to read the two systems of record and refuse to ship the third idea on the list until the first two have a metric.
What we would repeat on the next app
The Play Stream, language apps, and health tools in the same RevenueCat org can run this tomorrow. The recipe is short:
- Instrument a small event list. If you cannot name
first_open, first successful action, and paywall view, stop. - Put GA4 and RevenueCat on MCP. One Grok project, one pair of servers.
- Start the day with the join prompt. End the day with at most three diffs.
- Measure on the same tools you diagnosed with. If the metric did not move, revert.
That is the success story. Not a model that “understands fitness.” A studio that stopped treating Firebase and RevenueCat as reports, and started treating them as the first function call in a shipping loop.
PushUP is still a small app. 200–270 daily users is a band we can hold, not a ceiling we are bragging about. It is also not 30. The difference is the loop.