Why AI trials are different
In most software, a free user costs you some storage and a little compute. In an AI product, every action can cost real money: a model call, an image render, a search, a page of a document. The cost scales with use, not with signups, so one determined person can cost more than a hundred genuine prospects.
That’s why so many AI products sit behind a signup wall, a waitlist or a credit card. Each of those works, and each has a price: the visitors who would have been convinced by seeing real output never see it.
The usual defences, and what each costs you
| Defence | What it helps with | What it costs you |
|---|---|---|
| Signup with email verification | Casual anonymous use | Visitors who only wanted a look. Throwaway addresses still get through. |
| Card on file | Much of the farming | Most genuine prospects, before they’ve seen any value |
| Waitlist or invite codes | Abuse, almost entirely | Momentum, and the visitor’s attention |
| Free credits per account | One account overspending | Nothing stops one person making many accounts |
| Rate limits by IP address | Bursts from one address | Shared offices and phone networks get blocked. Changing address is easy. |
| Canned or recorded output | All spend | Visitors see someone else’s prompt answered last month, not your product now |
Signup with email verification
- What it helps with
- Casual anonymous use
- What it costs you
- Visitors who only wanted a look. Throwaway addresses still get through.
Card on file
- What it helps with
- Much of the farming
- What it costs you
- Most genuine prospects, before they’ve seen any value
Waitlist or invite codes
- What it helps with
- Abuse, almost entirely
- What it costs you
- Momentum, and the visitor’s attention
Free credits per account
- What it helps with
- One account overspending
- What it costs you
- Nothing stops one person making many accounts
Rate limits by IP address
- What it helps with
- Bursts from one address
- What it costs you
- Shared offices and phone networks get blocked. Changing address is easy.
Canned or recorded output
- What it helps with
- All spend
- What it costs you
- Visitors see someone else’s prompt answered last month, not your product now
None of these is wrong. Each trades reach for safety. What you want is a trial with a hard edge on cost that doesn’t need an account.
Design: a small allowance for each visitor
The pattern that works is the same one prepaid usage uses: give each visitor a small allowance and meter it, instead of trusting them or blocking them. In practice that means:
- A disposable workspace for each visitor, not a shared demo account. One visitor’s use can’t spend another’s allowance, and cleanup is simply deleting the workspace.
- One meter per cost. Count in the unit you pay for: requests, tokens, renders or pages.
- Reserve before you run. Take the estimate from the allowance first, then make the call. Parallel requests can’t overshoot a limit they all have to reserve against.
- Record what was really used, and give the reservation back if the call fails.
- Refuse clearly. When the allowance is gone, say so and say what happens next, such as signing up to continue.
- End the session on a timer and delete everything it made.
What it looks like in code
This is how it looks with Trylane’s Postgres adapter, where budgets are in beta. The recipe declares what each visitor starts with, and each costly call goes through withBudget.
import { TrylaneError } from "@trylaneapp/sdk";
import { withBudget } from "@trylaneapp/adapter-postgres";
// In the recipe: what each visitor starts with
const summarizer = {
id: "summarizer", version: 1, maxRows: 20,
budgets: { "ai.requests": 10, "ai.tokens": 30000 },
// actions, milestones, seed and cleanup as usual
};
// In your route, in demo mode, after verifying the visitor
try {
const summary = await withBudget(
sql, grant, recipes,
"ai.tokens", 1500, // estimate, reserved first
() => model.summarize(document),
(result) => result.usage.totalTokens, // what it really used
);
return Response.json({ summary });
} catch (error) {
if (error instanceof TrylaneError && error.code.startsWith("budget_exhausted")) {
return Response.json(
{ error: "You’ve used this demo’s allowance. Sign up to keep going." },
{ status: 429 },
);
}
throw error;
}A meter your recipe doesn’t declare is refused, not unlimited, so forgetting to declare one fails safe. The sample data docs cover the full contract, including usageOf, which returns what each visitor has left.
Choosing the numbers
There are no universal numbers, and anyone quoting them for your product is guessing. Work them out like this:
- Run your product’s best first session yourself and write down what it used on each meter.
- Set the allowance a little above that, so a genuine visitor can finish and try once more, but not ten times.
- Set each call’s estimate near its typical use. Actual usage is recorded afterwards.
- Watch the funnel in session insights. If many visitors hit the limit before reaching a result, raise it. If almost none ever do, you may be giving away more than you need to.
- Revisit the numbers whenever your model costs change.
What this doesn’t do
It’s worth being exact about the edges.
- Budgets are in beta.
- Only calls you wrap are counted. A costly call outside
withBudgetspends freely, so wrap every path that costs money. - It isn’t a hard dollar cap. A call that uses more than it reserved is recorded afterwards, so that overrun is real spend. It does block that visitor’s later calls.
- It limits one visitor’s workspace. It doesn’t stop someone from starting many sessions. Per-address limits, concurrency caps and your monthly session allowance bound that, and a spend limit with your model provider is the backstop for anything not counted.
Want visitors to try your product before they sign up?
Trylane is free for one product. It works with TypeScript apps on PostgreSQL, and your coding agent can do most of the setup.