Skip to main content

Signal Configuration Guide

This guide walks through configuring signal rules for anomaly detection in SpatialFlow. For background on what signals are and how they work, see the Signals concept page.

Dwell Detection Configuration

Dwell detection fires when a device stays inside a geofence beyond a time threshold. Thresholds are configured per-workflow in the trigger configuration, so multiple workflows can monitor the same geofence with different sensitivity levels.

Setting Up a Dwell Workflow

Create a workflow with a geofence_dwell trigger type:

curl -X POST https://api.spatialflow.io/api/v1/workflows \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Warehouse Dwell Alert",
"description": "Alert when a vehicle dwells at warehouse for 5+ minutes",
"trigger_config": {
"type": "geofence_dwell",
"event_type": "geofence_dwell",
"geofence_ids": ["a1b2c3d4-5678-90ab-cdef-1234567890ab"],
"dwell_threshold": 300
},
"steps": [
{
"type": "slack",
"name": "Notify warehouse team",
"config": {
"integration_id": "int_slack123",
"channel": "#warehouse-ops",
"message": "Vehicle {{trigger.device_id}} has been at {{trigger.geofence_name}} for {{trigger.dwell_time}}s"
}
}
],
"is_active": true
}'

Dwell Threshold

The dwell_threshold field specifies the minimum dwell duration in seconds before the signal fires. Valid range is 30 to 86,400 seconds (30 seconds to 24 hours). If omitted, the default is 300 seconds (5 minutes).

The threshold is per-workflow, meaning you can have multiple workflows monitoring the same geofence with different thresholds. Each workflow fires independently when its threshold is crossed.

Sensitivity Tuning

Lower thresholds detect shorter dwell events (more sensitive, more alerts). Higher thresholds require longer presence before firing (less sensitive, fewer alerts).

ScenarioThresholdNotes
Quick stop detection60s (1 min)Delivery confirmation
Standard dwell300s (5 min)Default, general purpose
Extended stay1800s (30 min)Warehouse loading
Long-term presence3600s (1 hour)Job site monitoring
Threshold Caching

Dwell thresholds are cached with a 60-second TTL (THRESHOLD_CACHE_TTL = 60). After changing a workflow's dwell threshold, it may take up to 60 seconds for the new value to take effect.

Policy Violation Configuration

Policies are workspace-level rules that evaluate on every processed location update. When a device's location matches a policy's conditions, a policy_violation signal fires.

Policy Structure

Each policy combines:

  1. Geofence condition -- The spatial boundary to monitor (required)
  2. Time window -- When the policy is active (optional; null = always active)
  3. Device filter -- Which devices to evaluate (optional; null = all devices)
  4. Role filter -- Which user roles to evaluate (optional; null = all roles)

All conditions must match simultaneously for a violation to fire.

Time Windows

Time windows restrict when a policy is active. Use them for after-hours monitoring, weekend restrictions, or shift-based rules.

{
"days_of_week": [0, 1, 2, 3, 4],
"start_time": "22:00",
"end_time": "06:00",
"timezone": "America/New_York"
}

Field details:

  • days_of_week -- Uses Python weekday convention: 0 = Monday, 1 = Tuesday, ..., 6 = Sunday
  • start_time / end_time -- 24-hour format (HH:MM). Overnight spans are supported (e.g., 22:00 to 06:00)
  • timezone -- IANA timezone string (e.g., America/New_York, Europe/London, UTC)

Set time_window to null for policies that should be active at all times.

Device Filters

Device filters narrow which devices the policy applies to, based on device type and metadata.

{
"device_types": ["vehicle", "tracker"],
"metadata_match": {"department": "logistics"}
}

Field details:

  • device_types -- List of device types to include. Valid values: mobile, vehicle, iot, tracker, other
  • metadata_match -- Key-value pairs that must match the device's metadata. All specified keys must match (AND logic)

Set device_filter to null for policies that apply to all devices.

Role Filters

Role filters restrict the policy to devices owned by users with specific workspace roles.

Valid roles: field_worker, member, manager, owner

["field_worker", "member"]

Set role_filter to null for policies that apply regardless of the device owner's role.

Violation Deduplication

Policy violations use two TTL values for lifecycle management:

  • VIOLATION_TTL = 86,400s (24 hours) -- Active violations are automatically cleaned up after 24 hours
  • DEDUPE_TTL = 300s (5 minutes) -- After a violation is resolved, the same policy cannot re-fire for 5 minutes, preventing rapid re-triggers when a device hovers at a geofence boundary

Workflow Trigger Configuration

Signals trigger workflows through two trigger types. Choose based on your detection needs.

Geofence Dwell Trigger

Use type: "geofence_dwell" for dwell detection. This is the primary path for time-based anomalies.

Schema:

FieldTypeRequiredDefaultDescription
typestringyes--Must be "geofence_dwell"
event_typestringyes--Must be "geofence_dwell"
geofence_idslistno[] (all)Limit to specific geofences
group_idslistno[]Include geofences from groups
dwell_thresholdnumberno300Seconds before dwell fires (30-86400)
device_filtersobjectno{}Filter by device criteria

Signal Trigger

Use type: "signal" for policy violations and general-purpose signal matching.

Schema:

FieldTypeRequiredDefaultDescription
typestringyes--Must be "signal"
signal_typeslistyes--Signal types to match (e.g., ["policy_violation"])
signal_stateslistno["confirmed"]States to trigger on
geofence_idslistno[]Limit to specific geofences
device_filtersobjectno{}Filter by device criteria

Template Variables

Signal triggers provide these template variables for use in action configurations:

VariableDescription
{{trigger.signal_type}}Signal type (e.g., dwell, policy_violation)
{{trigger.state}}Signal state (e.g., confirmed, ended)
{{trigger.device.id}}Device identifier
{{trigger.device.name}}Device name
{{trigger.geofence.name}}Geofence name (if applicable)
{{trigger.explanation}}Structured explanation object
{{trigger.reason_codes}}List of machine-readable reason codes
{{trigger.metadata}}Signal metadata (location, thresholds, duration)

Common Patterns

After-Hours Access Alert

Detect when vehicles enter a restricted area outside business hours. Combines a policy violation with a Slack notification.

Policy configuration:

{
"name": "After-hours warehouse access",
"geofence_id": "warehouse-geofence-uuid",
"time_window": {
"days_of_week": [0, 1, 2, 3, 4],
"start_time": "18:00",
"end_time": "07:00",
"timezone": "America/Chicago"
},
"device_filter": {
"device_types": ["vehicle"]
},
"role_filter": null
}

Workflow trigger:

{
"type": "signal",
"signal_types": ["policy_violation"],
"signal_states": ["confirmed"],
"geofence_ids": ["warehouse-geofence-uuid"]
}

Extended Dwell Alert

Alert warehouse operations when a vehicle stays at a loading dock for more than 30 minutes.

{
"name": "Extended Loading Dock Dwell",
"trigger_config": {
"type": "geofence_dwell",
"event_type": "geofence_dwell",
"geofence_ids": ["loading-dock-uuid"],
"dwell_threshold": 1800
},
"steps": [
{
"type": "email",
"name": "Alert operations manager",
"config": {
"integration_id": "int_email456",
"to": ["ops-manager@example.com"],
"subject": "Extended dwell at loading dock",
"body_text": "Vehicle {{trigger.device_id}} has been at {{trigger.geofence_name}} for over 30 minutes ({{trigger.dwell_time}}s)."
}
}
]
}

Multi-Threshold Dwell

Monitor the same geofence with two sensitivity levels by creating two workflows with different dwell_threshold values:

  • Workflow 1 -- dwell_threshold: 300 (5 min) triggers an informational Slack message to #field-updates
  • Workflow 2 -- dwell_threshold: 1800 (30 min) triggers an urgent Slack message to #dispatch-alerts

Both workflows use type: "geofence_dwell" with the same geofence_ids. Each fires independently when its threshold is crossed.

Troubleshooting

Signal Not Firing

  • Check GPS jitter filters: Location updates with accuracy > 100 meters (MAX_ACCURACY_METERS) are dropped. Verify the device is sending high-quality GPS fixes.
  • Check minimum distance: Movements under 25 meters (MIN_DISTANCE_METERS) are filtered out. Stationary devices with GPS drift may not generate new containment checks.
  • Verify device is active: Inactive devices do not process location updates.
  • Verify workflow is active: Draft or paused workflows do not trigger.
  • Check signal_types in trigger config: Ensure the workflow's trigger config includes the correct signal type.

Too Many Signals

  • Increase dwell threshold: Higher thresholds require longer presence, reducing alert volume.
  • Check cooldown period: Each device x geofence x event type combination has a 300-second cooldown (COOLDOWN_SECONDS). Signals cannot re-fire within this window.
  • Review policy time windows: Ensure policies are restricted to the intended hours. A null time window means the policy is always active.
  • Check policy deduplication: The 5-minute dedupe TTL (DEDUPE_TTL = 300) prevents rapid re-triggers after resolution.

Signal Fires but Workflow Does Not Execute

  • Check signal_states in trigger config: The default is ["confirmed"], not "started". If your signal is in the started state, the workflow will not trigger unless you explicitly include "started" in the states list.
  • Check signal_types match: The workflow's signal_types must include the specific signal type being generated.
  • Verify geofence filter: If geofence_ids is set in the trigger config, the signal's geofence must be in that list.

Next Steps

  • Signals -- Understand signal types, lifecycle, and explainability
  • Workflows -- Build automation pipelines triggered by signals
  • Geofences -- Create the spatial boundaries that signals monitor
  • API Reference -- Complete API documentation