Telemetry
Stream live telemetry from devices, query historical data over time ranges, and fetch the latest reading for any metric.
Access via app.telemetry.
API
stream()
Subscribe to live telemetry from a device.
- JavaScript
- Python
app.telemetry.stream(params)await app.telemetry.stream(params)| Parameter | Type | Description |
|---|---|---|
device_ident | string | The device identifier. Must match [a-zA-Z0-9_-]+ |
metric | string[] or "*" | Metrics to subscribe to. Use "*" for all metrics. A non-"*" string is rejected, pass an array for specific metrics |
callback | function | Called with each incoming reading. Python accepts both sync and async callbacks |
The callback receives an object with metric and data:
| Field | Type | Description |
|---|---|---|
metric | string | The metric name |
data.value | any | The reading value (matches the device schema type) |
data.timestamp | number | Unix milliseconds when the device published the reading |
- JavaScript
- Python
// subscribe to specific metrics
app.telemetry.stream({
device_ident: "sensor_01",
metric: ["temperature", "humidity"],
callback: (data) => {
console.log(`${data.metric}:`, data.data.value, "at", data.data.timestamp);
},
});
// subscribe to all metrics
app.telemetry.stream({
device_ident: "sensor_01",
metric: "*",
callback: (data) => {
console.log(`${data.metric}:`, data.data.value);
},
});
# subscribe to specific metrics
await app.telemetry.stream({
"device_ident": "sensor_01",
"metric": ["temperature", "humidity"],
"callback": lambda data: print(f"{data['metric']}: {data['data']['value']}"),
})
# subscribe to all metrics
await app.telemetry.stream({
"device_ident": "sensor_01",
"metric": "*",
"callback": lambda data: print(f"{data['metric']}: {data['data']['value']}"),
})
You can call stream() multiple times for the same device with different metric sets and callbacks. Each call creates an independent subscription.
The SDK throws if device_ident is empty or contains characters outside [a-zA-Z0-9_-], if metric is anything other than "*" or a non-empty array, if callback is not a function, or if the app is not connected.
off()
Unsubscribe from live telemetry.
- JavaScript
- Python
app.telemetry.off(params)await app.telemetry.off(params)| Parameter | Type | Description |
|---|---|---|
device_ident | string | The device identifier |
metric | string[] | (optional) Specific metrics to unsubscribe. Omit to unsubscribe all |
- JavaScript
- Python
// unsubscribe from specific metrics
app.telemetry.off({
device_ident: "sensor_01",
metric: ["temperature"],
});
// unsubscribe from all metrics for a device
app.telemetry.off({
device_ident: "sensor_01",
});
# unsubscribe from specific metrics
await app.telemetry.off({
"device_ident": "sensor_01",
"metric": ["temperature"],
})
# unsubscribe from all metrics for a device
await app.telemetry.off({
"device_ident": "sensor_01",
})
A metric-specific off() does not tear down a wildcard ("*") subscription on the same device. If you started a stream with metric: "*", you have to call off({ device_ident }) without a metric filter to remove it. Calling off() on a device with no active subscriptions is a no-op, not an error.
history()
Query historical telemetry data over a time range.
- JavaScript
- Python
await app.telemetry.history(params)await app.telemetry.history(params)| Parameter | Type | Description |
|---|---|---|
device_ident | string | The device identifier |
fields | string[] | Metrics to query |
start | string | Start time (ISO 8601, UTC) |
end | string | End time (ISO 8601, UTC) |
interval | string | Optional. Bucket size as a Flux duration ("30s", "5m", "1h"). Must be paired with aggregate_fn. |
aggregate_fn | string | Optional. One of "mean", "min", "max", "sum", "count", "first", "last", "median", "stddev". Must be paired with interval. |
Returns an object keyed by metric name, each containing an array of data points
- JavaScript
- Python
const history = await app.telemetry.history({
device_ident: "sensor_01",
fields: ["temperature", "humidity"],
start: "2026-03-01T00:00:00.000Z",
end: "2026-03-02T00:00:00.000Z",
});
// history.temperature = [{ value: 22.5, timestamp: ... }, ...]
// history.humidity = [{ value: 61.3, timestamp: ... }, ...]
history.temperature.forEach((point) => {
console.log(`${point.value} at ${point.timestamp}`);
});
history = await app.telemetry.history({
"device_ident": "sensor_01",
"fields": ["temperature", "humidity"],
"start": "2026-03-01T00:00:00.000Z",
"end": "2026-03-02T00:00:00.000Z",
})
# history["temperature"] = [{"value": 22.5, "timestamp": ...}, ...]
for point in history["temperature"]:
print(f"{point['value']} at {point['timestamp']}")
Example response:
{
"temperature": [
{ "value": 22.5, "timestamp": 1774690200000 },
{ "value": 23.1, "timestamp": 1774690205000 },
{ "value": 22.8, "timestamp": 1774690210000 }
],
"humidity": [
{ "value": 61.3, "timestamp": 1774690200000 },
{ "value": 60.8, "timestamp": 1774690205000 }
]
}
If a metric has no data in the queried range, the array will be empty:
{
"temperature": [],
"humidity": []
}
Aggregating over time
Pass interval and aggregate_fn together to bucket readings into time intervals and aggregate within each bucket. This is useful for charting trends over long ranges where the raw data would be too dense to plot.
- JavaScript
- Python
// hourly mean temperature for the last day
const hourly = await app.telemetry.history({
device_ident: "sensor_01",
fields: ["temperature"],
start: "2026-03-01T00:00:00.000Z",
end: "2026-03-02T00:00:00.000Z",
interval: "1h",
aggregate_fn: "mean",
});
# hourly mean temperature for the last day
hourly = await app.telemetry.history({
"device_ident": "sensor_01",
"fields": ["temperature"],
"start": "2026-03-01T00:00:00.000Z",
"end": "2026-03-02T00:00:00.000Z",
"interval": "1h",
"aggregate_fn": "mean",
})
The response shape is unchanged: each metric is an array of { value, timestamp } points, one per bucket boundary, aligned across all requested metrics.
Passing one without the other has no effect. Both are required to switch from raw points to aggregated buckets.
History retention depends on your plan. For example, the free plan retains 3 days of history. Queries outside your retention window will return empty arrays.
latest()
Get the most recent reading for each metric.
- JavaScript
- Python
await app.telemetry.latest(params)await app.telemetry.latest(params)| Parameter | Type | Description |
|---|---|---|
device_ident | string | The device identifier |
fields | string[] | Metrics to query |
start | string | Start of lookup window (ISO 8601, UTC) |
end | string | End of lookup window (ISO 8601, UTC) |
Returns an object keyed by metric name, each containing the latest value and timestamp (Unix milliseconds).
- JavaScript
- Python
const latest = await app.telemetry.latest({
device_ident: "sensor_01",
fields: ["temperature", "humidity"],
start: "2026-03-28T00:00:00.000Z",
end: "2026-03-29T00:00:00.000Z",
});
// latest.temperature = { value: 25.3, timestamp: 1774742340000 }
console.log("Temperature:", latest.temperature.value);
console.log("Humidity:", latest.humidity.value);
latest = await app.telemetry.latest({
"device_ident": "sensor_01",
"fields": ["temperature", "humidity"],
"start": "2026-03-28T00:00:00.000Z",
"end": "2026-03-29T00:00:00.000Z",
})
# latest["temperature"] = {"value": 25.3, "timestamp": 1774742340000}
print("Temperature:", latest["temperature"]["value"])
print("Humidity:", latest["humidity"]["value"])
Example response:
{
"temperature": { "value": 25.3, "timestamp": 1774742340000 },
"humidity": { "value": 60.1, "timestamp": 1774742325000 }
}