Cloud beacon setup
Send production execution counts from a browser or Node service to Fallow Cloud, so you can see which functions run and which never do. Covers setup, the first-ingest check, and an empty dashboard.
The beacon records how often each function runs in production and sends those counts to Fallow Cloud. You use the counts to find hot paths and code that never runs.
In HTTP mode, the beacon sends nothing until you give it three values: an API key, a project id, and the Fallow Cloud endpoint. If the API key or the endpoint is missing or empty, the beacon does not start. It reports a transport-misconfigured error through onRuntimeMismatch, or through console.error when you do not set that callback.
Browser setup
Install the beacon and a build instrumenter that is compatible with Istanbul:
npm install @fallow-cli/beacon
npm install --save-dev oxc-coverage-instrument
Add oxc-coverage-instrument to the production build so that it fills window.__coverage__. Then start the browser beacon from the application entrypoint:
import { createBrowserBeacon } from "@fallow-cli/beacon/browser";
const beacon = createBrowserBeacon({
apiKey: import.meta.env.VITE_BEACON_API_KEY,
endpoint: "https://api.fallow.cloud",
projectId: "your-org/your-repo",
commitSha: import.meta.env.VITE_GIT_SHA,
coverageOrigin: "production",
});
beacon.start();
In browser code, use an ingest-only key with the prefix fallow_pub_k1_. This key can only call POST /v1/ingest. Never put a full fallow_live_k1_ key in a browser bundle. If the browser beacon gets a fallow_live_k1_ key, it logs an error to the console.
To report only part of the page sessions, set sampleRate to a value from 0 to 1. The default is 1, so every session reports.
The beacon reads window.__coverage__ every 30 seconds by default (flushIntervalMs), and again when the page is hidden or unloaded. If window.__coverage__ does not exist, the browser beacon sends nothing and does not report an error.
The beacon skips the first snapshot when every instrumented function in it has already run, because that snapshot shows only startup code. It checks again at the next read. To send data, do these steps:
- Go through at least one real workflow in the app, so that the snapshot also contains functions that did not run.
- Wait for the next 30-second read, or hide the page.
If every instrumented function in your app runs at startup, the browser beacon never sends data.
Node setup
Node can read V8 coverage only when NODE_V8_COVERAGE is set before the process starts. The beacon cannot turn on V8 coverage after the process has started.
NODE_V8_COVERAGE=./coverage node dist/index.js
Start the beacon from server code after boot:
import { createNodeBeacon } from "@fallow-cli/beacon";
const beacon = createNodeBeacon({
apiKey: process.env.BEACON_API_KEY,
endpoint: "https://api.fallow.cloud",
projectId: "your-org/your-repo",
commitSha: process.env.GIT_SHA,
coverageOrigin: "production",
});
beacon.start();
process.on("SIGTERM", async () => {
await beacon.flush();
await beacon.stop();
process.exit(0);
});
The beacon keeps the first Node snapshot as a baseline and does not send it. Call flush() before shutdown, so that the last counts are sent.
If globalThis.__coverage__ has Istanbul counters, the Node beacon uses them instead of V8 coverage. Set coverageSource: "v8" or coverageSource: "istanbul" to select the source yourself.
Use a full fallow_live_k1_ key and keep it on the server. Bun and Deno need Istanbul instrumentation at build time, because their V8 capture is unavailable or incomplete.
Verify the first ingest
The beacon logs nothing when an upload succeeds. To confirm that data arrives, check one of these signals:
POST https://api.fallow.cloud/v1/ingestreturns202 Acceptedin the browser network panel or server proxy logs.- The onboarding card at fallow.cloud changes to a repository row after aggregation.
- The key's
last usedvalue updates under Settings, API keys.
Fallow Cloud processes an accepted ingest asynchronously. Expect a short delay between the 202 response and the repository row.
If the dashboard stays empty
Check these in order:
endpointis exactlyhttps://api.fallow.cloud.- Browser code uses an ingest-only key. Server code uses a full key.
- The configured environment variable exists in the production build or process.
projectIdis stable and different for each repository or service.- Browser builds contain Istanbul counters, or Node started with
NODE_V8_COVERAGE. - The app exercised real routes or jobs after the beacon started.
- The first
/v1/ingestresponse is202, not401,403,402,413, or429. A206response also means that Fallow Cloud accepted the data, but it keeps only a sample of the payloads. projectIdis 200 characters or fewer,environmentis 64 characters or fewer, andcommitShais a git SHA of 40 characters or fewer. A container image ref does not fit incommitSha.commitShacontains only the charactersA-Z,a-z,0-9,.,_and-, and not only dots./v1/ingestrejects any other value with400. Deployments, inventories and source maps use the same rule, so the runtime SHA always matches them. An emptycommitShacounts as no SHA.
When the Node beacon finds no coverage source, or a configuration value is too long or has characters that ingest rejects, it reports one onRuntimeMismatch error that tells you what to fix. Then it stops. Without an onRuntimeMismatch callback, the beacon logs the error with console.error. Fix that error before you wait for another batch.
Add static inventory
Runtime capture tells Fallow Cloud only what V8 or Istanbul observed. To see the functions that were never tracked, upload the static inventory in CI. Fallow Cloud then shows them as untracked:
# FALLOW_API_KEY holds the API key as a CI secret
fallow coverage upload-inventory
The command reads the key from FALLOW_API_KEY. You can also pass --api-key, but on a shared CI runner other processes can see a command-line secret.
The inventory must use the same project id as the beacon projectId. By default, the command uses $GITHUB_REPOSITORY, then $CI_PROJECT_PATH, then the origin remote URL. Pass --project-id when your beacon uses a different value. If your deployment runs from a container directory such as /app, pass --path-prefix /app, so that the inventory paths match the paths that the beacon reports.
For bundled or minified code, also upload source maps from CI. fallow coverage documents the inventory and source-map commands.
Privacy
The beacon sends function paths, names, positions, hit counts, project metadata, and delivery reports. It does not send arguments, request bodies, environment variables, or source code. The network activity disclosure lists everything the beacon sends.