free-geocoding-and-maps
This skill provides free address geocoding and reverse geocoding using OpenStreetMap's Nominatim API, converting addresses to coordinates and vice versa without requiring API keys or incurring costs. Use it when building location-based features, validating addresses, or performing geospatial lookups while avoiding paid geocoding services like Google Maps or Mapbox.
git clone --depth 1 https://github.com/besoeasy/open-skills /tmp/free-geocoding-and-maps && cp -r /tmp/free-geocoding-and-maps/skills/free-geocoding-and-maps ~/.claude/skills/free-geocoding-and-mapsSKILL.md
# Free Geocoding and Maps — OpenStreetMap Nominatim
Geocode addresses to coordinates and reverse geocode coordinates to addresses using free OpenStreetMap Nominatim API. Privacy-respecting alternative to Google Maps API ($5-40/1000 requests).
## Why This Replaces Paid Geocoding APIs
**💰 Cost savings:**
- ✅ **100% free** — no API keys required
- ✅ **No rate limits** — generous 1 request/second for public instances
- ✅ **Open source** — self-hostable for unlimited usage
- ✅ **Privacy-first** — no tracking, no data collection
**Perfect for AI agents that need:**
- Address validation and geocoding
- Reverse geocoding (coordinates to address)
- Location search and mapping
- Geospatial data without Google Maps API costs
## Quick comparison
| Service | Cost | Rate limit | Privacy | API key required |
|---------|------|------------|---------|------------------|
| Google Maps Geocoding | $5/1000 requests | 40,000/month free | ❌ Tracked | ✅ Yes |
| Mapbox Geocoding | $0.50/1000 after 100k free | 100k/month free | ❌ Tracked | ✅ Yes |
| **Nominatim (OSM)** | **Free** | **1 req/sec** | **✅ Private** | **❌ No** |
## Skills
### geocode_address
Convert address to coordinates (latitude/longitude).
```bash
# Geocode an address
ADDRESS="1600 Amphitheatre Parkway, Mountain View, CA"
curl -s "https://nominatim.openstreetmap.org/search?q=${ADDRESS}&format=json&limit=1" \
| jq -r '.[0] | {lat: .lat, lon: .lon, display_name: .display_name}'
# Geocode with structured address
curl -s "https://nominatim.openstreetmap.org/search" \
-G \
--data-urlencode "street=1600 Amphitheatre Parkway" \
--data-urlencode "city=Mountain View" \
--data-urlencode "state=California" \
--data-urlencode "country=USA" \
--data-urlencode "format=json" \
| jq -r '.[0] | {lat: .lat, lon: .lon}'
# Get multiple results
curl -s "https://nominatim.openstreetmap.org/search?q=London&format=json&limit=5" \
| jq -r '.[] | {name: .display_name, lat: .lat, lon: .lon}'
```
**Node.js:**
```javascript
async function geocodeAddress(address, limit = 1) {
const params = new URLSearchParams({
q: address,
format: 'json',
limit: limit.toString()
});
const res = await fetch(`https://nominatim.openstreetmap.org/search?${params}`, {
headers: {
'User-Agent': 'AI-Agent/1.0' // Required by Nominatim usage policy
}
});
if (!res.ok) {
throw new Error(`Geocoding failed: ${res.status}`);
}
const results = await res.json();
if (results.length === 0) {
return null;
}
return results.map(r => ({
lat: parseFloat(r.lat),
lon: parseFloat(r.lon),
displayName: r.display_name,
type: r.type,
importance: r.importance
}));
}
// Usage
// geocodeAddress('Eiffel Tower, Paris')
// .then(results => {
// if (results) {
// console.log(`Location: ${results[0].displayName}`);
// console.log(`Coordinates: ${results[0].lat}, ${results[0].lon}`);
// }
// });
```
### reverse_geocode
Convert coordinates to address (reverse geocoding).
```bash
# Reverse geocode coordinates
LAT=40.7589
LON=-73.9851
curl -s "https://nominatim.openstreetmap.org/reverse?lat=${LAT}&lon=${LON}&format=json" \
| jq -r '.display_name'
# Get detailed address components
curl -s "https://nominatim.openstreetmap.org/reverse?lat=${LAT}&lon=${LON}&format=json" \
| jq -r '.address | {
road: .road,
city: .city,
state: .state,
country: .country,
postcode: .postcode
}'
# Reverse geocode with zoom level (detail level)
curl -s "https://nominatim.openstreetmap.org/reverse?lat=${LAT}&lon=${LON}&format=json&zoom=18" \
| jq -r '.display_name'
```
**Node.js:**
```javascript
async function reverseGeocode(lat, lon, zoom = 18) {
const params = new URLSearchParams({
lat: lat.toString(),
lon: lon.toString(),
format: 'json',
zoom: zoom.toString()
});
const res = await fetch(`https://nominatim.openstreetmap.org/reverse?${params}`, {
headers: {
'User-Agent': 'AI-Agent/1.0'
}
});
if (!res.ok) {
throw new Error(`Reverse geocoding failed: ${res.status}`);
}
const data = await res.json();
return {
displayName: data.display_name,
address: {
road: data.address?.road,
city: data.address?.city || data.address?.town || data.address?.village,
state: data.address?.state,
country: data.address?.country,
postcode: data.address?.postcode
},
lat: parseFloat(data.lat),
lon: parseFloat(data.lon)
};
}
// Usage
// reverseGeocode(48.8584, 2.2945) // Eiffel Tower coordinates
// .then(result => {
// console.log('Address:', result.displayName);
// console.log('City:', result.address.city);
// console.log('Country:', result.address.country);
// });
```
### search_nearby_places
Search for places near coordinates or within a bounding box.
```bash
# Search for places near coordinates
LAT=40.7589
LON=-73.9851
RADIUS_KM=1
curl -s "https://nominatim.openstreetmap.org/search?q=restaurant&format=json&limit=10&lat=${LAT}&lon=${LON}" \
| jq -r '.[] | {name: .display_name, distance: .distance}'
# Search within bounding box (viewbox)
# Format: left,top,right,bottom (min_lon,max_lat,max_lon,min_lat)
curl -s "https://nominatim.openstreetmap.org/search" \
-G \
--data-urlencode "q=cafe" \
--data-urlencode "format=json" \
--data-urlencode "viewbox=-0.1278,51.5074,-0.1,51.52" \
--data-urlencode "bounded=1" \
| jq -r '.[] | {name: .display_name, lat: .lat, lon: .lon}'
```
**Node.js:**
```javascript
async function searchNearby(query, lat, lon, limit = 10) {
const params = new URLSearchParams({
q: query,
format: 'json',
limit: limit.toString(),
lat: lat.toString(),
lon: lon.toString()
});
const res = await fetch(`https://nominatim.openstreetmap.org/search?${params}`, {
headers: {
'User-Agent': 'AI-Agent/1.0'
}
});
if (!res.ok) {
throw new Error(`Search failed: ${res.status}`);
}
const results = awEncrypt and decrypt files or streams using age — a simple, modern, and secure encryption tool with small explicit keys, passphrase support, SSH key support, post-quantum hybrid keys, and UNIX-style composability. No config options, no footguns.
Upload and host files anonymously using decentralized storage with Originless and IPFS.
Automate web browsers for AI agents using agent-browser CLI with deterministic element selection.
Star all repositories from a GitHub user automatically. Use when: (1) Supporting open source creators, (2) Bulk discovery of useful projects, or (3) Automating GitHub engagement.
Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.
Log all chat messages to a SQLite database for searchable history and audit. Use when: (1) Building chat history, (2) Auditing conversations, (3) Searching past messages, or (4) User asks to log chats.
Check cryptocurrency wallet balances across multiple blockchains using free public APIs.
Calculate line-of-sight and road distances between two cities using free OpenStreetMap services.