Enrich GPX tracks with Points of Interest from OpenStreetMap via configurable YAML profiles
Project description
gpx-poi-enricher
A three-command toolkit for building POI-enriched GPX files from a Google Maps route.
Table of Contents
- The Pipeline
- Features
- Installation
- Quick Start
- 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 ← adds evenly-spaced split markers (optional, for long routes)
│
▼
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 work independently or in sequence. In the end, if the result file is too large (>5MB) for your consumer app, https://www.gpxtokml.com/ helps a lot.
Features
maps-to-gpx— convert a Google Maps directions URL (including shortmaps.app.goo.gllinks) directly to a routed GPX file. Handles place-name waypoints via Nominatim geocoding and routes via the public OSRM API. No API key required.gpx-split-waypoints— add evenly-spaced split waypoints to a GPX track, useful for importing oversized files into apps that enforce a waypoint limit.gpx-poi-enricher— enrich any GPX track with Points of Interest from OpenStreetMap. 11 ready-to-use profiles covering camping, beaches, playgrounds, theme parks, restaurants, and more.- Country-aware search terms: automatically detects which country each section of the route passes through and queries in the local language (DE, FR, ES, EN).
- Searches OpenStreetMap via the public Overpass API with multi-endpoint fallback for reliability.
- Configurable search radius, sampling interval, and batch size per profile — all overridable on the command line.
- Extensible: add a new profile by dropping a single YAML file into the
profiles/directory.
Installation
From PyPI (recommended)
pip install gpx-poi-enricher
From source (development)
git clone https://github.com/devmarkusb/gpx-poi-enricher.git
cd gpx-poi-enricher
pip install -e ".[dev]"
Quick Start
Full pipeline — Google Maps URL to a campsite waypoint file:
# Step 1: convert a Google Maps directions link to a GPX track
maps-to-gpx "https://www.google.com/maps/dir/Paris/Lyon/Barcelona/" route.gpx
# Step 2 (optional): add split markers every ~10% of the route
gpx-split-waypoints route.gpx route-split.gpx 10
# Step 3: find all campsites within 10 km of the route
gpx-poi-enricher route.gpx camping.gpx --profile camping
Command: maps-to-gpx
Converts a Google Maps directions URL to a routed GPX file.
- Follows redirects for short
maps.app.goo.glURLs - Handles both path-style (
/maps/dir/A/B/C) and query-style (?api=1&origin=...) URLs - Geocodes place names via Nominatim (no API key)
- Routes via the public OSRM API (no API key)
- Writes a
<trk>with the full routed geometry and<wpt>markers for each stopover
usage: maps-to-gpx [-h] [--mode {driving,cycling,walking}] [--name NAME]
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)
Examples:
# Path-style URL with place names
maps-to-gpx "https://www.google.com/maps/dir/Paris/Lyon/Marseille/" route.gpx
# Short URL
maps-to-gpx "https://maps.app.goo.gl/ABC123" route.gpx
# Query-style URL with multiple stopovers, custom name
maps-to-gpx "https://www.google.com/maps/dir/?api=1&origin=Paris&destination=Barcelona&waypoints=Lyon|Avignon" route.gpx --name "France to Spain"
# Cycling route
maps-to-gpx "https://www.google.com/maps/dir/Amsterdam/Utrecht/" route.gpx --mode cycling
Command: gpx-split-waypoints
Adds evenly-spaced waypoints along a GPX track, named Split 1, Split 2, etc. Useful when an app or device has a waypoint import limit and a long route needs to be broken into manageable segments.
usage: gpx-split-waypoints input.gpx output.gpx [segments]
positional arguments:
input.gpx Input GPX file with a track
output.gpx Output GPX file (original track + split waypoints)
segments Number of equal segments to split into (default: 10)
Examples:
# Split into 10 equal segments (default)
gpx-split-waypoints route.gpx route-split.gpx
# Split into 5 segments
gpx-split-waypoints route.gpx route-split.gpx 5
Command: gpx-poi-enricher
Queries OpenStreetMap for Points of Interest along a GPX track and writes them as waypoints to a new GPX file.
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]
[--list-profiles]
[input_gpx] [output_gpx]
positional arguments:
input_gpx Input GPX file with a track
output_gpx Output GPX file (waypoints only)
options:
-h, --help show this help message and exit
--profile PROFILE Profile id, e.g. camping or playground
(case-insensitive)
--max-km MAX_KM Override max distance from track (km)
--sample-km SAMPLE_KM
Override track sampling interval (km)
--batch-size BATCH_SIZE
Override Overpass query batch size
--country-sample-km COUNTRY_SAMPLE_KM
Min distance (km) between Nominatim reverse-geocode
calls (default: 40)
--progress-interval SEC
Print progress to stderr every SEC seconds
(default: 5; 0 = off)
--verbose Print verbose Overpass error bodies
--list-profiles List built-in profiles and exit
Examples:
# Find campsites within 10 km of the route
gpx-poi-enricher route.gpx camping.gpx --profile camping
# Find playgrounds within 5 km (overriding the profile default of 3 km)
gpx-poi-enricher route.gpx playgrounds.gpx --profile playground --max-km 5
# List all available built-in profiles
gpx-poi-enricher --list-profiles
Key options explained
--max-km— How far from the track a POI may be to be included. Larger values cast a wider net but produce more results and slower queries.--sample-km— The track is sampled at this interval before querying Overpass. Smaller values give denser coverage but proportionally more API calls.--batch-size— How many sample points are bundled into a single Overpass request. Tune this if you hit timeouts on slow connections.--country-sample-km— Distance between Nominatim reverse-geocode lookups used to determine the current country. Increase to reduce Nominatim traffic on very long routes.
Built-in Profiles
| Profile ID | Description | Default max_km |
|---|---|---|
camping |
Campsite / motorhome stopover | 10.0 |
playground |
Playground | 3.0 |
outdoor_pool |
Outdoor pool / water park / thermal bath | 10.0 |
beach |
Beach / swimming lake | 25.0 |
theme_park |
Theme park / amusement park | 10.0 |
zoo |
Zoo / petting zoo | 12.0 |
aquarium |
Aquarium | 15.0 |
mcdonalds |
McDonald's restaurants | 5.0 |
restaurant |
Family-friendly restaurant with kids menu | 5.0 |
kids_activities |
Kids activities of all kinds | 15.0 |
attractions |
Family-friendly sights, viewpoints, museums | 20.0 |
Creating Custom Profiles
A profile is a plain YAML file placed in the profiles/ directory. The filename without extension becomes the profile ID.
# 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 # default search radius from the track
sample_km: 4.0 # sample the track every N km
batch_size: 5 # sample points per Overpass request
retries: 3 # number of Overpass retry attempts
# One or more OSM tag matchers. Results matching ANY entry are included.
tags:
- key: tourism
value: museum
- key: historic
value: castle
# Optional sub-filter: both conditions must match
- key: amenity
value: fast_food
and:
key: cuisine
value: pizza
# Country-specific search terms used to name waypoints.
# Omit or set to {} if not needed.
terms:
DE: ["Museum", "Schloss", "Burg"]
FR: ["musée", "château"]
ES: ["museo", "castillo"]
EN: ["museum", "castle"]
All fields in defaults can be overridden on the command line. The terms map is keyed by ISO 3166-1 alpha-2 country code; the tool selects the appropriate language based on the country detected along the route.
How It Works
maps-to-gpx
- URL expansion — Short
maps.app.goo.gllinks are resolved by following HTTP redirects. - Waypoint extraction — The URL path (
/maps/dir/A/B/C) or query parameters (origin,waypoints,destination) are parsed. Coordinate waypoints (48.8566,2.3522) are used directly; place-name waypoints are geocoded via Nominatim. - Routing — Waypoints are sent to the OSRM public routing API, which returns a full road-snapped geometry.
- GPX output — The routed geometry is written as a
<trk>element; the user waypoints (start, stopovers, end) are written as<wpt>elements.
gpx-poi-enricher
- Track sampling — The input GPX track is sampled at
sample_kmintervals, producing a list of coordinates. - Country detection — Every
country_sample_kmkilometres, the tool calls the Nominatim reverse-geocoding API to determine the current country code. This allows the profile's search terms to be localised. - Overpass queries — Sample points are grouped into batches. For each batch, an Overpass API query is built from the profile's
tagsand the country-appropriateterms. The query fetches all matching OSM nodes and ways withinmax_kmof each sample point. - Deduplication — Results from all batches are merged and deduplicated by OSM ID.
- GPX output — Each unique POI is written as a
<wpt>element to the output GPX file. Tracks and routes are intentionally excluded so the file contains only waypoints.
The tool rotates through several public Overpass API endpoints and retries failed requests automatically, making it resilient to temporary rate limits.
Data Attribution
Map data is sourced from OpenStreetMap contributors and is made available under the Open Database License (ODbL).
© OpenStreetMap contributors
Geocoding and reverse geocoding are performed by the Nominatim service, provided by the OpenStreetMap Foundation.
Routing is performed by the OSRM public demo server, also based on OpenStreetMap data (ODbL).
Please respect the usage policies of all three services:
- Nominatim: maximum 1 request per second; identify your application with a meaningful
User-Agent. - Overpass API: avoid bulk downloads; the tool's default batch and retry settings are chosen to be a considerate citizen of the public infrastructure.
- OSRM demo server: personal/non-commercial use; attribution required; access may be withdrawn without notice — consider self-hosting for production workloads.
Contributing
Contributions are welcome. Please read CONTRIBUTING.md before opening a pull request.
Bug reports and feature requests can be filed as GitHub issues.
License
This project is licensed under the MIT License — see the LICENSE file for details.
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-0.1.0.tar.gz.
File metadata
- Download URL: gpx_poi_enricher-0.1.0.tar.gz
- Upload date:
- Size: 74.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d640fb8a5e4f0c54d66d02c3ac7adcf0d1d442879ddefec31bad6382354ab1d
|
|
| MD5 |
580ccd9b575158284a8d1622712a1fd0
|
|
| BLAKE2b-256 |
8961fcec925360347d506a43312184be6f20a2be7074b113785604aecc355269
|
File details
Details for the file gpx_poi_enricher-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gpx_poi_enricher-0.1.0-py3-none-any.whl
- Upload date:
- Size: 25.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e50e05b09e6ea034ed46f2ba5058b06c14ec23e7c8f6b4e484c36cb24ac30d3
|
|
| MD5 |
74edebb25ae82d80076c79ae14d290e8
|
|
| BLAKE2b-256 |
b3c9bd05cbfd28735a1e5600e52168e7057355fe7071591c162fd1e7cb1c09ab
|