Telemetry
The self-hosted Dakera engine sends product telemetry to Dakera's PostHog project. It tells us how many engines run, and how they run: which versions, platforms and storage setups, whether they stay up, how often they are upgraded, and how much they are used. We use it to decide what to build, test and support, and to find the crashes and slow paths that users rarely report.
This page is for operators who need to know exactly what leaves their server: every event and property, what is never sent, how to inspect each payload and how to turn telemetry off.
In v0.12.0 the engine sends the machine's hostname, and PostHog keeps the IP address the events come from and derives a coarse location from it (GeoIP). Both stop with one setting: DAKERA_TELEMETRY=0 or DO_NOT_TRACK=1. A memory engine holds sensitive data, so telemetry is built on these rules:
- it never reads what you store;
- everything it sends is listed on this page;
- you can inspect every payload;
- one setting turns it off.
Turning it off
Set either variable, in the server's environment. Nothing is then counted, written or sent.
DAKERA_TELEMETRY=0 ./dakera # also: false | off | no
DO_NOT_TRACK=1 ./dakera # the cross-tool convention; also: true
At startup the engine logs one line: what it sends and how to turn it off, or that telemetry is disabled.
Seeing exactly what is sent
With this setting, the engine logs every batch of events (as JSON) before it sends it:
DAKERA_TELEMETRY_DEBUG=1 ./dakera
What is NEVER sent
- Memory content, embeddings, queries, prompts or anything else a user wrote.
- Ids and names: memory, agent, session, namespace and API-key ids, or any name you chose.
- API keys, passwords, tokens or any other secret.
- File paths, URLs, bucket names, endpoints: no text value of any setting.
- Raw User-Agent strings: only the client kind and major.minor version.
- Exact business volumes: request, memory, agent and namespace counts are rounded to two significant digits (12 345 → 12 000).
What identifies a deployment
Telemetry is not anonymous at the network level:
- Hostname:
engine_startedandengine_heartbeatcarry the machine's hostname (hostname), as the operating system reports it. - IP address: PostHog records the IP address the events come from (
$ip), as any web service sees it, and derives a coarse location from it (GeoIP: country, region, city).
Both are used to count and understand deployments, never sold or shared. If
you do not want them sent, turn telemetry off (DAKERA_TELEMETRY=0 or
DO_NOT_TRACK=1); nothing else changes.
PostHog creates no person profile ($process_person_profile: false).
Identity
| Id | What it is | Where it lives |
|---|---|---|
distinct_id |
A random UUID for this node, created at its first start. Not derived from anything about your machine or data. | <data root>/., the same file v0.11 used, so an upgrade keeps it. |
deployment_id |
The id of the deployment: the same on every replica and every recreated container of one deployment. | See below. |
run_id |
A random UUID for this process, new at every start. | Not persisted. |
Where deployment_id comes from:
- S3 storage: the bucket's
.instance_idobject. The first start writes it, seeded with this node's id. - Cluster: the smallest
deployment_idgossiped by the live members. - Otherwise: the node's own id.
When the data root is read-only, the engine falls back in this order:
$XDG_STATE_HOME/dakera/.instance_id;- an app-specific hash of
/etc/machine-id, from which the machine-id cannot be recovered; - a random id per process, reported with
id_ephemeral: true.
The node also keeps a small record at
<data root>/_dakera_cluster/telemetry.json. It holds:
- the version and start time of the last run;
- whether that run stopped cleanly;
- lifetime request totals;
- a random local salt;
- the salted fingerprints.
The engine uses it to tell restarts, upgrades and crashes apart. The record
never leaves the machine. If you copy a data directory, delete .instance_id
and _dakera_cluster/telemetry.json in the copy to give it its own identity.
When events are sent
All events of a moment go in one HTTPS POST to
{DAKERA_TELEMETRY_HOST}/batch/ (default https://eu.i.posthog.com, EU).
| Event | When |
|---|---|
engine_started |
Once per process, when the server is ready (models loaded). If it never gets ready, at shutdown or after 10 minutes, with ready: false. |
engine_ |
With engine_started, then every 6 hours, and at a graceful stop. |
engine_stopped |
At a graceful stop. |
engine_crashed |
At the next start, when the previous run did not stop gracefully. Dated when that run was last seen alive. |
engine_ |
At the first start on a new version. |
A node that has started five times or more in the past hour (a crash loop) sends no start-time events. The next start outside the loop reports how many were suppressed.
Sending never gets in the way:
- Each request times out after 3 s.
- A failed batch is kept (at most 50 events) and retried after 15 minutes, then 30, 60, and so on, up to 6 hours. There are no retry storms.
- Offline or air-gapped, sends fail quietly: a debug log line, nothing else.
- Shutdown waits for telemetry at most 2 s.
- On the request path, counting is an atomic increment.
Properties
On every event
| Property | Example | Meaning |
|---|---|---|
distinct_id, deployment_id, run_id |
UUIDs | See Identity |
deployment_ |
data_root, bucket, cluster, node |
Where the deployment id came from |
boot_seq |
12 |
This node's start count |
id_source, id_ephemeral |
data_root, false |
Where the node id lives (data_root, state_home, machine_id, ephemeral) |
version, product, dakera_schema |
0.12.0, dakera-engine, 4 |
|
os, arch |
linux, x86_64 |
|
deployment |
docker, k8s, binary |
Detected. DAKERA_ overrides it, but only a known kind is sent; anything else is sent as custom. |
deployment_type |
production, ci, development, staging |
Detected. DAKERA_ overrides it, with the same closed-set rule. |
container_ |
docker, podman, containerd, lxc, none |
|
is_internal |
false |
DAKERA_INTERNAL: Dakera's own infrastructure |
Environment, configuration and health (engine_started, engine_heartbeat)
| Property | Meaning |
|---|---|
kernel |
Kernel major.minor (6.8) |
os_distro, os_ |
/etc/os-release ID / VERSION_ID (debian, 12) |
cloud |
The provider, read from the machine's DMI vendor. A closed set: aws, gcp, azure, hetzner, digitalocean, oracle, alibaba, ovh, scaleway, linode, vultr, openstack, vmware, kvm, virtualbox, apple, other, unknown. |
cpu_count, cpu_quota |
CPUs available; the cgroup CPU limit in cores |
memory_, memory_ |
Host memory; the cgroup memory limit |
gpu_build, gpu_devices |
A CUDA build; the number of NVIDIA devices |
hostname, hostname_ |
The machine's hostname; low / medium / high: a named host vs a generated one |
storage, tiered_storage, hot_tier, wal |
The storage topology (memory, segmented, filesystem, s3; the WAL is on, off, tiered or backend) |
cluster, cluster_role, redis, grpc, auth, tiered_, otel_tracing |
What is switched on |
data_origin |
fresh (installed by v0.12), existing (upgraded), undetermined |
embedding_model |
The model that embeds memories (bge-large, …) |
config_vars |
The names of the Dakera variables that are set. Only registered names; a misspelled name is only counted, in config_. |
cfg_<name> |
The value of each set variable that is a boolean, a choice from a fixed list, a number, or a model or mode name. For example cfg_, cfg_. A text variable (path, URL, key, secret, label) is never sent, whatever it holds. |
config_, config_hash |
How many are set. A hash of exactly the names and values above, so identical configurations can be counted. |
config_warnings, config_ |
How many configuration warnings, and their categories (env_name, data_location, …). The messages are never sent. |
degraded_ |
The names of components running degraded (reranker, …). The reasons are never sent. |
engine_started
| Property | Meaning |
|---|---|
start_kind |
first_start, restart, upgrade or downgrade |
previous_ |
The version of the previous run (pre-0.12 after a v0.11 upgrade) |
previous_exit |
clean, unclean (killed, OOM-killed, power loss), panic, none (first start) or unknown |
previous_, downtime_s, previous_run_id |
How long the previous run lived, how long the node was down, and which run it was |
startup_ms, ready |
Time from process start to ready; whether it got there |
host_changed, config_changed |
Whether the host or the configuration changed since the previous run, from local salted fingerprints (only the yes/no is sent) |
install_ |
Days since this node was first seen |
starts_ |
Starts the crash-loop throttle did not report |
cli_, cli_models_runs |
dakera downgrade / dakera models runs since the previous start (counted on disk; the CLI itself sends nothing) |
engine_heartbeat
| Property | Meaning |
|---|---|
interval_s, uptime_s, uptime_bucket |
The time the heartbeat covers; process uptime |
rss_bytes, rss_peak_bytes, memory_used_pct |
Resident memory, peak, and share of the limit |
cpu_cores_used, cpu_percent |
Average CPU over the interval |
threads, open_fds |
|
tcp_connections, tcp_ |
Clients connected to the REST and gRPC ports |
inflight_, inflight_peak |
Requests being served now; the peak since start |
requests, requests_ |
Client requests in the interval, and since the node's first start. Probes, /metrics scrapes and cluster peer traffic are excluded. |
req_<class>, req_ |
Requests per class: store, recall, search, memory_read, memory_update, forget, session, agent, knowledge, vector_write, vector_query, multimodal, extract, import_export, admin, events, infra, internal, unmatched, other |
lat_, lat_ |
Latency percentiles, as histogram bucket bounds (5, 10, 25, 50, 100, 250, 500 ms, 1, 2.5, 5, 10, 30, 60 s) |
responses_2xx, responses_4xx, responses_429, responses_5xx, responses_503, error_rate_pct, error_ |
Response status classes and the 5xx rate over client requests |
grpc_requests |
Calls on the gRPC port |
memory_writes, memory_reads, memory_, memory_ |
Memory store and recall operations: v2 bucket and rounded count |
memories_total, agents_total, namespaces_, total_ |
Scale, as counts only |
recall_ |
The v3 recall p50 band |
clients_, clients_ |
Requests per client kind (py, js, go, rust, cli, mcp, other), taken from the dakera-<kind>/<version> User-Agent |
cluster_members |
Live cluster members (cluster mode) |
engine_crashed
| Property | Meaning |
|---|---|
reason |
unclean or panic |
panic_location |
The source location of a panic (api/). The panic message is never sent. |
suspected_oom |
The previous run's last memory sample was at 90 % or more of its limit |
reached_ready, previous_, previous_, previous_run_id, last_rss_bytes, last_ |
engine_version_changed and engine_stopped
engine_version_changedcarriesfrom_version,to_version,direction(upgrade/downgrade) andprevious_run_id.engine_stoppedcarriesuptime_sandready.
Closed sets
Operator-set labels are sent only when they are one of these words; any
other value is sent as custom:
DAKERA_DEPLOYMENT:k8s,kubernetes,helm,docker,compose,docker-compose,podman,nomad,ecs,cloudrun,fly,railway,render,systemd,binary,source.DAKERA_DEPLOYMENT_TYPE:production,staging,development,ci,test,demo,internal.
Configuration reference
No variable is needed. These existed before v0.12; none is new.
| Variable | Default | Meaning |
|---|---|---|
DAKERA_ |
enabled | 0/false/off/no disables |
DO_NOT_TRACK |
unset | 1/true disables |
DAKERA_ |
unset | 1 logs each batch before it is sent |
DAKERA_ |
https:// |
PostHog ingestion host (a fork or your own PostHog) |
DAKERA_ |
built-in write-only key | Point a fork at a different PostHog project |
DAKERA_ |
detected | Deployment kind (closed set, else custom) |
DAKERA_ |
detected | Deployment purpose (closed set, else custom) |
DAKERA_INTERNAL |
unset | 1/true marks a Dakera-internal deployment |
Heartbeats from development builds (version 0.0.0) are dropped at the
source.