Product telemetry
Farm.js has two separately controlled product-telemetry paths:
- Anonymous command telemetry in
@farm.js/cli(farm) and@farm.js/create-appis enabled by default for interactive local commands. - Production website reporting is enabled by default in built server runtimes and automatically reduces incoming production request URLs to their public HTTPS origin.
These signals help the maintainers understand which coarse framework paths are useful, where compatibility work should be focused, and which websites are running Farm in production.
This is separate from application observability. OpenTelemetry describes what your application does and is configured by the application owner. Farm.js product telemetry never includes application spans, logs, visitor analytics, or request contents.
Control CLI telemetry
farm telemetry status
farm telemetry enable
farm telemetry disableThe first eligible event creates a random anonymous installation ID in the operating system's local
configuration directory. farm telemetry disable opts out and deletes that ID. Running
farm telemetry enable later creates a different ID. Saved opt-out preferences remain respected
across upgrades.
Environment variables can provide an explicit per-process or organization-wide policy:
| Variable | Behavior |
|---|---|
FARM_TELEMETRY=1 | Enables CLI telemetry, including non-interactive and CI commands. |
FARM_TELEMETRY=0 | Disables CLI and production-site telemetry for the process. |
FARM_TELEMETRY_DISABLED=1 | Disables CLI and production-site telemetry for the process. |
DO_NOT_TRACK=1 | Disables all telemetry and takes precedence over Farm's enable setting. |
FARM_TELEMETRY_DEBUG=1 | Prints delivery status without event contents, origins, or identifiers. |
Without the explicit FARM_TELEMETRY=1 override, Farm skips test, CI, and non-interactive
processes even when the saved local preference is enabled.
The preference file is stored at:
- macOS:
~/Library/Application Support/farmjs/telemetry.json - Linux:
$XDG_CONFIG_HOME/farmjs/telemetry.json, or~/.config/farmjs/telemetry.json - Windows:
%APPDATA%\farmjs\telemetry.json
Automatic production-site detection
No site URL configuration is required. After the first non-health request reaches a built Farm
server runtime, Farm reads the request URL and reduces it to an origin. For example,
https://shop.example.com/private/orders?token=secret becomes only
https://shop.example.com before telemetry delivery.
Farm accepts detected origins only when they use HTTPS and a public hostname. HTTP, localhost, IP,
single-label, and .local origins are ignored. Request paths, query strings, hashes, and credentials
are discarded and never included in the check-in.
To disable production-site reporting in farm.config.ts:
import { defineConfig } from "@farm.js/core";
export default defineConfig({
telemetry: false,
});Vercel preview, development, and custom-environment deployments are skipped automatically from
VERCEL_ENV and VERCEL_TARGET_ENV, as are Netlify preview, branch, and dev deployments (when
NETLIFY=true) and Render pull-request previews (when IS_PULL_REQUEST=true). Farm does not
classify deployments from the hostname suffix, so a production website whose public domain ends
in .vercel.app remains eligible. On a provider Farm does not auto-detect, set
FARM_TELEMETRY=0 or FARM_TELEMETRY_DISABLED=1 in preview environments while leaving
production enabled.
The Farm-owned endpoint removes the Vercel-confirmed legacy preview aliases that were stored before this runtime guard existed. It does not guess whether a deployment is a preview from its hostname.
After the first non-health production request, Farm schedules a check-in through the deployment runtime's background-work hook. It does not wait for the network before handling or returning the application response. A running instance checks in at most once every 24 hours, and a failed request is eligible for a later best-effort retry. Multiple instances update the same site record.
The check-in contains only the detected origin, @farm.js/core version, renderer name, and deploy
target. It does not contain a visitor or installation identifier, the full request URL beyond the
reported origin, headers, cookies, IP address, user-agent string, or application data. Fully static
exports have no server runtime and therefore do not send production-site check-ins. Vercel preview,
development, and custom-environment deployments do not send production-site check-ins.
Set telemetry: false and redeploy to stop future check-ins. An inactive site disappears from the
maintainer dashboard after the retention window.
Data that is sent
Farm currently sends three versioned event types:
| Event | Fields |
|---|---|
command_invoked | Allowlisted command from farm or create-farm-app, package/version, optional deploy target, runtime. |
project_created | Allowlisted starter, renderer, package manager, TypeScript/install booleans, runtime fields. |
production_site_active | Automatically detected HTTPS origin, core version, renderer, and deploy target. |
The farm binary records each actionable command path, including nested commands such as
auth:migrate, cron:list, cron:run, and add:integration. The app generator records create
or list-templates, and a completed scaffold also records project_created. Help, version, and the
farm telemetry privacy-control commands do not emit events.
Every CLI event also has a random event ID for deduplication and the random local installation ID.
The server immediately converts the installation ID into an HMAC hash using a server-only salt;
the raw ID is not stored. Production-site check-ins have neither identifier and are upserted by the
detected origin. A telemetry-enabled production server also answers
/.well-known/farm-telemetry with the same framework metadata so the ingestion service can attest
the claimed origin before storage. Receipt time is assigned by the server instead of trusting a
client timestamp.
Farm does not collect or store:
- project names, filesystem paths, Git remotes, repository names, source code, or route names;
- usernames, email addresses, account IDs, cookies, application payloads, or application events;
- environment variable names or values, database URLs, credentials, tokens, or other secrets;
- IP addresses or user-agent strings.
The CLI client schedules delivery in the background so telemetry does not delay command execution, and network delivery does not keep a short-lived process open. A request has a three-second timeout and transient network, rate-limit, and server failures receive two bounded retries while the process remains alive. Telemetry can never make a Farm command fail, and there is no persistent retry queue.
Endpoint, validation, and retention
CLI events are posted to https://farmjs.dev/api/telemetry/v1/events; production-site check-ins are
posted to https://farmjs.dev/api/telemetry/v1/sites. Both endpoints accept a strict, versioned JSON
schema, reject unknown fields and bodies larger than 8 KiB, and rate-limit traffic. CLI events are
deduplicated by event ID. Before a production site is upserted, the service fetches its fixed
well-known endpoint through a private-address-blocking connection, rejects redirects and oversized
responses, and stores the metadata returned by that origin instead of client-claimed metadata.
Rows created before origin attestation was introduced remain conservatively labeled as unverified
and disappear through the normal retention window unless a current deployment attests them.
Raw telemetry events and inactive production-site records are retained for 90 days by default and
are pruned by the ingestion service. The verified legacy Vercel preview records are also removed
during this maintenance pass. Aggregated package-download counts remain available independently
through npm's public download statistics. A deployment operator can change the retention window
with FARM_TELEMETRY_RETENTION_DAYS.
For local endpoint development only, FARM_TELEMETRY_ENDPOINT and
FARM_TELEMETRY_SITE_ENDPOINT can point at an HTTPS URL or an HTTP localhost address. Released
clients use the Farm-owned endpoints by default. An invalid or insecure explicit override is skipped
instead of being redirected to a Farm-owned endpoint.
Maintainer deployment setup
The Farm-owned docs deployment uses four server-only environment variables:
| Variable | Purpose |
|---|---|
DATABASE_URL | Pooled Postgres connection used by Prisma. |
FARM_TELEMETRY_IDENTITY_SALT | Long random secret used to HMAC-hash local anonymous IDs. |
FARM_TELEMETRY_DASHBOARD_TOKEN | Long random secret used to open the internal /telemetry dashboard. |
FARM_TELEMETRY_RETENTION_DAYS | Optional event and inactive-site retention window; defaults to 90. |
These values must be encrypted deployment variables and must never use a PUBLIC_ prefix or be
committed to the repository. Public telemetry clients do not contain an ingestion secret; the
endpoints use strict validation, body limits, rate limits, event deduplication, and origin
attestation instead.
After connecting Postgres, generate the Prisma client and apply the schema from the repository:
pnpm --dir docs prisma:generate
pnpm --dir docs db:push/telemetry exchanges the dashboard token through a server-side form for a 12-hour HttpOnly,
SameSite cookie. The token is not placed in the URL, local storage, or client-side JavaScript.
Understand and control Farm.js CLI and production-site telemetry.