Skip to main content

gpx-poi-enricher

CLI tools and a desktop GUI for turning Google Maps directions into routed GPX tracks and POI waypoint files.

CI Python 3.10+ License: MIT PyPI


Table of Contents


The Pipeline

Google Maps URL
      │
      ▼
 maps-to-gpx          ← directions URL → routed GPX track
      │
      ▼
gpx-split-waypoints   ← optional: evenly-spaced split markers
      │
      ▼
gpx-poi-enricher      ← OpenStreetMap POIs along the track
      │
      ▼
 waypoints.gpx        ← Garmin / OsmAnd / Google My Maps <https://www.google.com/mymaps>

All three commands install together and can be run alone or chained. Split and POI output are waypoints-only GPX (no <trk>) — import alongside the route file or merge externally. Files

5 MB? Try https://www.gpxtokml.com/.


Features

  • maps-to-gpx — Google Maps URL (incl. maps.app.goo.gl) → routed GPX via Nominatim + public OSRM; custom base URL via OSRM_BASE_URL or --osrm-base-url. No API keys for defaults.
  • gpx-split-waypoints — evenly spaced split <wpt> markers for waypoint-limited apps.
  • gpx-poi-enricher — OSM POIs along a track; 10 curated YAML profiles plus a POI catalog (~95 common types); --quick for sparse smoke tests.
  • GUI (gpx-poi-enricher-gui) — Easy: URL → GPX(s) → POIs; Expert: CLI tools in tabs; Profiles: add POI types from the built-in catalog.
  • Country-aware terms (DE, FR, ES, EN); Overpass mirrors with retries; per-profile defaults overridable on the CLI; custom YAML via GPX_POI_PROFILES_DIR.

Installation

Python 3.10+. Use an isolated install — system Python is often externally managed on Linux. Recommended: venv + pip:

python3 -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install gpx-poi-enricher              # CLI
pip install "gpx-poi-enricher[gui]"       # CLI + PyQt6 GUI

Alternatives: pipx install "gpx-poi-enricher[gui]" (no activate); or uv tool install "gpx-poi-enricher[gui]" with uv.

Development

git clone https://github.com/devmarkusb/gpx-poi-enricher.git && cd gpx-poi-enricher
uv sync --extra dev --extra gui   # .venv + editable install (matches CI)
./scripts/setup-pre-commit.sh
uv run pytest                     # uv run <cmd> works without activating .venv

Without uv: venv + pip install -e ".[dev,gui]". See CONTRIBUTING.md.


Quick Start

Google Maps URL → campsite waypoints:

maps-to-gpx "https://www.google.com/maps/dir/Paris/Lyon/Barcelona/" route.gpx
gpx-split-waypoints route.gpx route-split.gpx 10    # optional split markers
gpx-poi-enricher route.gpx camping.gpx --profile camping

GUI

gpx-poi-enricher-gui          # requires [gui] extra — see Installation
gpx-poi-enricher-gui --quick  # sparse enrichment ([quick] in title bar)

From a clone: uv run gpx-poi-enricher-gui.

Easy — one primary Maps URL (required), optional extra URLs per line → routed GPX(s), optional alternate/detour GPX files, then POI enrichment. Progress log + file list; cancel after current Overpass batch.

Expert — POI Enricher, Split Waypoints, Maps → GPX, and Profiles tabs (same CLIs; Maps tab supports multiple URLs like Easy). Profiles → Add from catalog… adds common OSM POI types (museums, pharmacies, viewpoints, …) as editable user profiles. Long-running work is off the UI thread.


Environment variables

GPX_POI_PROFILES_DIR — existing directory of *.yaml replaces built-in profiles.

OSRM_BASE_URL — OSRM root ending in /route/v1 for maps-to-gpx (override with --osrm-base-url).


Command: maps-to-gpx

One Google Maps directions URL → routed GPX (<trk> + stopover <wpt>). Short links, path-style (/maps/dir/A/B/C), and query-style (?api=1&origin=…) URLs. Names → Nominatim; routing → public OSRM or your own stack. Multiple routes/detours: use the GUI.

Run maps-to-gpx --help for --mode, --name, --osrm-base-url.

maps-to-gpx "https://www.google.com/maps/dir/Paris/Lyon/Marseille/" route.gpx
maps-to-gpx "https://maps.app.goo.gl/ABC123" route.gpx
maps-to-gpx "https://www.google.com/maps/dir/Amsterdam/Utrecht/" route.gpx --mode cycling
maps-to-gpx "https://www.google.com/maps/dir/A/B/" route.gpx \
  --osrm-base-url "https://my-osrm.example.com/route/v1"   # must end with /route/v1

Command: gpx-split-waypoints

Track → segments − 1 evenly spaced waypoints (Split 1, …); description holds track position (e.g. 10.0% of track length). Waypoints only — companion file, not the original track. segments >= 2.

gpx-split-waypoints route.gpx route-split.gpx       # 10 segments → 9 waypoints (default)
gpx-split-waypoints route.gpx route-split.gpx 5   # 5 segments → 4 waypoints

Command: gpx-poi-enricher

Track GPX in → waypoints-only POI GPX out. Run gpx-poi-enricher --help for all flags.

  • --profile — required unless --list-profiles
  • --max-km — max distance from track to keep a POI
  • --sample-km — sampling step along the track
  • --batch-size — sample points per Overpass request
  • --country-sample-km — Nominatim spacing for country detection (default 40; 500 with --quick)
  • --progress-interval — stderr progress in seconds (0 off; default 5)
  • --verbose — verbose Overpass error bodies
  • --list-profiles — list profiles and defaults, then exit
  • --quick — sparse defaults (~500 km sample/country, 1 km radius) unless overrides are set
gpx-poi-enricher route.gpx camping.gpx --profile camping
gpx-poi-enricher route.gpx playgrounds.gpx --profile playground --max-km 5
gpx-poi-enricher --list-profiles
gpx-poi-enricher route.gpx probe.gpx --profile camping --quick

Built-in Profiles

From profiles/. gpx-poi-enricher --list-profiles shows sample_km, batch_size, retries.

Profile Description (YAML) Default max_km
camping Campsite 10.0
playground Playground 3.0
outdoor_pool Outdoor Pool, Adventure Pool, Thermal Bath 10.0
beach Swimming Lake, Beach 20.0
theme_park Theme Park 12.0
zoo Zoo, Petting Zoo 12.0
aquarium Aquarium 15.0
mcdonalds McDonalds 5.0
restaurant Restaurant 2.0
kids_activities Children's Activities of All Kinds 15.0

kids_activities matches mainly via terms (regex on OSM name / description / operator); most others use tags, optionally plus terms.


POI catalog

Besides the curated built-ins above, the app ships a catalog of ~95 common OSM POI types (restaurants, museums, pharmacies, viewpoints, …) in src/gpx_poi_enricher/data/poi_catalog.yaml.

Desktop GUI: Expert → Profiles → Add from catalog… — searchable list by category. Android: Profiles tab → Add from catalog…

Choosing an entry writes a user profile YAML with:

  • OSM tags from the catalog entry
  • defaults from a preset bucket (urban_dense, regional_sparse, …) — e.g. tight radius for shops, wider radius for zoos
  • empty terms (tag-only search; edit later if you need name matching)

If the profile id already exists (e.g. built-in aquarium), saving from the catalog creates a user override with the same id. You can edit radius, symbols, or add terms afterward.

Programmatic use:

from gpx_poi_enricher.poi_catalog import save_catalog_entry

save_catalog_entry("museum")  # writes ~/.config/gpx-poi-enricher/profiles/museum.yaml (desktop)

Creating Custom Profiles

Easiest: use Add from catalog… in the GUI (see POI catalog) for standard OSM types, then edit the generated YAML if needed.

Manual: add a YAML file; id or filename (without .yaml) is the profile id. With PyPI installs, set GPX_POI_PROFILES_DIR to use only your profiles.

# profiles/my_profile.yaml
id: my_profile
description: "My custom POI type"
symbol: Flag, Blue          # Garmin symbol in output GPX

defaults:
  max_km: 8.0
  sample_km: 4.0
  batch_size: 5
  retries: 3

tags:                       # any tag line can match
  - key: tourism
    value: museum
  - key: amenity
    value: fast_food
    and:
      key: cuisine
      value: pizza

terms:                      # regex selectors (per country + EN)
  DE: ["Museum", "Schloss"]
  FR: ["musée", "château"]
  ES: ["museo", "castillo"]
  EN: ["museum", "castle"]

Need non-empty tags or terms for the current country plus EN (else query build fails). defaults keys are overridable on the CLI.


How It Works

maps-to-gpx: expand short URLs → parse path/query (geocode names, keep coords) → OSRM route → GPX <trk> + stopover <wpt>.

POI enrichment: sample every sample_km → reverse-geocode country every country_sample_km → Overpass per batch (tags = typed selectors; terms = regex on name/description/operator within max_km) → dedupe by OSM id → <wpt> only. Mirrors rotate; retries on failure.


Data Attribution

Map data © OpenStreetMap contributors — ODbL. Nominatim — OSM Foundation. Routing — OSRM public demo (ODbL).

Usage policies: Nominatim ~1 req/s + meaningful User-Agent (this project sends one); Overpass — no bulk scraping; OSRM demo — personal/non-commercial; use OSRM_BASE_URL / --osrm-base-url for heavy use.


Contributing

See CONTRIBUTING.md. Issues: GitHub.


License

MIT — LICENSE.

Metadata

Release files for gpx-poi-enricher 1.10.1

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

Source distribution (sdist)

Source distribution for gpx-poi-enricher 1.10.1
File Size Uploaded
gpx_poi_enricher-1.10.1.tar.gz 691.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gpx-poi-enricher 1.10.1
File Interpreter ABI Platform
gpx_poi_enricher-1.10.1-py3-none-any.whl Python 3 none any Details

Total release size: 749.1 kB

Release files / gpx_poi_enricher-1.10.1.tar.gz

Download URL gpx_poi_enricher-1.10.1.tar.gz
Size 691.1 kB
Tags Source
SHA-256 checksum
How to use checksums
fe3fd9cb4e522af392224902b9d22b1290d4ba56c572633c53f286efef86f596
BLAKE2b-256 checksum
How to use checksums
46961e4405ccab446249c00cf32eed5e7d47b0a9dcfd0cca82ac539ac6801c1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 11, 2026.

Transparency log

Release files / gpx_poi_enricher-1.10.1-py3-none-any.whl

Download URL gpx_poi_enricher-1.10.1-py3-none-any.whl
Size 58.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
40223906a2a57841d4756fce8d2880564332a414dc1cd613dbdf6d098bcb6f54
BLAKE2b-256 checksum
How to use checksums
9b3446267153efd759dc1b88296bf706b66e2b683f0a8d54830119af56e87940
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 11, 2026.

Transparency log

Release history Release notifications | RSS feed

1.15.0

2 release files

1.14.0

2 release files

1.13.0

2 release files

1.12.1

2 release files

1.12.0

2 release files

1.11.2

2 release files

1.11.1

2 release files

1.11.0

2 release files

This release

1.10.1 This release

2 release files

1.10.0

2 release files

1.9.0

2 release files

1.8.1

2 release files

1.8.0

2 release files

1.7.1

2 release files

1.7.0

2 release files

1.6.2

2 release files

1.6.1

2 release files

1.6.0

2 release files

1.5.7

2 release files

1.5.6

2 release files

1.5.5

2 release files

1.5.4

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.2

2 release files

0.1.0

2 release files

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