diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f961dc89..ec4d749d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -177,6 +177,7 @@ The website code lives under `src/`: - `src/client/` — browser-side TypeScript (search, filter, dark mode), Tailwind entry, and the vendored Outfit fonts under `fonts/` that social cards are rendered with. - `src/build/` — SSG pipeline (renders pages, compiles assets, emits JSON API, generates a social card per page). - `src/server/` — Express dev server. +- `src/tracking/` — API usage tracking; the root `middleware.ts` posts one Web Analytics custom event per JSON API request at the edge. Conventions: diff --git a/README.md b/README.md index a8e161be..6439b789 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,8 @@ curl https://modelparams.dev/api/v1/params/gpt-5.5.json Schema at `https://modelparams.dev/api/v1/schema.json`, per the [Model Parameters convention](docs/model-parameters-schema.md). +API requests are counted at the edge and reported to Vercel Web Analytics as `api_request` custom events (endpoint, model, client type), so API usage lands in the same dashboard as page views. Off Vercel it's a no-op; see [`src/tracking/api-usage.ts`](src/tracking/api-usage.ts). + ## Adding a model Drop a YAML file in `models//`, open a PR, and CI validates it against the schema. Details in [CONTRIBUTING.md](CONTRIBUTING.md). Can't open a PR? [File an issue](https://github.com/mnfst/modelparams.dev/issues/new/choose) with a link to the docs. diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 00000000..37d6cf88 --- /dev/null +++ b/middleware.ts @@ -0,0 +1,21 @@ +import { trackApiUsage } from "./src/tracking/api-usage.js"; + +/** + * Vercel Edge Middleware: counts requests to the JSON API and the llms.txt + * companion files as Web Analytics custom events. Middleware runs before the + * CDN cache, so cached responses are counted too. What gets recorded is + * documented in src/tracking/api-usage.ts. + */ +export const config = { + matcher: ["/api/:path*", "/llms.txt", "/llms-full.txt"], +}; + +interface MiddlewareContext { + waitUntil(promise: Promise): void; +} + +export default function middleware(request: Request, context: MiddlewareContext): void { + const pending = trackApiUsage(request); + if (pending) context.waitUntil(pending); + // Returning nothing lets the request fall through to the static files. +} diff --git a/src/tracking/api-usage.ts b/src/tracking/api-usage.ts new file mode 100644 index 00000000..51b10b21 --- /dev/null +++ b/src/tracking/api-usage.ts @@ -0,0 +1,165 @@ +/** + * Server-side usage tracking for the JSON API, reported to Vercel Web + * Analytics so API traffic shows up in the same dashboard as page views. + * + * The API is static files on Vercel's CDN, so the Web Analytics