Enrich GPX tracks with Points of Interest from OpenStreetMap via configurable YAML profiles
Project description
gpx-poi-enricher
CLI tools and a desktop GUI for turning Google Maps directions into routed GPX tracks and POI waypoint files.
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
- Creating Custom Profiles
- How It Works
- Data Attribution
- Contributing
- License
The Pipeline
Google Maps URL
│
▼
maps-to-gpx ← converts a directions URL to a routed GPX track
│
▼
gpx-split-waypoints ← optional: extract evenly-spaced split markers (see below)
│
▼
gpx-poi-enricher ← queries OpenStreetMap for POIs along the track
│
▼
waypoints.gpx ← import into Garmin / OsmAnd / Google My Maps <https://www.google.com/mymaps>
All three commands are installed together and can be run alone or chained.
Split and POI steps each write waypoints-only GPX files (no <trk>). Import both the route file
and those waypoints in your app, or merge them externally if needed.
If a result file is too large (>5 MB) for your consumer app, https://www.gpxtokml.com/ can help shrink it.
Features
maps-to-gpx: Google Maps directions URL (including shortmaps.app.goo.gllinks) → routed GPX. Place-name stopovers via Nominatim; routing via the public OSRM API. Optional custom OSRM base URL orOSRM_BASE_URLenv. No Google or OSRM API key required for the defaults.gpx-split-waypoints: read a track from an input GPX and write only evenly spaced split<wpt>markers (Split 1, …) for apps that limit imported waypoints.gpx-poi-enricher: enrich a GPX track with OpenStreetMap POIs using 11 built-in YAML profiles (camping, beaches, playgrounds, theme parks, restaurants, etc.).--quicksmoke-test mode for fast, sparse sampling.- GUI (
gpx-poi-enricher-gui): Easy mode runs Maps URL → routed GPX(s) → POI enrichment in one flow; Expert exposes the enricher, split, and Maps→GPX tools as separate tabs. Optional--quickflag for both modes. - Country-aware
terms(DE,FR,ES,EN): reverse-geocoding along the route picks a country so queries can use localized strings where profiles define them. - Overpass queries use several public endpoints with retries.
- Profiles: per-profile defaults for radius, sampling, batch size, and retries; everything can be
overridden on the CLI. Custom profiles via YAML and optional
GPX_POI_PROFILES_DIR.
Installation
From PyPI (recommended)
pip install gpx-poi-enricher # CLI tools only
pip install "gpx-poi-enricher[gui]" # CLI + desktop GUI (PyQt6)
From source (development)
git clone https://github.com/devmarkusb/gpx-poi-enricher.git
cd gpx-poi-enricher
pip install -e ".[dev,gui]"
./scripts/setup-pre-commit.sh
Quick Start
Google Maps URL → campsite waypoints:
# Step 1: directions link → routed GPX (track + stopover waypoints)
maps-to-gpx "https://www.google.com/maps/dir/Paris/Lyon/Barcelona/" route.gpx
# Step 2 (optional): split markers only → route-split.gpx (import alongside route.gpx)
gpx-split-waypoints route.gpx route-split.gpx 10
# Step 3: POIs along the route track (use the same track file you want to query)
gpx-poi-enricher route.gpx camping.gpx --profile camping
GUI
Launch:
gpx-poi-enricher-gui
Development equivalent: python -m gpx_poi_enricher.gui (with the package on PYTHONPATH or installed).
Quick mode: append --quick to use sparse enrichment defaults in Easy and Expert’s POI Enricher (title bar shows [quick]).
Requires the gui extra: pip install "gpx-poi-enricher[gui]".
Easy vs Expert
Easy — Primary Google Maps URL (required); optional additional URLs (one per line) for alternate itineraries. Writes the primary routed GPX, optional alternate-route GPX files, optional detour fragment GPX files where an alternate differs from the primary, then runs POI enrichment on the tracks to search. Progress log and a list of generated files. Cancel stops after the current Overpass batch.
Expert — Same three tools as the CLIs in tabs: POI Enricher, Split Waypoints, Maps → GPX. The Maps → GPX tab also supports multiple URLs (primary + optional alternates/detours), matching the richer routing behaviour in Easy.
Long-running work runs off the UI thread.
Environment variables
GPX_POI_PROFILES_DIR — If set to an existing directory, built-in profiles are replaced by
every *.yaml in that folder (for private or dev profiles without editing the package).
OSRM_BASE_URL — Default OSRM API root ending in /route/v1 for maps-to-gpx. Overridden per
run by --osrm-base-url.
Command: maps-to-gpx
Converts one Google Maps directions URL to a routed GPX file.
- Resolves short
maps.app.goo.gllinks - Path-style (
/maps/dir/A/B/C) and query-style (?api=1&origin=…) URLs - Place names → Nominatim
- Routing → public OSRM (or your own via env /
--osrm-base-url) - Output:
<trk>geometry plus<wpt>for each user stopover
For multiple routes or detour GPX generation, use the GUI (Easy or Maps → GPX).
usage: maps-to-gpx [-h] [--mode {driving,cycling,walking}] [--name NAME]
[--osrm-base-url URL]
url output_gpx
positional arguments:
url Google Maps directions URL (full or short
maps.app.goo.gl link)
output_gpx Output GPX file path
options:
-h, --help show this help message and exit
--mode {driving,cycling,walking}
Transport mode for routing (default: driving)
--name NAME Track name written into the GPX file (default: Route)
--osrm-base-url URL OSRM API root ending in /route/v1 (default: public demo;
overrides OSRM_BASE_URL env if set)
Examples:
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/?api=1&origin=Paris&destination=Barcelona&waypoints=Lyon|Avignon" \
route.gpx --name "France to Spain"
maps-to-gpx "https://www.google.com/maps/dir/Amsterdam/Utrecht/" route.gpx --mode cycling
# Self-hosted OSRM (URL must end with /route/v1)
maps-to-gpx "https://www.google.com/maps/dir/A/B/" route.gpx \
--osrm-base-url "https://my-osrm.example.com/route/v1"
Command: gpx-split-waypoints
Reads track points from the input GPX and writes segments - 1 waypoints at even distances
along the track (Split 1, …). Each waypoint’s description holds the fractional position along
the track (e.g. 10.0% of track length).
Output is waypoints only — not the original track. Use it as a companion file or merge in your toolchain.
Requires segments >= 2.
usage: gpx-split-waypoints input.gpx output.gpx [segments]
positional arguments:
input.gpx Input GPX file with a track (≥ 2 points)
output.gpx Output GPX (split waypoint markers only)
segments Split into N equal segments → N−1 markers (default: 10)
Examples:
gpx-split-waypoints route.gpx route-split.gpx # default: 10 segments → 9 waypoints
gpx-split-waypoints route.gpx route-split.gpx 5 # 5 segments → 4 waypoints
Command: gpx-poi-enricher
Queries OpenStreetMap along the input GPX track and writes waypoints-only output.
usage: gpx-poi-enricher [-h] [--profile PROFILE] [--max-km MAX_KM]
[--sample-km SAMPLE_KM] [--batch-size BATCH_SIZE]
[--country-sample-km COUNTRY_SAMPLE_KM]
[--progress-interval SEC] [--verbose] [--quick]
[--list-profiles]
[input_gpx] [output_gpx]
Positional arguments:
input_gpx— GPX with a track to sampleoutput_gpx— GPX containing only<wpt>POIs
Options (subset):
--profile— profile id (case-insensitive), required unless--list-profiles--max-km,--sample-km,--batch-size,--country-sample-km— override profile defaults--progress-interval— stderr progress interval in seconds (0disables; default5)--verbose— print verbose Overpass error bodies--list-profiles— print all profiles and defaults, then exit--quick— combines with unset overrides: about 500 km sampling, 1 km search radius, 500 km country re-detection. Still overridden by explicit--sample-km/--max-km/--country-sample-km.
Examples:
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
Key options explained
--max-km— Maximum distance from the sampled track for a POI to be kept.--sample-km— Sampling step along the track before Overpass batching.--batch-size— Sample points bundled into one Overpass request (timeouts vs load).--country-sample-km— Minimum spacing between Nominatim reverse-geocode calls for country detection (default 40 when not using--quick).
Built-in Profiles
Defaults come from each file under profiles/. Run gpx-poi-enricher --list-profiles for full
sample_km, batch_size, and 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 with Kids Menu | 5.0 |
kids_activities |
Children's Activities of All Kinds | 15.0 |
attractions |
Generally spectacular child-friendly attraction | 10.0 |
Profiles like attractions and kids_activities use terms (regex over OSM name /
description / operator) with empty tags; others rely mainly on tags and may add
terms for extra matches.
Creating Custom Profiles
Add a YAML file. The id field or the filename (without .yaml) is the profile id.
When installed from PyPI, point GPX_POI_PROFILES_DIR at a folder of YAML files to use only
those profiles instead of the bundled set.
# profiles/my_profile.yaml
id: my_profile
description: "My custom POI type"
symbol: Flag, Blue # Garmin symbol name shown in the output GPX
defaults:
max_km: 8.0
sample_km: 4.0
batch_size: 5
retries: 3
# Matchers: ANY tag line can match OR (below) regex terms contribute extra selectors.
tags:
- key: tourism
value: museum
- key: amenity
value: fast_food
and:
key: cuisine
value: pizza
terms:
DE: ["Museum", "Schloss"]
FR: ["musée", "château"]
ES: ["museo", "castillo"]
EN: ["museum", "castle"]
You need at least one of: non-empty tags, or terms for the current country plus shared
EN terms (otherwise Overpass query construction fails). All keys in defaults can be
overridden from the CLI.
How It Works
maps-to-gpx
- Expand short URLs via HTTP redirects.
- Parse path or query parameters; coordinates used as-is; names geocoded with Nominatim.
- Route through OSRM; receive polyline geometry.
- Emit GPX
<trk>plus user<wpt>elements.
POI enrichment
- Sample the track every
sample_km. - Every
country_sample_km, reverse-geocode with Nominatim for ISO country codes. - Build Overpass QL per batch:
tags→ typed selectors around each sample;terms→ case-insensitive regex on selected elements’name/description/operatorwithinmax_km. - Merge results and deduplicate by OSM id.
- Write POIs as
<wpt>only; no tracks in the POI output file.
Overpass POSTs rotate through configured public mirrors and retry on failure.
Data Attribution
Map data © OpenStreetMap contributors — ODbL.
© OpenStreetMap contributors
Nominatim — OpenStreetMap Foundation.
Routing — OSRM public demo (ODbL); same caveats as in earlier README: usage limits, attribution, prefer self-hosted for heavy use.
Usage policies:
- Nominatim: ~1 request/s; meaningful
User-Agent(the tool sends one identifying this project). - Overpass: no bulk scraping; conservative defaults by design.
- OSRM demo: personal / non-commercial expectations;
OSRM_BASE_URL/--osrm-base-urlfor your own stack.
Contributing
Contributions are welcome — see CONTRIBUTING.md.
After cloning: ./scripts/setup-pre-commit.sh (hooks via devmarkusb/pre-commit, no submodule).
Bug reports and feature requests: GitHub issues.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gpx_poi_enricher-1.6.2.tar.gz.
File metadata
- Download URL: gpx_poi_enricher-1.6.2.tar.gz
- Upload date:
- Size: 680.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e43da63356e97d73fcffed992b6633d0b38671f9b4277de069f17d2748820fa4
|
|
| MD5 |
d37c4637aa626de1fa9b7f5f61f5f5f6
|
|
| BLAKE2b-256 |
cad65a29b64bace8c5d5e9c92f7d819267eb455a55a02b10f25e06d4ed8c4a00
|
Provenance
The following attestation bundles were made for gpx_poi_enricher-1.6.2.tar.gz:
Publisher:
release.yml on devmarkusb/gpx-poi-enricher
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gpx_poi_enricher-1.6.2.tar.gz -
Subject digest:
e43da63356e97d73fcffed992b6633d0b38671f9b4277de069f17d2748820fa4 - Sigstore transparency entry: 1526041914
- Sigstore integration time:
-
Permalink:
devmarkusb/gpx-poi-enricher@e100c7a2b6e0e8e98824422770d4292d7f6dffc4 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/devmarkusb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e100c7a2b6e0e8e98824422770d4292d7f6dffc4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file gpx_poi_enricher-1.6.2-py3-none-any.whl.
File metadata
- Download URL: gpx_poi_enricher-1.6.2-py3-none-any.whl
- Upload date:
- Size: 52.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9669097824b79e064adea5e95ce1977306fea99e173c83170946afb84304ab3
|
|
| MD5 |
cf85156f788b29dd05286242440e9c36
|
|
| BLAKE2b-256 |
3e42a51d73c22da697a596cec0a639bb7e9a40689a1bcc7095fb5f982b260747
|
Provenance
The following attestation bundles were made for gpx_poi_enricher-1.6.2-py3-none-any.whl:
Publisher:
release.yml on devmarkusb/gpx-poi-enricher
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gpx_poi_enricher-1.6.2-py3-none-any.whl -
Subject digest:
e9669097824b79e064adea5e95ce1977306fea99e173c83170946afb84304ab3 - Sigstore transparency entry: 1526042012
- Sigstore integration time:
-
Permalink:
devmarkusb/gpx-poi-enricher@e100c7a2b6e0e8e98824422770d4292d7f6dffc4 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/devmarkusb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e100c7a2b6e0e8e98824422770d4292d7f6dffc4 -
Trigger Event:
push
-
Statement type: