Garmin GPI — Proprietary POI Format for nuvi/etrex: Icons, Proximity Alerts and OSM Conversion

2026-04-027 min read
GarminGPIPOInavigationGPSbinaryproprietary

Garmin GPI is a proprietary binary container for custom POI (Points of Interest) targeting Garmin GPS devices: the nüvi, Drive, eTrex, GPSMAP, Oregon and Edge lines. The format appeared around 2005 alongside the free Garmin POI Loader utility and is still the standard way to push custom "points of interest" onto a Garmin device: speed cameras, specific fuel-station brands, favourite restaurants, trusted truck stops. Three things make GPI different from a plain GPX waypoint file and keep it alive: per-category BMP icons, proximity alerts (an audible beep when you come within N metres), and category grouping with on-device toggles right from the menu. On osm2cdr.ru the GPI exporter is implemented as a gpsbabel -o garmin_gpi chain: the user picks OSM POI categories (fuel, ATMs, cafés, parking), the backend pulls points from PostGIS, builds an intermediate GPX, and gpsbabel packages the final .gpi with icons.

Map generation of Vladivostok city center

History: Garmin POI Loader and the birth of GPI

By 2004 Garmin already had a mature pipeline for basemaps (Garmin IMG) and for tracks/waypoints (GPX via MapSource), but a missing piece — a format for "user POIs" that wouldn't be part of the basemap, would update independently, and would carry visual styling. The main trigger was third-party custom POI databases: speed-camera lists shared widely across European POI communities, branded fuel-station networks, restaurant guides, campsites. Garmin needed a format these providers could pack their data into.

In 2005 Garmin shipped POI Loader — a free Windows utility that took CSV/GPX plus a BMP icon and emitted a .gpi file ready to drop into the /Garmin/POI/ folder. Garmin never published the spec — classic closed binary, just like IMG. But by 2008–2010 the open-source gpsbabel project (Robert Lipe et al.) reverse-engineered read/write support for GPI, which effectively made the format accessible from Linux/macOS and from any Python script via subprocess.

Since then GPI has had a parallel life: commercial services (POI-Factory, POIplaza) sell subscriptions to fresh GPI speed-camera and fuel databases, while the open-source community (us included) generates GPI from OSM data — natively through gpsbabel.

Inside GPI files

.gpi is a binary container with its own magic header, a sectioned structure, and packed BMP resources. Reverse engineering by gpsbabel revealed the following main sections:

  • Header — magic bytes GRMREC00 / GRMRECnn, format version, codepage (typically cp1252, utf-8 in newer revisions), creation timestamp, total POI count.
  • Categories block — list of categories with their names (what appears in the Custom POI menu on the device) and an embedded BMP icon for each (usually 24×24 or 32×32, 8-bit color). A category equals one logical layer the user can toggle on/off.
  • POI records — repeating entries: lat (float64), lon (float64), name (variable-length string in the chosen codepage), description (optional), category_id (uint16), proximity_alert_distance (uint32 in metres, 0 = no alert), phone (optional, for click-to-call on nüvi), address (optional).
  • Footer — checksum, end-of-file marker.

Coordinates are stored in WGS84 as float64, without Garmin's grid projection (unlike IMG, which uses a 24-bit signed integer grid). So GPI is noticeably "fatter" per point in bytes but simpler to generate — no custom geo-projection.

Maximum .gpi size is bounded more by device memory than by the format: a typical nüvi from 2005-2010 happily accepts 50-100 thousand POIs; a modern Drive 5x handles millions. A single .gpi can hold up to ~200 categories (a practical limit found by the community).

Use cases

Driver with speed cameras and fuel brands. The main historic use case: load into a nüvi or Drive a database of every speed camera in your country with a 300-metre proximity alert, so the device "barks" before the corner with a camera. In parallel — POIs of a favourite fuel-station brand (Lukoil, Shell, ExxonMobil) with a branded icon, so the "nearest gas" search surfaces them first. On osm2cdr you can export amenity=fuel for an entire region as one GPI with a branded icon.

Tourist and outdoor. Edge cyclists and eTrex hikers load custom POIs with verified overnight spots, water sources, cafés along long-distance bike routes. GPI is valuable because icons are visible right on the device screen (unlike anonymous GPX waypoints), and the "campsites" and "shops" layers can be toggled separately.

Map generation of Tokyo city center

Workflow in OSM2CDR

Our GPI export is garmin_gpi_exporter.py, a thin wrapper around the PostGIS → GPX → gpsbabel chain. The pipeline:

Step 1: POI filtering. From local PostGIS via local_osm_loader.py we pull points of the requested categories inside the bbox. Default mapping: amenity=fuel → "Fuel" category, amenity=atm → "ATM", amenity=cafe → "Cafe", amenity=parking → "Parking", tourism=* → "Tourism", and so on (about 15 categories out of the box).

Step 2: intermediate GPX generation. Each point is written as <wpt> with <name>, <desc> (address + tags), and a custom <extensions> block tying it to our category. One GPX covers all categories — gpsbabel will sort them out.

Step 3: run gpsbabel. The worker calls gpsbabel -i gpx -f /tmp/poi.gpx -o garmin_gpi,bitmap=icons/<category>.bmp,category="Category Name" -F /tmp/output.gpi. For each category — a separate run with its own BMP icon (24×24, 8-bit), stored in worker/renderer/assets/garmin_gpi_icons/. The per-category .gpi files are merged into one via gpsbabel's merge mode.

Step 4: validation. We confirm the output .gpi parses back via gpsbabel -i garmin_gpi -f output.gpi -o gpx -F /tmp/check.gpx and that the waypoint count matches the input. The user gets a single .gpi plus an instruction note: "copy to Garmin/POI/ on the device, reboot, find under the Custom POI menu".

Fallback scenario: if gpsbabel isn't available in the worker image for some reason (e.g. during a degraded deployment), the exporter falls back to pure GPX and warns the user: icons and alerts are lost, but waypoints will open on any Garmin as plain points. The /api/render?format=garmin-gpi endpoint supports both paths.

GPI vs GPX vs OV2

GPX is an open XML format read by any GPS device and any software, but it carries no icons, no categories, and no proximity alerts; on the device display every waypoint looks like an identical dot. TomTom OV2 is a parallel proprietary POI format, only for TomTom devices, with a comparable feature set (categories, BMP icons, alerts) but incompatible with Garmin. GPI sits in its own niche: richer than GPX in presentation (icons + alerts + categories) and at the same time compatible with the entire Garmin ecosystem from 2005-2010 right up to the latest Drive and Edge models.

If your device is a Garmin and you need more than "bare coordinates" — pick GPI. If you need the most universal format for sharing between devices from different manufacturers — pick GPX. If you have a TomTom — go with OV2.

Map generation of Saint Petersburg city center

Conclusion

Garmin GPI is a compact, long-stabilised proprietary format that, thanks to gpsbabel, has effectively become open enough to generate from any source. For users of Garmin nüvi, Drive, eTrex or Edge devices it remains the most practical way to turn OSM POIs into proper "points of interest" with icons and audio alerts — far more useful than anonymous GPX waypoints. Try exporting the region you need now on the /formats/garmin-gpi/ page: pick POI categories, draw a bbox on the map, and receive a ready .gpi in a minute.

Sources

← All articles