Use case

Freemium AI SaaS: ship a free → paid funnel without a backend

Build a freemium AI product where the free plan has hard quotas, the paid plan unlocks more, and "you have used 80% of your free renders" nudges drive upgrades. Drop-in implementation, ten minutes from zero to live.

Last updated: 2026-05-10

The problem

Freemium for AI is harder than freemium for regular SaaS, because every action your free users take costs you real money - tokens, GPU time, API fees. A free tier with no enforcement bleeds margin.

You also need the conversion mechanics: track usage in real time, show users how close they are to the limit, fire upgrade nudges at 80%, hard-block at 100%, expose a billing portal at the right moment.

Building all of that in-house - counter tables, period resets, dashboards, webhooks, an end-user portal - is weeks of work that competes with the actual product.

The solution

Define two plans: free (hard caps) and pro (high or no caps). When a user signs up, call vevee.upsertSubscription(userId, "plan_free"). When they pay, switch to plan_pro.

Gate every AI call with vevee.reserve/commit/release. Free users get a clean limit_reached when they hit their cap; your UI catches the error code and shows an upgrade prompt.

Wire webhooks to fire at 80% threshold for upgrade nudges. Use the pk_live_ public key to render "X renders left this month" client-side without a server roundtrip.

Example

Free users hit a clean 429 at quota. The error code drives the upgrade prompt. Paid users keep going.

import { createClient, VeveeError } from "@vevee/sdk";

const vevee = createClient({ apiKey: process.env.VEVEE_KEY! });

export async function generate(userId: string, prompt: string) {
  try {
    await vevee.track(userId, "image.render", 1);
    return await callFlux(prompt);
  } catch (err) {
    if (err instanceof VeveeError && err.code === "limit_reached") {
      // Free user hit their cap - show upgrade prompt in the UI
      throw new UpgradeRequiredError("You have reached your free plan limit");
    }
    throw err;
  }
}

// On Stripe checkout success:
export async function onCheckoutComplete(userId: string) {
  await vevee.upsertSubscription({
    userId,
    planId: "plan_pro",
  });
}

Plan migration without losing counters

When a user upgrades from free to pro mid-month, you don't want to reset their counter (they keep their history) or pretend they used nothing (they ate their free quota). Vevee's default onPlanChange: "carry" keeps counters ticking; the new plan's higher limits just give them more headroom.

Closing the free → paid → cancel → free exploit

Without protection, a savvy user can churn between free and paid to keep getting fresh quota. Set onPlanChange: "block" on a few key limit groups: when they downgrade back to free, those counters pre-fill to quota and stay there until the next period rollover.

Upgrade nudges at 80%

Best-in-class freemium products nudge at ~80% of quota - "20% left this month, want to upgrade?" - not at 100% (too late). Vevee fires threshold webhooks; wire them to your email or in-app message system.

Real-time client-side usage display

A pk_live_ public key reads only the calling user's own counters and is safe in browser code. Render the "12 / 20 renders this month" display without a server roundtrip. Updates within seconds of a track call.

Frequently asked questions

Do I need Stripe to use freemium with Vevee?

No. You can run a free tier indefinitely with hard caps and never touch payments. Add Stripe (or Lemon Squeezy / Paddle) when you want to charge for the upgrade.

Can users get a temporary boost (e.g. "free trial of pro for 7 days")?

Yes. Use customLimits in vevee.upsertSubscription to override quotas for that user, with endsAt set to 7 days out. After expiry, they revert to their actual plan.

How do I show "0 renders left, upgrade now" in the UI?

Catch limit_reached errors in your AI handler and render the upgrade modal. Or proactively render "X renders left" using vevee.usage(userId) on the client.

Can I A/B test different free quotas?

Yes. Use customLimits per-user when assigning the free plan, or define plan_free_v1 / plan_free_v2 and route users to different plans based on your experiment cohort.

Other use cases

Set your first limit in about five minutes.

50k operations free every month. No card required.
Join waitlist