Usage Tracking
Track billable events with basicUsageEventConsumer and middlewareEventConsumer
Events are the core of Scrawn every API call, AI generation, or billable action produces an event. Track them manually where you need control, or automatically with middleware.
Manual Tracking
Call basicUsageEventConsumer whenever a billable action happens:
Debit a fixed amount (smallest currency unit):
import { biller } from "./scrawn/biller";
await biller.basicUsageEventConsumer({
userId: "user-123",
debit: 500,
});Use a price tag managed on the backend:
await biller.basicUsageEventConsumer({
userId: "user-123",
debit: biller.tag("PREMIUM_CALL"),
});Or use a pricing expression - wrap with biller.expr():
import { mul } from "@scrawn/core";
await biller.basicUsageEventConsumer({
userId: "user-123",
debit: biller.expr(mul(biller.tag("PER_CALL"), 3)),
});Parameters
Prop
Type
The debit field accepts a number (smallest currency unit), a biller.tag() reference (e.g. biller.tag("PREMIUM_CALL")), or any pricing expression wrapped in biller.expr() (e.g. biller.expr(mul(biller.tag("RATE"), 3))). Raw mul(), add(), etc. must be wrapped in biller.expr() to be accepted.
Options
The second argument accepts an optional options object:
Prop
Type
Automatic Tracking (Middleware)
middlewareEventConsumer drops into any Express-compatible framework and tracks events automatically based on your extractor function.
import { biller } from "./scrawn/biller";
app.use(biller.middlewareEventConsumer({
extractor: (req) => ({
userId: req.headers["x-user-id"] as string,
debit: biller.tag("API_CALL"),
}),
}));Use whitelist to only track specific paths:
app.use(biller.middlewareEventConsumer({
extractor: (req) => ({
userId: req.headers["x-user-id"] as string,
debit: biller.tag("API_CALL"),
}),
whitelist: ["/api/**"],
}));Use blacklist to exclude specific paths:
app.use(biller.middlewareEventConsumer({
extractor: (req) => ({
userId: req.headers["x-user-id"] as string,
debit: biller.tag("API_CALL"),
}),
blacklist: ["/api/collect-payment"],
}));Configuration
Prop
Type
Best Practices
Place after authentication:
app.use(authMiddleware);
app.use(biller.middlewareEventConsumer({ /* ... */ }));Middleware runs tracking in the background - your handler is not blocked:
app.post("/api/generate", async (req, res) => {
const result = await generateContent(req.body);
res.json(result);
// Tracking already happened in parallel
});Framework Compatibility
The middleware uses standard (req, res, next) signatures. For Fastify, Next.js, or Hono, call basicUsageEventConsumer directly in route handlers or check framework recipes for adapters.