Contribute to SparrowMap

Feed sightings from your own device using two endpoints. Your compute stays yours. Video never leaves your machine.

🔒 What actually goes up

SparrowMap never accepts video. A contribution is a small, plate-illegible crop plus a position, and nothing else. Our side runs the classifier and a person confirms it before anything appears on the map. Only government and emergency vehicles are ever published; private vehicles are dropped.

So you send crops, we decide. You never send raw footage, and you never publish a claim directly.

The two endpoints

Base URL: https://map.sparrowmap.com

  1. Enroll once to register your device and get a token.
  2. Post a sighting for each vehicle you detect, using that token.

1 · Enroll — POST /api/enroll

Send a name and a rough starting position. For anything that moves (a dashcam, a car, a phone), set "kind": "mobile". A fixed camera can omit it.

curl -X POST https://map.sparrowmap.com/api/enroll \
  -H "Content-Type: application/json" \
  -d '{"name":"My Pi node","lat":XX.XXXX,"lon":-YY.YYYY,"kind":"mobile","contact":"your handle or email"}'

Response (the token is shown once — save it):

{ "id": "n_1a2b3c4d", "status": "active", "token": "KEEP-THIS-SECRET",
  "review_url": "/rv", "review_token": "…" }

review_url + review_token let you review your own device's catches at /rv. Replace XX.XXXX / -YY.YYYY with your real latitude and longitude.

2 · Post a sighting — POST /api/sightings

Send the token in the Authorization header. Include a sub-resolution crop and where the vehicle sits in it. For a moving node, include the live GPS on every sighting.

curl -X POST https://map.sparrowmap.com/api/sightings \
  -H "Authorization: Bearer KEEP-THIS-SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "node_id": "n_1a2b3c4d",
    "ts": 1700000000,
    "lat": XX.XXXX, "lon": -YY.YYYY,
    "source": "phone_node",
    "snap_b64": "data:image/jpeg;base64,/9j/4AAQ…",
    "vehicle_box": [x1, y1, x2, y2],
    "body": "car"
  }'

Python

import base64, json, time, requests

with open("crop.jpg", "rb") as f:
    b64 = "data:image/jpeg;base64," + base64.b64encode(f.read()).decode()

requests.post("https://map.sparrowmap.com/api/sightings",
  headers={"Authorization": "Bearer KEEP-THIS-SECRET"},
  json={
    "node_id": "n_1a2b3c4d",
    "ts": time.time(),
    "lat": XX.XXXX, "lon": -YY.YYYY,   # live GPS, per sighting
    "source": "phone_node",
    "snap_b64": b64,
    "vehicle_box": [x1, y1, x2, y2],
    "body": "car",
  })

Fields

FieldWhat it is
node_idrequiredThe id you got from /api/enroll.
snap_b64requiredA sub-resolution, plate-illegible crop as a data:image/jpeg;base64,… string. Keep it small (a couple hundred px of vehicle). Never full-res, never video.
vehicle_boxrequired[x1,y1,x2,y2] pixel box of the vehicle in the crop, so the server crops to the vehicle and not the street.
lat, lonrequired if mobileThe live GPS for this sighting. A fixed camera can omit these (it uses its watched span). A moving node must send them, or every dot pins to the enrol point.
tsoptionalUnix time of the sighting. Defaults to now.
sourceoptionalUse "phone_node" for a remote contributor: the crop is parked so our classifier scores it and a human reviews before publish.
bodyoptionalYour guess at the vehicle type ("car", "truck"…). A hint only; the classifier decides.
headingoptionalDirection the vehicle was travelling, degrees.
plate_text / plate_confoptionalOnly if you read a plate. Weak reads are dropped; the crop still counts.

⚠️ Good to know

📡 No camera? Help test the RF scanner BETA

We're building a scanner that finds surveillance cameras (Flock/ALPR) by the wifi they broadcast — no camera needed, just an Android phone or a Raspberry Pi. Same privacy rule: only surveillance devices leave your device, everything private is dropped at the edge.

Join the RF beta →

Compute stays on your device, video never leaves it, and only public government vehicles are ever published. That is the whole point of SparrowMap.