BlogMetering

Add usage limits to your AI app in 10 minutes (no backend required)

You shipped an AI feature on Friday. By Monday one user had burned $212 of OpenAI credit on your free tier. The fix is not a TODO comment that says "add rate limiting" - it is two method calls.

The $212 user

Every AI product gets one. You launch a free tier with "10 generations a day" written in the pricing table and nowhere in the code, because enforcing it meant building a counters table, a period-rollover job, and an admin view - and you wanted to ship. Then one user writes a loop. The bill arrives before the limit does. The reason this keeps happening across thousands of indie AI apps is that usage limits feel like a feature you can defer, when they are actually the part of the product that touches money on both sides: your provider bill and your customer’s plan.

What "10 minutes" actually includes

This is the whole integration: create an app in the Vevee dashboard, define a plan with one limit group ("generations", 10 per day), copy the secret key, and wrap your AI call in a check and a track. There is no schema to design, no migration to run, no cron to schedule. The counters, periods, and rollover live on the other side of the API. Your code asks one question - can this user do this right now? - and reports one fact afterward - they did it.

import { createClient } from '@vevee/sdk';

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

export async function generateImage(userId: string, prompt: string) {
  if (!(await vevee.can(userId, 'image_generation'))) {
    throw new Error('limit_reached'); // show your upgrade screen
  }

  const image = await openai.images.generate({ prompt });

  await vevee.track(userId, 'image_generation');
  return image;
}

You name the events, not us

The event string is yours. image_generation, llm_tokens, video_seconds, pdf_export - Vevee does not ship a fixed vocabulary, because your product’s unit of value is not ours to guess. The plan you built in the dashboard has match rules that map event patterns to limit groups, so when you later add a second model you can track image.flux and image.sdxl separately and still have both count toward one "images" quota. Start with one event name today; the naming scheme can grow without a migration.

The user id is whatever you already have

You pass end-user ids as opaque strings - an email, a UUID, your internal user id. Vevee never authenticates your users and never needs to; it just keys counters on the string you provide. That means there is no OAuth dance, no user-sync job, no webhook to keep two user tables consistent. The id you have in scope at the call site is the id you use.

What you get for the two calls

The can/track pair buys more than a gate. Every tracked event lands in a per-user usage timeline you can chart in the dashboard, every counter knows its period and resets itself when the plan says so, and changing the free tier from 10 to 25 generations is an edit in the plan builder - not a deploy. When you add a paid plan next month, upsertSubscription moves a user onto it and the same two lines of integration code start enforcing the new numbers.

When you outgrow can + track

There is one honest caveat: can followed by track has a race. Two parallel requests can both pass the check before either records usage, so a determined user can overshoot a tight limit. For most free tiers that is fine - the overshoot is one or two events. When it stops being fine (expensive video models, strict credit packs), switch to reserve/commit/release, which holds quota atomically before the AI call runs. The upgrade is local: same SDK, same event names, three calls instead of two, only on the paths that need it.

const r = await vevee.reserve(userId, 'video_seconds', 30);
if (!r.allowed) throw new Error('limit_reached');
try {
  const video = await renderVideo(prompt);
  await vevee.commit(r.reservationId!);
  return video;
} catch (e) {
  await vevee.release(r.reservationId!);
  throw e;
}
See your own numbers in two minutes.Add the SDK and your users, costs and revenue fill in on the next request.
Join waitlist

Keep reading

ShareCopy a link to this post.

Set your first limit in about five minutes.

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