Recipe: perimeter intrusion detection with evidence and alerts
Draw zones on a camera, arm them on a night schedule, and get a signed webhook plus snapshot and clip evidence the moment a person steps in. A full self-hosted intrusion pipeline.
Why perimeter detection
A motion sensor cannot tell a person from a cat, and a cloud camera service sends your footage to someone else's servers. The Perimeter Studio App watches your own camera for people inside zones you define, only while it is armed, and delivers evidence to a webhook you control. It is the difference between "something moved" and "a person entered the loading dock at 02:14, here is the snapshot and a ten-second clip".
Architecture in words
Perimeter is a Studio App with a Python worker (YOLOv8 person detection over the app's HLS). You define zones as normalized rectangles or polygons, an arming schedule, and a callback URL. When a person's foot-point lands inside an armed zone, the worker writes a snapshot JPEG and an optional short clip to disk, records the alert in a per-app perimeter.db, POSTs a signed perimeter.intrusion event to your webhook, and pushes it to the dashboard's live panel.
1. Install and point it at a camera
export BASE="https://your-server.example.com/api/v1"
export TOKEN="sk_...."
curl -X POST $BASE/apps/security/plugins/perimeter/install -H "Authorization: Bearer $TOKEN"
curl -X PATCH $BASE/apps/security/plugins/perimeter -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"enabled": true,
"config": {
"room": "cam-dock",
"zones": "[{\"id\":\"gate\",\"rect\":[0.6,0.4,0.35,0.55]}]",
"callbackUrl": "https://alerts.example.com/hooks/perimeter",
"callbackSecret": "a-long-shared-secret"
}
}'
room and at least one zone are required. Zones are JSON, normalized 0–1: a rect is [x, y, width, height]; polygons take points.
2. Set the arming schedule
The key config knobs (with their defaults):
armMode—schedule(default), orarmed/disarmedto override manually.armSchedule—"22:00-06:00"by default; aHH:MM-HH:MMwindow in local time that wraps past midnight.armWeekends—true; arms all day Saturday and Sunday on top of the daily window.timezone— an IANA name; empty uses host local time.confidence—0.5;fps—1;cooldown—60seconds per zone;clipSeconds—10(0 disables the clip);anchor—foot;model—nano(orsmall).
So a warehouse armed nightly and all weekend is just armMode: schedule, armSchedule: "20:00-07:00", armWeekends: true, timezone: "America/Argentina/Buenos_Aires".
3. Verify the notify chain
Each intrusion POSTs to your callbackUrl:
{ "event": "perimeter.intrusion", "app": "security", "room": "cam-dock",
"ts": 1751000000.42, "zone": "gate", "confidence": 0.88,
"snapshot": "…/evidence/20260709-233015-482-gate.jpg", "clip": "…-gate.mp4" }
When callbackSecret is set, the body is signed with X-StreamHub-Signature: sha256=<hex> (HMAC-SHA256) — verify it exactly as you would a StreamHub webhook. From there, fan out to email, Slack or a siren however you like.
4. Read alerts in the dashboard
The Perimeter app-tab reads the authenticated live channel, GET /apps/security/plugins/perimeter/live/state, which streams the current armed state, live person boxes, and recent alerts (with base64 thumbnails). To acknowledge alerts up to a point, PATCH the config field ackThrough to that alert's timestamp — everything at or before it flips to acknowledged.
What you should see
While disarmed, nothing fires. Inside the armed window, walking into the gate zone produces a webhook within about a second, an entry in the app-tab alert list with a thumbnail, and a snapshot (plus a ~10s clip) under apps/security/perimeter/evidence/.
Troubleshooting
- No alerts at all — check you are inside the armed window (or set
armMode: armedto test now), and thatroomplus at least one zone are set. - Snapshot but no clip — the
-c copyclip is cut from the local on-disk HLS. A worker reading HLS over HTTP (a remote edge node) records snapshot-only; run co-located for clips. - Too many alerts — raise
confidence, shrink the zone, or increasecooldown. - CPU high — this is real detection: budget roughly 0.5–1 CPU core and ~1.5–2 GB RAM per watched room at 1–2 fps. Drop
fpsor use a GPU (cuda: true) for more.
Closing
The whole pipeline — model, evidence, database, alerts — runs on your hardware, and the footage never leaves it. If you need multi-camera arming, a guard-facing alert console, or integration with an existing NVR or SOC, our team builds those on top of the open-source Perimeter app.