docs/netdata-ai/skills/query-netdata-cloud/how-tos/fleet-connectivity-slo-queries.md
For a fleet of devices (IoT gateways, robots, edge nodes) streaming to Netdata parents:
TOKEN, SPACE, ROOM (see SKILL.md prerequisites)mycollector.upstream_connectivity, dimension Overallafter in relative seconds)average of a 0/1 metric IS the ratioAll four questions reduce to one trick: the average of a 0/1 series
is the fraction of 1s. No countif needed (see gotcha 3):
Percent of fleet connected (from the parents' per-child streaming
state). Netdata parents (v2.10.0-nightly 2026-06+ pulse) expose
netdata.streaming.in.state — a per-child one-hot chart with 0/1
dimensions running, offline, archived, waiting,
waiting replication, replicating. The fleet ratio is the average
of running across all tracked children:
source docs/netdata-ai/skills/query-netdata-agents/scripts/_lib.sh
agents_load_env
agents_query_cloud POST /api/v3/spaces/$SPACE/rooms/$ROOM/data '{
"scope":{"contexts":["netdata.streaming.in.state"],"dimensions":["running"]},
"selectors":{"nodes":["*"],"contexts":["*"],"instances":["*"],"dimensions":["*"],"labels":["*"],"alerts":["*"]},
"window":{"after":-21600,"before":0,"points":12},
"aggregations":{"metrics":[{"group_by":["selected"],"aggregation":"avg"}],
"time":{"time_group":"average"}},
"format":"json2","options":["jsonwrap","minify","unaligned"],"timeout":60000}' \
| jq -r '.result.data[] | [(.[0]|todate), ((.[1][0]*10000|round)/100)] | @tsv'
One column, values 0–1 (multiply by 100 for %). The denominator is
every child the parents still track — including archived ones
(see gotcha 1).
Percent of devices with a boolean dimension at 1. Same pattern on the collector context — average the 0/1 dimension across all instances:
agents_query_cloud POST /api/v3/spaces/$SPACE/rooms/$ROOM/data '{
"scope":{"contexts":["CONTEXT"],"dimensions":["DIMENSION"]},
"selectors":{"nodes":["*"],"contexts":["*"],"instances":["*"],"dimensions":["*"],"labels":["*"],"alerts":["*"]},
"window":{"after":-21600,"before":0,"points":12},
"aggregations":{"metrics":[{"group_by":["selected"],"aggregation":"avg"}],
"time":{"time_group":"average"}},
"format":"json2","options":["jsonwrap","minify","unaligned"],"timeout":60000}' \
| jq -r '.result.data[] | [(.[0]|todate), ((.[1][0]*10000|round)/100)] | @tsv'
The opposite ratio is 100 − (step 2), computed client-side:
... | jq -r '.result.data[] | [(.[0]|todate), (100 - (.[1][0]*10000|round)/100)] | @tsv'
Do NOT use time_group: countif "=0" through Netdata Cloud for
this — see gotcha 3.
Rank devices by percent of time the dimension was 1 (or 0). Group by node, average over the whole window into a single point, then sort client-side:
agents_query_cloud POST /api/v3/spaces/$SPACE/rooms/$ROOM/data '{
"scope":{"contexts":["CONTEXT"],"dimensions":["DIMENSION"]},
"selectors":{"nodes":["*"],"contexts":["*"],"instances":["*"],"dimensions":["*"],"labels":["*"],"alerts":["*"]},
"window":{"after":-86400,"before":0,"points":1},
"aggregations":{"metrics":[{"group_by":["node"],"aggregation":"avg"}],
"time":{"time_group":"average"}},
"format":"json2","options":["jsonwrap","minify","unaligned"],"timeout":120000}' > /tmp/rank.json
# bottom 20 = devices with the LOWEST fraction of time at 1
jq -r '.view.dimensions as $d
| [range(0; ($d.ids|length)) | {n:$d.names[.], v:$d.sts.avg[.]}]
| sort_by(.v) | .[:20][]
| [((.v*10000|round)/100|tostring)+"%", .n] | @tsv' /tmp/rank.json
sort_by(.v) ascending = most-disconnected first; sort_by(-.v)
for the healthiest. The per-device value is in
view.dimensions.sts.avg[] when points:1.
percent<TAB>hostname of all devices.archived (long-gone or
re-parented duplicates), until their charts obsolete. In steps 2–4
the denominator is only devices whose collector produced data in
the window — fully offline devices drop out of the average
entirely (they have gaps, and gap points are excluded from group-by
aggregation). Pair step 1 (connectivity) with step 2 (health of the
connected) for the complete picture.totals.instances to equal the
room node count.countif through Netdata Cloud is unreliable (verified
2026-07-06). On a multi-parent space, time_group: countif with
group_by: selected returned ~29–43% of the true value, and
options: ["percentage"] returned >100% values. Plain
time_group: average on the same data returned correct results.
Until the Cloud aggregation of these is fixed, use the
average-of-boolean trick above. (Direct agent queries are not
affected.)countif (which
needs raw samples) is fragile here./spaces, /rooms, /nodes)