gpx-poi-enricher
CLI tools and apps for finding OpenStreetMap POIs along a track or around a Google Maps place.
Table of Contents
- The Pipeline
- Features
- Installation
- Quick Start
- GUI
- Environment variables
- Command: maps-to-gpx
- Command: gpx-split-waypoints
- Command: gpx-poi-enricher
- Built-in Profiles
- POI catalog
- Creating Custom Profiles
- How It Works
- Data Attribution
- Contributing
- License
The Pipeline
Google Maps directions ── maps-to-gpx ── routed GPX ─┐
├─ gpx-poi-enricher ── POI waypoints
Track GPX ──────────────────────────────────────────┤
Google Maps place / coordinates ────────────────────┘
│
▼
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 viaOSRM_BASE_URLor--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 or around a point; 10 curated YAML profiles plus a POI catalog (~95 common types);--quickfor sparse smoke tests.- GUI (
gpx-poi-enricher-gui) — Easy: route or point → GPX + POIs; Expert: track or point search; Profiles: add POI types from the built-in catalog. - Android app — Easy and POI Enricher support point/Maps link searches.
- Country-aware
terms(DE,FR,ES,EN); Overpass mirrors with retries; per-profile defaults overridable on the CLI; custom YAML viaGPX_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.
macOS app bundle (Finder/Dock icon, double-click): after uv sync --extra gui, run
uv run python scripts/build_macos_app.py → dist/GPX POI Enricher.app. Drag to Applications or
Dock. Rebuild after upgrading the package in .venv.
Easy — choose Route for Maps directions → GPX(s) + POIs, or Point for coordinates/a Maps place link → POI-only GPX. Point radius comes from the profile. Route mode also supports alternates, detours, and milestones. Progress log + file list; cancel after the current 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. POI Enricher accepts a track GPX or a point/Maps link. 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 or point in → waypoints-only POI GPX out. A point may be LAT,LON or a Google Maps
place link. Run gpx-poi-enricher --help for all flags.
--profile— required unless--list-profiles--max-km— max distance from track, or radius around a point--sample-km— sampling step along a track (unused for a point)--output— output GPX path with--point--batch-size— sample points per Overpass request--country-sample-km— spacing between track country lookups (default 40; 500 with--quick)--point—LAT,LONor a Google Maps place link; pair with--output--progress-interval— stderr progress in seconds (0off; default5)--verbose— verbose Overpass error bodies (track searches only)--list-profiles— list profiles and defaults, then exit--quick— sparse track defaults and a 1 km radius (including point searches), unless overridden
gpx-poi-enricher route.gpx camping.gpx --profile camping
gpx-poi-enricher route.gpx playgrounds.gpx --profile playground --max-km 5
gpx-poi-enricher --point '52.038993,13.748653' --output aquariums.gpx --profile aquarium
gpx-poi-enricher --point 'https://maps.app.goo.gl/JDocHptvdByZ1WZSA' \
--output aquariums.gpx --profile aquarium
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
tagsfrom the catalog entry defaultsfrom 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.17.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gpx_poi_enricher-1.17.0.tar.gz | 712.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gpx_poi_enricher-1.17.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 782.2 kB
Release files / gpx_poi_enricher-1.17.0.tar.gz
| Download URL | gpx_poi_enricher-1.17.0.tar.gz |
|---|---|
| Size | 712.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
27ac833156c1c4c2409ec074c9d8b0b37baac3857ef6a7313c4c01c36fd32a5c
|
|
BLAKE2b-256 checksum How to use checksums |
562690a4ffd8f5f7ca6dc75d53ebfd8d314c353b81568c50f03dcd05ca5e23be
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 7, 2026.
Transparency logRelease files / gpx_poi_enricher-1.17.0-py3-none-any.whl
| Download URL | gpx_poi_enricher-1.17.0-py3-none-any.whl |
|---|---|
| Size | 69.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7f9b365c40f53e68b0d0df51abf05faa272bc4a96dd0258e513cb57323fd0513
|
|
BLAKE2b-256 checksum How to use checksums |
1e240412f377256c1db9dd783444599ca2b03f0eb6591ab7aff81da96a55e8aa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 7, 2026.
Transparency log