Skip to main content
The CCTV Mesh layer plots publicly accessible traffic and infrastructure cameras on the map. Camera feeds are stored in a local SQLite database (cctv.db) and refreshed every 10 minutes by the scheduler.
The CCTV Mesh layer is off by default. It is a dense layer — enable it when you want to investigate a specific city or region.

Sources

Four official public data sources are ingested automatically:
SourceAgencyCoverageRefresh rateAPI key
TfL JamCamsTransport for LondonLondon, UK10 minNo
TxDOT / Austin MobilityAustin, TX TxDOTAustin, TX, US10 minNo
NYC DOTNew York City DOTNew York City, US10 minNo
Singapore LTALand Transport AuthoritySingapore10 minYes (LTA_ACCOUNT_KEY)

TfL JamCams (London)

Fetches from https://api.tfl.gov.uk/Place/Type/JamCam. Each camera returns a videoUrl (preferred) or imageUrl for the live feed, plus the camera’s street-level commonName for location context. TfL JamCams refresh at 15-second intervals.

Austin TxDOT

Fetches from the City of Austin Open Data portal (data.austintexas.gov) with a limit of 2,000 records. Live images are served at https://cctv.austinmobility.io/image/{cam_id}.jpg.

NYC DOT

Fetches from https://webcams.nyctmc.org/api/cameras. Live images are served at https://webcams.nyctmc.org/api/cameras/{cam_id}/image. NYC DOT cameras refresh at 30-second intervals.

Singapore LTA

Fetches from https://api.data.gov.sg/v1/transport/traffic-images. Camera IDs are prefixed SGP-. Requires an LTA_ACCOUNT_KEY environment variable. Singapore LTA cameras refresh every 60 seconds.

Custom URL ingestion

In addition to the four official sources, ShadowBroker supports ingestion of custom camera URLs. Any URL pointing to a compatible feed type can be added and will appear on the map.

Feed rendering

The frontend automatically detects the correct rendering method for each camera URL:
Media typeDetection ruleRendering method
videoURL ends with .mp4, .webm, or .oggHTML <video> element
mjpegURL contains .mjpg, .mjpeg, or axis-cgi/mjpgMJPEG stream via <img>
hlsURL contains .m3u8 or hlsHLS player
embedURL contains embed, maps/embed, or iframe<iframe> embed
satelliteURL contains mapbox.com or satelliteSatellite tile render
imageAll other URLsStatic <img> refreshed on interval
Type detection runs at query time in _detect_media_type() and is stored alongside each camera record.

Database schema

Cameras are stored in a SQLite database at backend/cctv.db:
CREATE TABLE cameras (
    id                    TEXT PRIMARY KEY,
    source_agency         TEXT,
    lat                   REAL,
    lon                   REAL,
    direction_facing      TEXT,
    media_url             TEXT,
    refresh_rate_seconds  INTEGER,
    last_updated          TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Camera IDs are namespaced by source: TFL-{id}, ATX-{id}, NYC-{id}, SGP-{id}.

Map display

Cameras are displayed as green dot markers that cluster at low zoom levels with count labels. Clicking a cluster zooms the map to decluster. Clicking an individual camera marker opens the live feed in the SIGINT panel.

Build docs developers (and LLMs) love