Synadia Insights

Telemetry

Insights trial builds send a small pulse every few minutes describing how the instance is used. This page lists every field it contains, and everything it deliberately does not.

What sends it

Only a trial build. Every other build contains no reporter at all: no destination, no credential, and no payload type are linked into it. That is a property of what was compiled, not a setting that could be changed at runtime.

Within a trial build, one process reports: a node running insights serve or insights-collector serve. The mcp and http servers and one-shot subcommands such as db query and ops backup save hold no license and send nothing themselves. They are counted, if at all, by the server that answers their requests (see Usage). So is insights web: what a person does in the UI it serves is counted by the node holding each system's database.

Turning it off

telemetry:
  enabled: false

Equivalently --telemetry=false or INSIGHTS_TELEMETRY=false.

The same setting applies to insights web, which sends nothing itself but passes what people do in its UI to the nodes that report it (see Usage). Switched off there, it passes nothing on.

There is no setting for where a pulse goes. The destination is fixed when the binary is built, so you can switch reporting off, or read exactly what it would send, but you cannot point it somewhere else. That keeps "what this build sends, and where" a property of the artifact rather than of one deployment.

To see exactly what your instance sends, set telemetry.print: true (or --telemetry.print) and every pulse is written to the log verbatim before it leaves, together with whether this build can deliver it.

What a pulse contains

A pulse is one JSON object. Run identity and build are top-level fields; the rest is grouped under config, stats (environment size and findings), and usage. This is a pulse from a node in use:

{
  "schema": 1,
  "instance": "3f9c2a4e8b1d4c6fa0e2b7d95c8e1f34",
  "session": "b7e14c0a92d34f6e8a1c5d7f3e9b2a60",
  "seq": 42,
  "ts": "2026-09-15T14:05:00Z",
  "version": "1.2.0",
  "platform": "linux/arm64",
  "build": "full",
  "config": { "scrape": 60, "pulse": 300, "retention": 2764800, "webhooks": 2, "web": true },
  "stats": {
    "systems": 1,
    "clusters": 3,
    "servers": 14,
    "leafnodes": 6,
    "accounts": 22,
    "connections": 1840,
    "streams": 212,
    "consumers": 960,
    "epochs": 4320,
    "checks": 7
  },
  "usage": {
    "act.filter": 2,
    "act.search": 1,
    "client.cli": 1,
    "page.checks": 6,
    "page.streams": 14,
    "page.streams.detail": 9,
    "viewers": 2
  }
}

Zero is absent throughout: a field with a zero, empty, or false value is not sent at all, so an instance nobody has opened sends a fraction of what is listed here. A group with nothing in it is left out too.

Run identity

FieldMeaning
schemaPayload version.
instanceA random identifier for this deployment, generated on first start and stored in telemetry-id in the data directory, a plain-text file holding that one value, which you can read or replace. It is not derived from your hostname, node id, or anything else about the machine.
sessionA random identifier for this run of the process.
seqPulse number within the run, from 1.
tsWhen the pulse was built.
collectorsSent only by a node whose catalogs are fed by collectors: those collectors' instance values, so the two read as parts of one installation. A collector hands its instance to the catalog it feeds over your own NATS ($INS.sys.<id>.ops.sink.info); which system it collects is never sent.

instance and session exist so a restart is distinguishable from a new install. They mean nothing outside Synadia's own records and identify no person, host, or network.

Build

FieldExample
version1.2.0
platformlinux/arm64
buildfull or collector

Configuration

Under config. Counts and durations only, never values. No URL, hostname, path, credential, threshold, or system id appears here.

FieldMeaning
scrapeScrape interval, in seconds. Absent on a node that scrapes nothing itself, such as a catalog fed by collectors.
pulseHow often these messages are sent, in seconds. It is here so the receiver can tell a late pulse from a stopped instance.
retentionDatabase retention window, in seconds. Absent when retention is disabled.
webhooksHow many notification endpoints are configured. The count only, never their URLs, credentials, or names.
simulatorPresent only when the built-in simulator is running.
webPresent only when this node serves the web UI itself. A separate insights web node sends no pulse, so a node viewed through one reports its page views without this field.

Environment size

Under stats. Exact counts of things, never the things: fourteen servers, not which fourteen.

clusters, servers, leafnodes, accounts, connections, streams, and consumers: each an integer, each counted at the most recent scrape. systems is how many monitored systems the node holds, and epochs how many epochs its databases retain. A node holding several systems reports the sum across them.

Findings

Under stats.

FieldMeaning
checksHow many distinct checks have a finding at the most recent scrape. The count only, never which checks, on which entities, or what they found.

One number, and it says how much Insights is telling you rather than what it is telling you. Which checks fire describes your deployment and stays in your instance, along with everything else in What never leaves the process.

Usage

Under usage. How much the instance is used, so one someone works in daily can be told apart from one left running unattended.

FieldMeaning
viewersHow many distinct browser sessions have opened this node's systems in the UI. The UI keeps a random identifier in the browser's session cookie, so the tabs and windows of one browser are one viewer, and closing the browser starts a new session. The identifier goes no further than the node that counts it, over your own NATS, where it is hashed; only the size of the set is reported, and it stops growing at 512.
page.<name>How many times a page was opened, by page. Names come from a fixed list: clusters, servers, leafnodes, connections, services, streams, kvstores, objectstores, consumers, accounts, users, checks, integrations, operations, search, systems, nodes, and map. A page not on the list counts as other. A check's page counts as checks whichever entity it belongs to, and the systems map as map.
page.<name>.detailThe same, for a page showing one entity. A system's own page is systems.detail, one system out of the list at page.systems.
act.filterTable sorts, filters, and page changes.
act.searchUses of the search box. The search terms are never sent.
client.cliRequests to this node's API from the insights command line.
client.agentRequests a coding agent made rather than a person: the insights command line run by an agent, or any request that names itself agent in the client header, such as a raw NATS request. The command line recognises an agent by an environment variable it sets for its commands: AI_AGENT, or one specific to Claude Code, Codex, pi, OpenCode, Gemini CLI, Cursor, Antigravity, GitHub Copilot, Goose, or Amp. Only whether one is present is read; which agent is never sent. An agent that sets none of them is counted under client.cli.
client.mcpRequests from an MCP client, via insights mcp.
client.httpRequests through the HTTP endpoint, insights http.

The client.* counters come from a header naming which first-party tool made each request, and nothing about the request itself. The web UI does not set it, so its own queries are not counted here; a page view already records them.

Page views, actions, and viewers are counted by the node holding the viewed system's database, wherever the UI is served. A node serving the UI for several sites passes each view to that site's node over NATS ($INS.sys.<id>.usage.record), and that node's pulse reports it. Pages that belong to no one system (the systems list, node inventory, search, and map) are counted by the serving node when it holds a database of its own, and otherwise by the node for the system whose id sorts first.

Every usage field is a running total for the life of the process, counting up from zero at start. The rest of a pulse (configuration and environment size) is a reading taken at the moment it was sent.

Health probes are not counted, and neither is a browser tab regaining focus or a dropped connection re-establishing and repeating the action it was already showing, nor an old or mistyped link that only redirects. The page it lands on is counted instead.

What never leaves the process

Insights holds a detailed picture of your NATS deployment. None of it is included, and this list is as much a part of the specification as the fields above:

  • Server, cluster, gateway, and leafnode names
  • Account names and nkeys, user names
  • Subjects, and stream, consumer, KV, and object store names
  • Message data, headers, and payloads
  • IP addresses and geolocation of anything you monitor
  • Your hostname and node id
  • Request paths and URLs
  • SQL query text and search terms
  • Check findings and their contents: which checks fired, on what, and why. The checks field is a count of distinct checks and carries none of it
  • Configuration values: no NATS URLs, credentials, tokens, webhook endpoints, file paths, TLS material, or check thresholds
  • Session identifiers
  • Error messages and log lines

The IP address your instance connects from is discarded on arrival: it is not logged, stored, or retained.

How it is sent

One NATS message every five minutes, roughly half a kibibyte (about 150 KiB a day), published to Synadia Cloud over a WebSocket connection on port 443. The interval is configurable (telemetry.interval); the destination is not.

The connection is opened for the publish and closed again, so nothing is held open in your network, nothing reconnects in the background, and an instance with no route out simply does nothing. There is no inbound access, no listening socket, and no long-lived session.

The credential is compiled into the binary and is the weakest one that can do the job: it may publish to the telemetry subject and nothing else. It cannot subscribe, request, or read anything.

Your instance is identified by a single subject token: the team id from your license. The license itself is never sent: your instance has already verified it locally, so there is nothing to gain by putting it on the wire.

If the message cannot be delivered it is dropped and the next one carries the same running totals. Telemetry never delays a start, never delays a shutdown, and never writes an error you have to read.

One limitation worth stating: unlike an HTTP client, the NATS client does not honour HTTPS_PROXY. Behind a proxy that requires CONNECT, pulses will not be delivered, and nothing will complain about it.

Previous
Metrics