Here's a problem every AI product hits: the demo only works if someone plugs in an API key. Share the repo, and the first thing a new developer sees is a wall of errors because ANTHROPIC_API_KEY isn't set. Put it in a template, and buyers can't run it until they've signed up for a provider. Deploy a preview, and it costs you tokens every time a stranger clicks around. There's a pattern that solves all of this: build the AI feature so it runs with zero keys, and make going live a one-function swap.
The trick: a mock engine that streams like the real thing
The key insight is that your UI shouldn't care where the tokens come from. If the streaming interface consumes a stream of text chunks, it doesn't matter whether those chunks are generated by a model or by a function that returns canned, context-aware replies and streams them token by token. So you build the mock to behave exactly like the real thing: keyword-match the prompt to a sensible answer, then stream it out with small delays so it feels alive.
// A keyless engine that streams like a real model.
const REPLIES: { match: RegExp; reply: string }[] = [
{ match: /metric|summary|how.*doing/i, reply: 'MRR is up 8.2% this week...' },
{ match: /invite|teammate/i, reply: 'To invite a teammate: open Settings...' },
];
const FALLBACK = 'In this demo I answer from a small set of canned replies so it runs with no API key.';
export function generateReply(prompt: string): string {
return REPLIES.find((r) => r.match.test(prompt))?.reply ?? FALLBACK;
}Then the UI streams that string one token at a time - the same loop it would use for a real model - so the mock is visually indistinguishable from a live assistant:
const tokens = generateReply(prompt).split(/(\s+)/);
let out = '';
for (const token of tokens) {
out += token;
setMessage(out); // re-render as it "streams"
await new Promise((r) => setTimeout(r, 20));
}Why this is worth doing
Making the AI keyless by default isn't a shortcut - it removes friction at every point where someone first meets your product.
- Demos never break - anyone can click the live preview and the assistant just works, at zero token cost to you
- Templates and open-source repos run on first clone, before any signup
- Onboarding is instant - new devs see the feature working before they wire anything
- Tests are deterministic - no network, no key, no flaky model responses in CI
- Design and iteration happen offline - you can build the whole UI on a plane
The one-function swap to go live
Because the entire model lives behind a single function, going from demo to production is a swap, not a rewrite. Replace the body of generateReply with a real streaming call (Claude via the Vercel AI SDK, behind a route handler so your key stays server-side) and the streaming UI never changes - it's still consuming a token stream, just a smarter one.
The principle underneath: isolate the model behind one seam. Whether the tokens come from a canned reply or a frontier model is an implementation detail the UI should never know about. Get that boundary right and the same codebase runs as a keyless demo and a production product.
Keel is built exactly this way - a keyless mock engine powers the assistant, Ask AI slide-over, and Cmd+K bar out of the box, then swaps to Claude via the Vercel AI SDK in one function. From $79, one-time.
See Keel