Writing Custom Scenarios
Custom scenarios let you reproduce specific real-world failure modes, model your deployment environment, or simulate conditions that aren’t covered by the built-in library. A scenario is a single JSON file — no code required.
Step 1 — Start with a location
Section titled “Step 1 — Start with a location”Every scenario starts at a real-world position. Pick the coordinates of your test environment: a city centre, a warehouse district, an airport approach path, or wherever your app is expected to run.
{ "$schema": "https://sensorchaos.com/schema/scenario/1.0", "name": "My First Scenario", "description": "GPS accuracy degrades, then signal is lost for 30 seconds.", "version": "1.0", "duration_s": 120, "tags": ["gnss", "loss", "navigation"], "baseline": { "location": { "lat": 48.8566, "lng": 2.3522, "accuracy_m": 5, "satellites": 12 }, "update_intervals_ms": { "location": 1000 } }, "timeline": []}Validate it before adding events:
sensorchaos validate my-scenario.jsonStep 2 — Add timeline keyframes
Section titled “Step 2 — Add timeline keyframes”The timeline is a list of sensor states indexed by time. The engine linearly interpolates between keyframes, so you only need to mark the moments that matter — not every second.
Add a normal start, a gradual degradation, a complete outage, and a recovery:
"timeline": [ { "at_s": 0, "location": { "lat": 48.8566, "lng": 2.3522, "accuracy_m": 5, "satellites": 12 }, "note": "Normal fix" }, { "at_s": 20, "location": { "accuracy_m": 40, "satellites": 5 }, "note": "Accuracy degrading" }, { "at_s": 40, "location": { "lat": null, "lng": null, "accuracy_m": null, "satellites": 0 }, "note": "Signal lost" }, { "at_s": 70, "location": { "lat": 48.8566, "lng": 2.3522, "accuracy_m": 200, "satellites": 3 }, "note": "Weak recovery" }, { "at_s": 100, "location": { "lat": 48.8566, "lng": 2.3522, "accuracy_m": 8, "satellites": 11 }, "note": "Full fix restored" }]Key points:
- Partial updates — only include the fields that change.
accuracy_mandsatellitesabove inheritlat/lngfrom the previous keyframe. - Signal loss — set
lat,lng,accuracy_mtonullandsatellitesto0. The app receives no location callbacks during this window. - Interpolation — between
at_s: 0(accuracy 5 m) andat_s: 20(accuracy 40 m), the engine smoothly ramps accuracy on each 1-second tick.
Run it on a connected device:
sensorchaos run ./my-scenario.jsonStep 3 — Add sensor data (multi-sensor scenarios)
Section titled “Step 3 — Add sensor data (multi-sensor scenarios)”For scenarios that also inject IMU, barometer, or magnetometer data, add those fields to the baseline and override them in the timeline. These scenarios require the in-process agent (--agent).
"baseline": { "location": { "lat": 51.5074, "lng": -0.1278, "accuracy_m": 6, "satellites": 10 }, "accelerometer": [0.0, 0.0, 9.81], "gyroscope": [0.0, 0.0, 0.0], "magnetometer": [20.0, -5.0, -44.0], "barometer": [1013.0], "update_intervals_ms": { "location": 1000, "sensors": 50 }}Then override sensors in specific keyframes:
{ "at_s": 45, "location": { "lat": null, "lng": null, "accuracy_m": null, "satellites": 0 }, "accelerometer": [0.3, 0.0, 9.81], "gyroscope": [0.0, 0.0, 0.12], "note": "GPS lost, vehicle turning right — yaw from gyro"}Run with the agent:
sensorchaos run ./my-scenario.json --agentSimulating common failure modes
Section titled “Simulating common failure modes”Gradual position drift (spoofing)
Section titled “Gradual position drift (spoofing)”Increment lat/lng across keyframes while keeping accuracy_m low and satellites high. The falsely confident accuracy is what makes spoofing dangerous.
{ "at_s": 0, "location": { "lat": 25.197, "lng": 55.274, "accuracy_m": 5, "satellites": 12 } },{ "at_s": 60, "location": { "lat": 25.215, "lng": 55.310, "accuracy_m": 6, "satellites": 11 } },{ "at_s": 120, "location": { "lat": 25.380, "lng": 55.520, "accuracy_m": 5, "satellites": 10 } }Accuracy oscillation (multipath / urban canyon)
Section titled “Accuracy oscillation (multipath / urban canyon)”Alternate accuracy between good and bad values across many short keyframes:
{ "at_s": 0, "location": { "accuracy_m": 5, "satellites": 11 } },{ "at_s": 8, "location": { "accuracy_m": 120, "satellites": 6 } },{ "at_s": 16, "location": { "accuracy_m": 8, "satellites": 10 } },{ "at_s": 24, "location": { "accuracy_m": 90, "satellites": 5 } }Repeated signal loss / recovery (jamming)
Section titled “Repeated signal loss / recovery (jamming)”Alternate between null and valid location states:
{ "at_s": 0, "location": { "lat": 59.33, "lng": 18.07, "accuracy_m": 6, "satellites": 9 } },{ "at_s": 20, "location": { "lat": null, "lng": null, "accuracy_m": null, "satellites": 0 } },{ "at_s": 40, "location": { "lat": 59.33, "lng": 18.07, "accuracy_m": 30, "satellites": 4 } },{ "at_s": 60, "location": { "lat": null, "lng": null, "accuracy_m": null, "satellites": 0 } },{ "at_s": 80, "location": { "lat": 59.33, "lng": 18.07, "accuracy_m": 8, "satellites": 9 } }Magnetometer interference
Section titled “Magnetometer interference”Keep GPS fully intact and only corrupt the magnetometer — tests compass-dependent features in isolation:
{ "at_s": 0, "magnetometer": [20.0, -5.0, -44.0] },{ "at_s": 30, "magnetometer": [85.0, 40.0, -20.0] },{ "at_s": 60, "magnetometer": [210.0, 180.0, 90.0] },{ "at_s": 90, "magnetometer": [20.0, -5.0, -44.0] }Using sensorchaos run with CI assertions
Section titled “Using sensorchaos run with CI assertions”Pair your custom scenario with exit-code assertions for automated testing:
sensorchaos run ./my-scenario.json \ --assert-max-position-error-km 0.5 \ --assert-no-crash \ --report report.json \ --exit-code-on-failThe --assert-max-position-error-km flag measures the maximum reported position error relative to the baseline coordinates. If the app correctly rejects spoofed positions, the error stays near zero.
Validating before committing
Section titled “Validating before committing”Always validate custom scenarios before committing them or sharing them with your team:
sensorchaos validate ./my-scenario.jsonFor a full schema reference including all fields and constraints, see Scenario Format.