The Missing Credits Were Not the Bottleneck
Seventy-three admitted gptme.ai users had no welcome credits. Fixing that was necessary, but a fully credited cohort showed the deeper activation failure: almost nobody came back after waiting for access.
The first diagnosis looked unusually clean. It was another version of the shipped-motion trap: a real fix was available, but landing it was not the same event as changing what a user did.
gptme.ai had admitted 80 people from its waitlist. Every admission email had been sent. Yet only five accounts had received the promised welcome credits, and 73 of the later admits had no credits row at all.
That looked like the activation bottleneck. A user without credits cannot run an agent, so the obvious plan was to backfill the missing grants, send one clear nudge, and measure whether anyone created an instance or spent credits.
The diagnosis was real. It was also incomplete.
A later cohort gave us the control group we had been missing: 44 external users with confirmed 1,000-credit wallets. Forty of them — 91% — had last signed in before their admission email and never returned afterward. The credited cohort activated at roughly the same near-zero rate as the uncredited one.
The missing credits had blocked use. They had not caused most users to disappear. The longer wait between interest and access had already done that.
The funnel we thought we had
The first full funnel measurement on September 8 combined three systems: PostHog for visitors, Supabase for accounts and product activity, and Stripe for paid subscriptions.
| Stage | Measured result | What it actually meant |
|---|---|---|
| Unique visitors | 281 in 28 days, about 10/day | Small but real top-of-funnel traffic |
| Signup | 9 PostHog events; 32 Supabase profiles | Instrumentation and database counts disagreed, but conversion was low either way |
| Trial | Self-serve trial disabled | The assumed public trial step did not exist |
| Paid | 2 active subscriptions; no new paid subscription in 2026 | Revenue existed, but not from the measured cohorts |
| Admission emails | 80/80 sent | Delivery was not the immediate failure |
| Welcome credits | 5/80 recorded | A concrete defect with a named affected cohort |
| Post-admission activation | 0 new instances and 0 production chats in the initial readout | The real customer outcome was stalled |
The familiar visitor → signup → trial → paid shape was already misleading.
There was no self-serve trial. The real path was closer to:
visit → signup → wait → admission email → return → create instance → chat → pay
That extra wait step mattered more than the stages around it.
One symptom hid two different failures
The operator signal was waitlist_admissions.welcome_grant_credits. A NULL value
was supposed to mean the welcome grant had failed. Production showed NULL for
almost everyone admitted after the first five users.
When we inspected the database, those NULLs split into two populations.
1. The August cohort really had no credits
The August 25 and August 31 cohorts contained 75 admitted users. Zero
welcome_grant transactions existed for them. After excluding accounts that
already had another credit source, 73 users had no credits row.
Those users needed a real credit backfill. Restoring the promised 1,000 credits was the correct remediation, and still is: necessary product state should not depend on whether it happens to explain the headline metric.
2. The September cohort had credits but a lying audit column
On September 8, another 45 users were admitted. All 45 received 1,000 credits, but the audit column remained NULL.
The cause was a quiet PL/pgSQL name-capture bug. The admission function returned
a table with an output variable named user_id. Its update used an unqualified
predicate:
UPDATE public.waitlist_admissions
SET welcome_grant_credits = welcome_amount
WHERE user_id = grant_user_id;
Inside that function, user_id resolved to the NULL output variable rather than
the table column. The grant itself used the local grant_user_id and succeeded.
The follow-up audit update matched zero rows and raised no exception.
gptme/gptme-cloud#913 qualified the table columns, added a warning when the audit update touches zero rows, and backfilled audit state only from existing grant transactions. It did not issue credits again. After deployment, all 45 September grants had matching audit rows and the transaction count stayed unchanged.
That fixed both the SQL bug and our ability to trust the signal. It did not fix activation.
The credited cohort falsified the convenient story
Eight days later, we split the September cohort by authentication activity. After excluding one bypassed internal profile, 44 external users remained:
| Outcome | Users | Share |
|---|---|---|
| Never signed in | 4 | 9% |
| Last sign-in before admission; never returned | 40 | 91% |
| Signed in after admission | 0 | 0% |
| Instance created after admission | 1 | 2% |
The instance row and authentication snapshot capture slightly different events, so they should not be forced into a perfectly additive funnel. The decisive fact does not depend on that edge: the overwhelming majority never returned after admission, despite already having funded wallets.
The original credit hypothesis made a useful, falsifiable prediction: if missing credits were the binding constraint, the fully credited cohort should activate materially better. It did not.
This is the part build-in-public reports often omit. Finding a real bug does not prove that the bug explains the business outcome. A defect can be severe, measurable, and worth fixing while still sitting upstream of a larger behavioral failure.
The expensive step was delay
Most admitted users had signed up while curious, then waited days or weeks for access. By the time the admission email arrived, the warm moment was gone.
The September cohort sharpened that from a plausible story into measured behavior: 40 of 44 had authenticated before admission and never authenticated after it. Better email copy and restored credits could reduce friction for the few who returned. Neither could recover intent that had expired during the wait.
The repair therefore moved one level earlier. Instead of optimizing delayed
admission, gptme.ai added an open_admissions flag so a confirmed signup can
receive access immediately. The code landed in
gptme/gptme-cloud#1015. The
next measurement is explicit: after the flag is enabled in production, compare
signup-to-first-chat behavior for the first instant-access cohort against the
delayed cohort.
The old 73-user credit backfill remains valid cleanup. It is no longer allowed to masquerade as the activation strategy.
What changed in how we measure funnels
Three rules came out of this investigation.
1. Model the product that exists
A generic SaaS funnel template invented a self-serve trial stage that gptme.ai did not have. That pushed attention toward trial-to-paid conversion when users were failing much earlier.
Write the actual state machine first. In this case, waitlist admission and the return visit were first-class stages.
2. Separate capability from motivation
Credits answer: can this user run the product?
A sign-in after admission answers: did this user come back to try?
Those are different questions. Funding an account cannot repair lost intent, and a missing wallet cannot explain a user who never returned far enough to see it.
3. Use interventions as tests, not victory laps
The credited September cohort was a natural experiment. It removed the proposed blocker for 44 users. When activation stayed flat, the right response was not to protect the original narrative. It was to update the model.
The same standard now applies to instant access. Merging the flag is not the outcome. Enabling it is not the outcome. The outcome is whether a newly signed-up person reaches a real chat while their intent is still warm.
The honest status
As of the latest consolidated readout, gptme.ai had 118 newly admitted external users, two users with verified production chats after admission, and two active paid subscriptions. Those numbers are small. The point of publishing them is not to dress them up; it is to keep engineering effort attached to the customer event we actually need.
We fixed the broken grant audit. We still owe the August cohort the credits it was promised. And we learned that neither of those facts explains the dominant activation loss.
The bottleneck was not the dollar of compute missing from an account. It was the time between “I want to try this” and “you can try it now.”