Device Offline
The Device Offline trigger fires when an active-shift device stops reporting location updates for longer than a configured threshold. Use it to detect dead batteries, lost connectivity, force-closed apps, or any silent failure where a tracker stops communicating without explicitly ending its shift.
For full backward compatibility, the API and SDK use trigger_type: "device_last_seen" as the internal identifier. Customers see "Device Offline" in the Workflow Builder UI and in this documentation; both refer to the same trigger.
What It Does
A scheduled scanner inspects every active-shift device in your workspace and compares its last_location_time to the configured threshold_minutes. When a device exceeds the threshold without reporting a new location, the workflow fires with a payload that includes the device identity, the stale duration, and the last known location (if any).
The trigger fires from the server-side scanner, not from a device-side event — so it works even when a device has gone completely silent.
When to Use
- Track field workers' phones that should be transmitting continuously during a shift
- Detect failed IoT trackers, equipment with dead batteries, or stalled GPS units
- Alert dispatch when a vehicle tracker drops off the network during a delivery run
- Surface devices that have crashed or been force-quit but didn't end their shift cleanly
Configuration
| Knob | Type | Default | Min / Max | Description |
|---|---|---|---|---|
threshold_minutes | integer | (required) | 2 / 10080 (1 week) | How long a device may go silent before the trigger fires. |
repeat_policy | string | once_until_seen | enum | once_until_seen fires once per stale period and re-arms only after the device is seen again. every_interval re-fires every cooldown. |
cooldown_minutes | integer | none | 1 / 10080 | Required when repeat_policy is every_interval. Minutes to wait before re-firing for the same still-stale device. |
device_filters | object | {} (all devices) | — | Optional filter: device_ids, exclude_device_ids, device_types (mobile, vehicle, iot, tracker, other), and metadata_match. |
Trigger Payload
When the trigger fires, the following trigger_data envelope is delivered to every downstream action. Optional fields are only present when the underlying data is available.
{
"event_type": "device_last_seen",
"signal_type": "device_last_seen",
"device_id": "truck-42",
"device_name": "Truck 42",
"device_type": "vehicle",
"workspace_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"last_seen_at": "2026-05-20T14:12:00+00:00",
"minutes_since_seen": 18,
"threshold_minutes": 15,
"stale_since": "2026-05-20T14:27:00+00:00",
"repeat_policy": "once_until_seen",
"shift_status": "active",
"location": {
"latitude": 37.7749,
"longitude": -122.4194
}
}
Template Variables
Reference these in any action body using the standard {{trigger.xxx}} syntax.
| Variable | Resolved Value |
|---|---|
{{trigger.event_type}} | "device_last_seen" (internal type string) |
{{trigger.signal_type}} | "device_last_seen" (mirrors event_type for signal-aware consumers) |
{{trigger.device_id}} | External device identifier (customer-assigned) |
{{trigger.device_name}} | Human-readable device name |
{{trigger.device_type}} | "mobile", "vehicle", "iot", "tracker", or "other" |
{{trigger.workspace_id}} | UUID of the workspace that owns the device |
{{trigger.last_seen_at}} | ISO 8601 timestamp of the device's last reported location |
{{trigger.minutes_since_seen}} | Integer minutes elapsed since last_seen_at |
{{trigger.threshold_minutes}} | The threshold the trigger was configured with (echoed back) |
{{trigger.stale_since}} | ISO 8601 timestamp at which the device crossed the threshold |
{{trigger.repeat_policy}} | "once_until_seen" or "every_interval" |
{{trigger.shift_status}} | Current shift status (when present) — typically "active" |
{{trigger.location.latitude}} | Last known latitude (only present if a location was ever reported) |
{{trigger.location.longitude}} | Last known longitude (only present if a location was ever reported) |
Example Use Case
Scenario. A logistics company tracks 200 delivery vans with phone-based GPS trackers. Drivers occasionally lose signal in parking garages or rural areas, but anything beyond 15 minutes of silence during an active shift indicates a real problem — a dead battery, a crashed app, or a connectivity failure.
Workflow.
- Trigger: Device Offline with
threshold_minutes: 15andrepeat_policy: once_until_seen, filtered todevice_types: ["vehicle"]. - Action 1 — Slack: Notify
#dispatchwith the driver name and last known location. - Action 2 — Webhook: POST to the fleet management system so the dispatcher's dashboard flags the van as "comms lost".
When the device reports a location again, the workflow re-arms automatically (because of once_until_seen) and will fire again the next time the same device goes silent for 15+ minutes.
Dashboard Status Pills
The manager dashboard surfaces this trigger's anomaly state as a status pill on the device list and a colored halo on the map marker.
Status pills (and the corresponding map halos) are driven by the workflow's debounce state. They appear only when a workspace has at least one active workflow using this trigger. A workspace with no anomaly workflows will show no pills — that's expected behavior, not a bug. Add a minimal workflow (any action — even a no-op email) to start surfacing the indicator.
The same applies to Device Stuck and Shift Overdue pills.
Related Recipes
End-to-end runnable guides for routing this trigger to external systems:
- Slack Alerting — incoming webhook + copy-pasteable JSON
- PagerDuty Alerting — Events API v2 incident payload
- Generic HTTP Alerting — minimal curl-testable pattern
See Also
- Device Stuck — device is reporting, but not moving
- Shift Overdue — shift has run longer than expected
- Workflows In Depth — actions, templates, and execution model