The usage bar that sells the upgrade (build it with a public key in an afternoon)
An invisible limit feels like a trap. A visible one feels like a fuel gauge. Same quota, same plan, same user - and a measurably different reaction when the wall finally arrives.
Surprise limits punish your best users
Think about who actually hits your free-tier cap: your most engaged free users - the exact people most likely to pay. If the first time they learn the limit exists is the moment it blocks them, the product just punished enthusiasm. The same enforcement lands completely differently when the user watched the meter fill all week: the limit becomes a known boundary they chose to approach, the wall becomes an expected event, and the upgrade becomes the obvious continuation of something going well rather than a toll booth that appeared out of nowhere.
The public key exists for exactly this
Each Vevee app ships a pk_live key alongside the secret one, and the public key can do precisely one thing: read a user’s own usage. Safe to embed in client code, useless for tracking or admin operations even if extracted. That scoping means the usage bar needs no backend route, no proxy endpoint, no session plumbing - the component fetches the numbers directly. The response carries every counter for the user’s current period: quota, count, remaining, the human label you set in the plan builder, and the period window itself.
// Client-side - pk key, reads this user's usage only
import { createClient } from '@vevee/sdk';
const vevee = createClient({ apiKey: process.env.NEXT_PUBLIC_VEVEE_PK! });
export async function UsageBar({ userId }: { userId: string }) {
const { counters, period } = await vevee.usage(userId);
return counters.map(c => (
<Meter key={c.groupId} label={c.label}
value={c.count} max={c.quota}
hint={`resets ${formatDate(period?.end)}`} />
));
}Render the reset date, not just the fraction
The single highest-leverage detail in a usage UI is the reset date. "38 of 50" creates anxiety; "38 of 50, resets June 14" creates a decision: wait six days or upgrade now. The usage response includes the actual period window - computed from the plan’s period and the subscription’s anchor - so the date you render is the date the counter genuinely rolls over, even for users whose cycle is pinned to a Stripe renewal mid-month. Never hardcode "the 1st"; for most of your users that date is wrong.
The 80% color change is your softest paywall
A meter that turns amber at 80% is an upgrade prompt that no one resents, because it is information, not interruption. Pair the threshold with a quiet inline link - "Running hot this month? Pro removes the cap" - and you have built the top of an upgrade funnel inside a status display. This composes with server-side nudges: the bar makes the situation visible, the personalized nudge makes the pitch, the paywall enforces the boundary. Three touches, escalating, all driven by the same counters.
Transparency is a conversion strategy
There is a fear that showing limits prominently scares users away, and the indie-SaaS experience keeps contradicting it: users trust products that show the meter, and trusted products get the upgrade. The bar also quietly kills a whole category of support ticket - "why was I blocked?" answers itself when the user watched themselves approach the line. Total cost: one component, one public key, one read endpoint you didn’t have to build. It is the cheapest conversion surface in your entire product, and most apps still don’t have one.
Keep reading
The race condition in "if (usage < limit)" that is costing your AI app money
A user at nine of ten images opens six tabs and clicks generate in all of them. Every tab passes your limit check, every tab gets an image, and you pay for all six. The bug is one read-then-write - and your unit tests will never catch it.
MeteringHow to build a credits system for your AI app (ledger design, rollover, refunds)
A user emails: "I had 40 credits this morning and now I have 12, and I only made one image." If your balance is a column you mutated, you cannot answer that email. Here is the ledger design that can.