Extract Points of Interest (POIs) from OpenStreetMap data and output GeoJSON files. Supports both local PBF files and Overpass API queries.
Part of the Trufi Association open-source ecosystem.
- Dual Source Support: Extract POIs from local
.osm.pbffiles or query the Overpass API directly - GeoJSON Output: Generate standard GeoJSON files for each POI category
- SVG Icons Included: Each POI includes an inline SVG icon from Maki Icons
- Customizable Categories: Use default categories or define your own via JSON configuration
- CLI & Library: Use as a command-line tool or import as a library in your Node.js projects
- TypeScript: Fully typed for excellent IDE support
- Polygon Support: Extracts POIs as points, polygons, or multipolygons based on OSM geometry
npm install -g trufi-server-poi_extractornpm install trufi-server-poi_extractorgit clone https://github.com/trufi-association/trufi-server-poi_extractor.git
cd trufi-server-poi_extractor
npm install
npm run buildBoth examples extract POIs from Cochabamba, Bolivia using different data sources.
Use this method when you have a local .osm.pbf file (faster for large areas, works offline).
# The repository includes base.osm.pbf (Cochabamba extract)
# Or download from Geofabrik: wget https://download.geofabrik.de/south-america/bolivia-latest.osm.pbf
# Extract all POIs from the PBF file
poi-extractor -i base.osm.pbf -o ./output -vUse this method to query OSM data directly via the internet using a bounding box.
# Extract POIs for Cochabamba using Overpass API
# Bbox format: south,west,north,east
# Note: Use --bbox=... format for negative coordinates
poi-extractor --bbox="-17.45,-66.25,-17.30,-66.10" -o ./output -vTip: Use bboxfinder.com to get the bounding box coordinates for your area.
output/
├── healthcare.geojson
├── education.geojson
├── transport.geojson
├── food.geojson
├── shopping.geojson
├── tourism.geojson
├── finance.geojson
├── emergency.geojson
├── recreation.geojson
├── religion.geojson
├── government.geojson
├── accommodation.geojson
└── metadata.json
USAGE:
poi-extractor --input <file.osm.pbf> --output <dir>
poi-extractor --bbox <south,west,north,east> --output <dir>
OPTIONS:
-i, --input <file> Input OSM PBF file path
-o, --output <dir> Output directory for GeoJSON files (required)
-b, --bbox <bbox> Bounding box: south,west,north,east (for Overpass API)
-c, --categories <file> Custom categories JSON file
--only <categories> Only extract specific categories (comma-separated)
--endpoint <url> Custom Overpass API endpoint
-v, --verbose Enable verbose output
-h, --help Show help message
--version Show version number
# Extract all categories from PBF
poi-extractor -i city.osm.pbf -o ./output
# Extract only healthcare and education
poi-extractor -i city.osm.pbf -o ./output --only healthcare,education
# Use custom categories file
poi-extractor -i city.osm.pbf -o ./output -c my-categories.json
# Extract from Overpass API with verbose output
poi-extractor --bbox="-17.45,-66.25,-17.30,-66.10" -o ./output -v
# Use a different Overpass endpoint
poi-extractor --bbox="-17.45,-66.25,-17.30,-66.10" -o ./output --endpoint https://overpass.kumi.systems/api/interpreterimport { extractFromPBF, extractFromOverpass, DEFAULT_CATEGORIES } from 'trufi-server-poi_extractor';
// Extract from PBF file
const result = await extractFromPBF({
inputFile: './city.osm.pbf',
outputDir: './output',
categories: DEFAULT_CATEGORIES,
verbose: true
});
console.log(`Extracted ${result.metadata.total} POIs`);
// Extract from Overpass API
const overpassResult = await extractFromOverpass({
bbox: {
south: -17.45,
west: -66.25,
north: -17.30,
east: -66.10
},
outputDir: './output',
categories: DEFAULT_CATEGORIES,
verbose: true
});| Category | Description | OSM Tags |
|---|---|---|
healthcare |
Hospitals, clinics, pharmacies | amenity=hospital/clinic/pharmacy, healthcare=* |
education |
Schools, universities, libraries | amenity=school/university/library |
transport |
Bus stops, train stations, airports | public_transport=*, railway=station, aeroway=* |
food |
Restaurants, cafes, bars | amenity=restaurant/cafe/fast_food/bar |
shopping |
Supermarkets, malls, markets | shop=supermarket/mall, amenity=marketplace |
tourism |
Hotels, museums, attractions | tourism=*, historic=* |
finance |
Banks, ATMs | amenity=bank/atm |
emergency |
Police, fire stations | amenity=police/fire_station, emergency=* |
recreation |
Parks, sports facilities | leisure=park/sports_centre, amenity=cinema |
religion |
Places of worship | amenity=place_of_worship |
government |
Town halls, post offices | amenity=townhall/post_office, office=government |
accommodation |
Hotels, hostels, camping | tourism=hotel/hostel/camp_site |
Create a JSON file with your custom categories:
{
"coffee_shops": {
"displayName": "Coffee Shops",
"matchers": [
{ "key": "amenity", "values": ["cafe"] },
{ "key": "cuisine", "values": ["coffee"] }
]
},
"ev_charging": {
"displayName": "EV Charging Stations",
"matchers": [
{ "key": "amenity", "values": ["charging_station"] }
]
},
"all_shops": {
"displayName": "All Shops",
"matchers": [
{ "key": "shop", "values": null }
]
}
}Use "values": null to match any value for a tag key.
Then use it:
poi-extractor -i city.osm.pbf -o ./output -c my-categories.jsonEach category generates a GeoJSON FeatureCollection:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": 123456789,
"geometry": {
"type": "Point",
"coordinates": [-66.15, -17.38]
},
"properties": {
"id": 123456789,
"name": "Hospital del Norte",
"type": "hospital",
"category": "healthcare",
"subcategory": "hospital",
"osmType": "node",
"iconName": "hospital",
"amenity": "hospital",
"addr:street": "Av. América"
}
}
]
}Icons are stored in metadata.json and referenced by iconName in each feature. This avoids duplicating SVG content across thousands of features.
Feature property:
"iconName": "hospital"metadata.json:
{
"icons": {
"hospital": "<?xml version=\"1.0\"...><svg>...</svg>",
"pharmacy": "<?xml version=\"1.0\"...><svg>...</svg>"
}
}Icons are automatically mapped based on the POI's type (OSM tag value). Common mappings:
| Type | Icon |
|---|---|
| hospital | hospital |
| pharmacy | pharmacy |
| school | school |
| university | college |
| library | library |
| restaurant | restaurant |
| cafe | cafe |
| hotel | lodging |
| bank | bank |
| police | police |
| park | park |
Icons are sourced from Maki Icons, released under CC0 1.0 Universal (Public Domain).
- Geofabrik: https://download.geofabrik.de/ (continent/country extracts)
- BBBike: https://extract.bbbike.org/ (custom extracts)
- Planet OSM: https://planet.openstreetmap.org/ (full planet file)
The tool uses the public Overpass API by default. For heavy usage, consider:
- Running your own Overpass instance
- Using alternative endpoints like
https://overpass.kumi.systems/api/interpreter
# Install dependencies
npm install
# Run in development mode
npm run dev -- -i test.osm.pbf -o ./out -v
# Type check
npm run typecheck
# Build for production
npm run build
# Run built version
npm start -- -i test.osm.pbf -o ./out -vContributions are welcome! Please read our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Trufi Core - Mobile transit app
- Trufi Server - Backend services
- OpenTripPlanner - Multimodal trip planning
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
- OpenStreetMap contributors for the amazing map data
- Overpass API for the query service
- osm-pbf-parser for PBF parsing
- Maki Icons by Mapbox for POI icons (CC0 1.0)
Made with care by Trufi Association