Skip to main content

tracelines

Extract the blue lines, never the circles.

Turn an area into GeoJSON polylines of continuous official street-level coverage — the solid blue Street View lines — while rigorously excluding user photospheres / photopets (the dots). Multi-source: Google (via streetlevel), Mapillary, and KartaView, fused onto one map.

CI PyPI Python License: AGPL v3 Docs GUI

🗺️ Live GUI · 📖 Documentation · 🔬 How the HARD RULE works · ✅ Reproduce the verification


Disclaimer. Research / educational tool, provided as-is, without warranty. The Google provider relies on undocumented internal endpoints (via streetlevel) that may break without notice. You are responsible for complying with each data source's Terms of Service and your local law. Respect rate limits — don't hammer the endpoints. Not affiliated with or endorsed by Google, Meta/Mapillary, or KartaView.

The HARD RULE

Output contains only genuine official Google car Street View coverage — never a user photosphere / photopet / photo-path, even a Google-hosted one.

Enforced in three defense-in-depth layers (each verified — see the filter contract and verification):

Layer Guard Stops
0 — Source Nodes come only from the z17 get_coverage_tile layer; never search_third_party. Photospheres are structurally absent there. Verified: 7,433 / 7,433 tile panos official (2026-07-13 snapshot; the count drifts as Google updates coverage, the 0-leak invariant does not — re-check with scripts/verify_hardrule.py).
1 — ID whitelist is_official_panoid(): 22 chars, 16-byte decode, terminal ∈ {A,Q,g,w}, not CIHM/CIAB/AF1Q. Legacy 22-char photospheres + the new CIAB UGC scheme. Verified: 753/753 official accepted, 3/3 photospheres rejected.
2 — Source allowlist (--precision) source == 'launch' (car), fetched per-pano. Trekker (scout), indoor (innerspace), every photos:* upload.

Honest caveat: launch is the road-snapped layer Google draws as solid blue lines; Google's own metadata says launch is "sometimes trekker" and scout is "sometimes car" — so no field perfectly separates car from trekker. That fuzz is orthogonal to the photosphere exclusion, which is airtight.

Install

pip install tracelines            # Google-capable out of the box (no API key)
pip install "tracelines[mapillary]"   # + Mapillary vector-tile source
pip install "tracelines[all]"     # + Mapillary + OSM road-snapping

Optional env vars: MAPILLARY_TOKEN (free, for the Mapillary source); MAPS_API_TOKEN (optional Google metadata enrichment — not required).

Quickstart

# Nearest official car coverage to a point (never a photosphere)
tracelines nearest 44.435072 26.050430

# Extract blue lines over an area -> GeoJSON
tracelines extract --area bucharest-city --sources google --out bucharest.geojson
tracelines extract --bbox 26.09,44.45,26.11,44.46 --sources google,mapillary --out out.geojson

# Pure car only (drops trekker/indoor; slower, one metadata call per pano)
tracelines extract --area bucharest-city --sources google --precision --out cars.geojson

# Density probe: covered km / segments / median year per source
tracelines probe --bbox 26.09,44.45,26.11,44.46 --sources google,mapillary
from tracelines import Settings, AREAS
from tracelines.pipeline import extract
from tracelines.export import write_geojson, summary_stats

segments, meta = extract(AREAS["bucharest-city"], ["google"], Settings())
write_geojson(segments, "bucharest.geojson")
print(summary_stats(segments))

The GUI

A static cockpit on GitHub Pages — because the Google extraction can't run in a browser (undocumented, CORS-blocked, Python-only), the page is a control surface, not the engine:

  • View any GeoJSON the CLI produced (drag & drop) on an interactive map.
  • Build a command — draw a bbox, copy the exact tracelines extract … command.
  • Live Mapillary overlay (paste your own free token — stored only in your browser).
  • Live Google works out-of-the-box via a shared hosted demo proxy — or run your own free.
  • Diff sources — where does Google have coverage Mapillary lacks, and vice-versa.

Deploy your own proxy (free)

The GUI ships pointed at a shared hosted demo proxy (Google Cloud Run) so Live Google works immediately. It's hardened (tiny bbox cap, per-IP rate limit) and may sleep or hit limits — for real use, run your own. A public Google-extraction proxy is an open relay (CORS doesn't stop curl), so keep the hardening env tight and treat it as best-effort, not a service.

Host Free? How
Render (recommended) ✅ no card Deploy to Render — one click; uses render.yaml
Docker anywhere — docker build -t tracelines-proxy . && docker run -p 8000:8000 -e TRACELINES_CORS_ORIGINS="https://<you>.github.io" tracelines-proxy
Google Cloud Run ✅ free tier gcloud run deploy tracelines-proxy --source . --allow-unauthenticated --max-instances 1
Hugging Face Space ⚠️ needs HF PRO now files in spaces/

Then paste your URL into the GUI's Proxy tab. Hardening knobs: TRACELINES_MAX_BBOX_DEG2, TRACELINES_RATE_PER_MIN, TRACELINES_CORS_ORIGINS, and the kill switch TRACELINES_DISABLED=1.

Sources & what you may do with the output

Source Live in browser? Output license
Google (streetlevel) ❌ (CLI or self-hosted proxy) No redistribution license — generate for yourself (details)
Mapillary ✅ (your token) CC-BY-SA 4.0 (attribute + share-alike)
KartaView ✅ best-effort CC-BY-SA 4.0 (attribute + share-alike)

See DATA_LICENSES.md — the AGPL license covers the code, not the data you extract.

How it works

bbox → z17 tile enumerate → async fetch (cached, concurrent)
     → Layer-1 official-id whitelist → panoid graph (links = edges)
     → [--precision] source=='launch' allowlist
     → shapely line_merge (splits at junctions) → CoverageSegments
   Mapillary sequence tiles ─┐
   KartaView bbox polylines ─┴→ fuse (union + provenance) → GeoJSON

Full internals: Architecture.

Documentation

Development

pip install -e ".[dev]"
pytest                 # hermetic tests (no network)
pytest -m network      # live tests (hit Google/Mapillary)
ruff check tracelines tests
python scripts/verify_hardrule.py    # re-run the HARD-RULE sweep

Acknowledgements

  • streetlevel by sk-zk — the MIT library this stands on; it does the actual Google coverage-tile walking.
  • matdoes.dev Street View / pano-id write-ups — invaluable for the id taxonomy.
  • Mapillary and KartaView for open, documented street-level APIs.

License

AGPL-3.0-or-later — see LICENSE. If you run a modified version as a network service (e.g. the proxy backend), the AGPL requires you to share your source. Third-party notices in THIRD_PARTY_LICENSES.md.

Metadata

Release files for tracelines 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tracelines 0.2.0
File Size Uploaded Provenance Actions
tracelines-0.2.0.tar.gz 53.5 kB Without provenance Details for tracelines-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for tracelines 0.2.0
File Interpreter ABI Platform Actions
tracelines-0.2.0-py3-none-any.whl Python 3 none any Details for tracelines-0.2.0-py3-none-any.whl

Total release size: 104.0 kB

Release files / tracelines-0.2.0.tar.gz

Download URL tracelines-0.2.0.tar.gz
Size 53.5 kB
Tags Source
SHA-256 checksum
How to use checksums
0cf9fc381325d8bba9eb0e0a80c1aabb9a48149c937e237dca5b28ed41e293e9
BLAKE2b-256 checksum
How to use checksums
1eec7ed5525d53d7716177eb68628195f398ed7cdcb8ee56c852685a7c9f4a8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Release files / tracelines-0.2.0-py3-none-any.whl

Download URL tracelines-0.2.0-py3-none-any.whl
Size 50.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3961bc7ae299f704008e8eb9f09b07ac6196aebe6e224b07f626542fe4e325c1
BLAKE2b-256 checksum
How to use checksums
84eab3e07a506b30d9dea6c4387664fee539fc5dc61aeb6e0d0ce2fb1a45cd70
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Security for tracelines 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page