Vercel AI SDK
First-class Vercel AI SDK integration - auto-bill every LLM call
Vercel AI SDK
Scrawn wraps the Vercel AI SDK so every streamText, generateText, streamObject, and generateObject call auto-bills on every step finish. No manual token counting, no per-route instrumentation.
Setup
Add the AI wrapper to your biller.ts:
// scrawn/biller.ts
import { scrawn } from "@scrawn/core";
import { TAGS, EXPRESSIONS } from "./pricerefs";
import * as aisdk from "ai";
export const biller = scrawn({
apiKey: process.env.SCRAWN_KEY,
baseURL: process.env.SCRAWN_BASE_URL,
httpUrl: process.env.SCRAWN_HTTP_URL,
tags: TAGS,
expressions: EXPRESSIONS,
});
export const ai = biller.ai(aisdk, {
inputDebit: biller.tag("GPT_INPUT"),
outputDebit: biller.expr("COMPLEX_FEE"),
});Then import ai from your biller in any file:
import { ai } from "./scrawn/biller";
const result = await ai.streamText({
userId: "user-123",
model: openai("gpt-4o-mini"),
prompt: "Hello",
});The config object accepts:
Prop
Type
The returned ai object works exactly like the original Vercel AI SDK - call streamText, generateText, etc. exactly as you normally would, just with a userId parameter added.
Usage
Every wrapped function works exactly like the original Vercel AI SDK - just add a userId to associate billing:
import { ai } from "./scrawn/biller";
const result = await ai.streamText({
userId: "user-123",
model: openai("gpt-4o-mini"),
prompt: "Hello",
});The same pattern applies to generateText, streamObject, and generateObject - all original options and types are preserved.
Multiple models
Use tags to charge different rates per model. Define separate wrappers in your biller.ts:
// scrawn/biller.ts
export const gpt = biller.ai(aisdk, {
inputDebit: biller.tag("GPT_INPUT"),
outputDebit: biller.tag("GPT_OUTPUT"),
});
export const claude = biller.ai(aisdk, {
inputDebit: biller.tag("CLAUDE_INPUT"),
outputDebit: biller.tag("CLAUDE_OUTPUT"),
});Then import the right one per call:
import { gpt, claude } from "./scrawn/biller";
const result = await gpt.streamText({
userId: "user-123",
model: openai("gpt-4o-mini"),
prompt: "Hello",
});Manual tracking (trackAI)
For full manual control without the biller.ai() wrapper, use trackAI() inside onFinish or onStepFinish:
import { biller } from "./scrawn/biller";
ai.streamText({
model: openai("gpt-4o"),
prompt: "Hello",
onFinish: async (event) => {
biller.trackAI({
userId: "user-123",
event,
inputDebit: biller.tag("GPT_INPUT"),
outputDebit: biller.tag("GPT_OUTPUT"),
});
},
});Prop
Type
Compatibility
The wrapper supports ai SDK versions 3.x and 4.x. If you encounter type issues, ensure ai and @scrawn/core are both on recent versions.