Farm.js

Product telemetry

Farm.js has two separately controlled product-telemetry paths:

  • Anonymous command telemetry in @farm.js/cli (farm) and @farm.js/create-app is 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 disable

The 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:

VariableBehavior
FARM_TELEMETRY=1Enables CLI telemetry, including non-interactive and CI commands.
FARM_TELEMETRY=0Disables CLI and production-site telemetry for the process.
FARM_TELEMETRY_DISABLED=1Disables CLI and production-site telemetry for the process.
DO_NOT_TRACK=1Disables all telemetry and takes precedence over Farm's enable setting.
FARM_TELEMETRY_DEBUG=1Prints 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:

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:

EventFields
command_invokedAllowlisted command from farm or create-farm-app, package/version, optional deploy target, runtime.
project_createdAllowlisted starter, renderer, package manager, TypeScript/install booleans, runtime fields.
production_site_activeAutomatically 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:

VariablePurpose
DATABASE_URLPooled Postgres connection used by Prisma.
FARM_TELEMETRY_IDENTITY_SALTLong random secret used to HMAC-hash local anonymous IDs.
FARM_TELEMETRY_DASHBOARD_TOKENLong random secret used to open the internal /telemetry dashboard.
FARM_TELEMETRY_RETENTION_DAYSOptional 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.