Geofences
A geofence is a named shape stored on an index, plus one question you can
ask it: is this point inside? Nothing is evaluated automatically - there
are no enter/exit events and no subscription. You call check-fence when
you have a position worth testing, typically right after writing it.
Fences come in two shapes, and the shape decides which fields are required:
circle-center_longitude,center_latitude, and a positiveradius_meters.polygon- averticesarray of at least three{longitude, latitude}points. The ring closes itself; do not repeat the first vertex.
Create and manage
snug geo create-fence --id <index-id> --name downtown \
--shape circle -x -122.4194 -y 37.7749 -r 1500
snug geo create-fence --id <index-id> --name wedge --shape polygon \
--vertices '[{"longitude":-122.45,"latitude":37.70},{"longitude":-122.35,"latitude":37.70},{"longitude":-122.40,"latitude":37.80}]'
snug geo list-fences --id <index-id> --active true --search downtown
snug geo get-fence --id <index-id> --fence-id <fence-id>
snug geo update-fence --id <index-id> --fence-id <fence-id> -r 3000
snug geo delete-fence --id <index-id> --fence-id <fence-id> --forceCreating a circle returns the whole record:
curl -s -X POST -H "Authorization: Bearer $SNUG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"docs4-downtown","description":"Downtown pickup zone","shape":"circle","center_longitude":-122.4194,"center_latitude":37.7749,"radius_meters":1500}' \
"http://localhost:4000/api/v1/geo/$INDEX/fences"{
"status": 201,
"msg": "Created",
"data": {
"id": "ChXdmARRMPnHjSHWxQfm",
"name": "docs4-downtown",
"description": "Downtown pickup zone",
"owner_id": "docs-wave",
"index_id": "XbwKybswsEpjELvHeKxz",
"shape": "circle",
"center_longitude": -122.4194,
"center_latitude": 37.7749,
"radius_meters": 1500.0,
"vertices": [],
"active": true,
"tags": {},
"created_at": 1788007778998,
"updated_at": 1788007778998
}
}Missing geometry is rejected at create time with 400 invalid_fence -
"Circle fence requires a positive radius" or "Polygon fence requires at
least 3 vertices". list-fences accepts the
shared search grammar and is scoped to
one index; a polygon's unused circle fields come back as 0.0, and a
circle's vertices as [].
Checking a point
snug --output json geo check-fence --id <index-id> \
--fence-id <fence-id> -x -122.4194 -y 37.7749{ "fence_id": "ChXdmARRMPnHjSHWxQfm", "inside": true, "distance_meters": 0.0 }For a circle, distance_meters is the great-circle distance from the
fence centre to the point, and inside is exactly
distance_meters <= radius_meters. Checking a point 3.5 km from the
centre of a 3 km circle returns
{"inside": false, "distance_meters": 3500.0946204088477}.
A "check every position I just wrote" loop is the normal pattern, since nothing evaluates fences for you:
snug --output json geo query-radius --id "$INDEX" \
-x -122.4194 -y 37.7749 -r 5000 -d -c \
| jq -r '.[] | "\(.entity_id) \(.longitude) \(.latitude)"' \
| while read -r id lon lat; do
inside=$(snug --output json geo check-fence --id "$INDEX" \
--fence-id "$FENCE" -x "$lon" -y "$lat" | jq -r '.inside')
echo "$id inside=$inside"
doneGotchas
distance_metersis meaningless for a polygon fence. It is always measured from the fence'scenter_*fields, which a polygon never sets, so it is really the distance from (0, 0). A point genuinely inside a polygon in San Francisco reported{"inside": true, "distance_meters": 12799648.694016874}- about 12,800 km, the distance to the Gulf of Guinea. Trustinsidefor polygons and ignore the distance.active: falsedoes not disable a fence. A deactivated fence still answerschecknormally, an inactive circle returnedinside: true. The flag is a filter forlist-fencesand a marker for your own code, nothing more.- The index id in the path is ignored on per-fence routes.
get,update,delete, andcheckresolve the fence byfence_idalone; passing a nonexistent index id in the URL still succeeds. Onlycreateandlistactually validate the index, which also means those two fail with400 index_inactiveon a deactivated index whilecheckkeeps working. - Fences are owned by their creator, not by the index. Another user
hitting your fence gets
403 unauthorized, "Access denied to this geo fence" - the same wall as the index itself. - Deleting the index does not delete its fences. They outlive it,
still readable and checkable by id, but invisible to
list-fences(which needs a live index). Delete fences before the index that owns them, or you lose the only handle you had on them. - Editing geometry is a partial update.
update-fenceleaves omitted fields alone, so you can resize a circle with-r 3000without restating its centre. Changing shape is not supported; create a new fence.
Reference
- Geo API - every endpoint, callable
- Geo overview - indexes, positions, and spatial queries