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 threshold counts from the later of the last location and the moment the shift started or resumed, so a device that has just begun or resumed a shift gets the full threshold to send its first location.
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, counted from a later shift start or resume if any |
{{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