Farm Infra analytics
Farm reports request and MCP tool activity to your Farm Infra project
when the server's environment links the app to one. There's no package to install and nothing to
add to farm.config.ts.
FARMJS_API_KEY=farmjs_…
FARMJS_PROJECT_ID=proj_…Copy the project ID from the project's page in Farm Infra. Set the variables wherever the server
runs: .env for farm dev, and your host's environment variables for production. Farm reads them
when the server starts, so the build doesn't need them.
An app without these variables sends nothing. FARMJS_API_KEY on its own isn't enough, because the
same key also authorizes other Farm Infra APIs.
Write-only keys
An account API key belongs to a person. It stops sending if they revoke it or leave the organization, and on a server it can also start previews and run site checks as them. For a key that can only write analytics, create a write-only key for the project and environment in Farm Infra and set that instead:
FARMJS_API_KEY=fti_…A write-only key names its own project and environment, so FARMJS_PROJECT_ID isn't needed.
Environment variables
| Variable | Purpose |
|---|---|
FARMJS_API_KEY | An account API key (farmjs_…) or a project's write-only key (fti_…). |
FARMJS_PROJECT_ID | The Farm Infra project to report to. Needed with an account API key. |
FARMJS_ENVIRONMENT | production, staging or development. Defaults to Vercel's environment (preview is staging), then NODE_ENV. |
FARMJS_API_URL | Farm Infra's address, if it isn't https://infra.farmjs.dev. Must be HTTPS, except for localhost. |
A value Farm can't use, such as a malformed key or project ID, leaves analytics off and prints one warning when the server starts. It never stops the app. If Farm Infra later rejects the key, Farm stops sending until the server restarts and prints one warning.
Turn it off
import { defineConfig } from "@farm.js/core";
export default defineConfig({
analytics: false,
});With analytics: false, the production server doesn't include the analytics code at all.
Removing the environment variables also turns it off.
What is sent
- For each request: a random ID, the matched route template (such as
/users/[id]), the method, the response status and the time until Farm returned the response. - For each registered MCP tool call: the tool name, whether it succeeded, and its duration, linked to its request.
- A self-reported agent category when the user-agent declares one of OpenAI's or Anthropic's
crawlers or agents (GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-SearchBot,
Claude-User). This is the user-agent's claim, not a verified identity. Anything else is
unknown.
Farm never sends URLs, query strings, route parameters, headers, cookies, IP addresses, full
user-agents, request or response bodies, tool arguments or results, or error messages. Requests that
match no route are reported as /[unmatched].
Delivery
Analytics never delays or changes a response. Events are queued in memory and sent in the
background through the runtime's waitUntil, in batches of up to 50, with a two-second timeout per
request and bounded retries. At most 500 events are held, and an event is dropped after five
minutes or five failed attempts. When the server shuts down, Farm tries once more to send what's
queued. It's best-effort: a crash or a platform's runtime limit can drop events.
What it can't see
Only requests that reach Farm's server runtime are counted. Pages served as static files, by a CDN cache or blocked by a firewall before reaching the app, aren't. Turning analytics on doesn't make a static page dynamic. Unhandled exceptions with no final response aren't given an invented status.
It runs on Node-compatible server runtimes. Edge runtimes are not supported yet.
This is separate from Farm's own product telemetry, which is controlled by the
telemetry option, and from OpenTelemetry.
Send request and MCP tool analytics to your Farm Infra project by setting two environment variables.