# Coordinate Lookup

> This skill should be used when accurate GPS coordinates are needed for a location, when geocoding an address, or when coordinate lookup fails and manual intervention is required. Provides OpenStreetMap Nominatim API expertise and geocoding utilities.

- Skill: `majiayu000/coordinate-lookup` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/coordinate-lookup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/coordinate-lookup/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/coordinate-lookup

---


# Coordinate Lookup

## Overview

Find accurate GPS coordinates for locations using OpenStreetMap's Nominatim geocoding service. This skill provides knowledge for querying Nominatim API, handling multiple search strategies, and selecting the most relevant results.

## When to Use This Skill

Load this skill when:
- Finding GPS coordinates for a location name
- Geocoding addresses or place names
- Resolving ambiguous location queries
- Validating coordinate accuracy
- Troubleshooting failed coordinate lookups

## Core Concepts

### Nominatim API

Nominatim is OpenStreetMap's free geocoding service that converts place names and addresses into geographic coordinates.

**Key features:**
- Free to use (no API key required)
- Global coverage from OpenStreetMap data
- Multiple search strategies (place name, address, structured)
- Returns multiple results ranked by relevance
- Includes bounding boxes and administrative boundaries

**Base URL:** `https://nominatim.openstreetmap.org`

**Rate limit:** 1 request per second (enforced)

### Search Endpoint

**Basic search:**
```bash
GET /search?q={query}&format=json&limit=5
```

**Parameters:**
- `q` - Search query (location name, address, etc.)
- `format` - Response format (`json`, `jsonv2`, `xml`)
- `limit` - Maximum results (default 10, max 50)
- `countrycodes` - Restrict to countries (ISO 3166-1 alpha-2, comma-separated)
- `addressdetails` - Include address breakdown (`0` or `1`)

**Example:**
```bash
curl "https://nominatim.openstreetmap.org/search?q=Old+Man+of+Storr&format=json&limit=5"
```

### Response Format

```json
[
  {
    "place_id": 12345,
    "lat": "57.5062935",
    "lon": "-6.180885",
    "display_name": "Old Man of Storr, Isle of Skye, Highland, Scotland, UK",
    "type": "peak",
    "importance": 0.62,
    "boundingbox": ["57.5062935", "57.5062935", "-6.180885", "-6.180885"]
  }
]
```

**Key fields:**
- `lat` - Latitude (string, convert to number)
- `lon` - Longitude (string, convert to number)
- `display_name` - Full location description
- `type` - OSM feature type (peak, city, restaurant, etc.)
- `importance` - Relevance score (0-1, higher = more important)
- `boundingbox` - [min_lat, max_lat, min_lon, max_lon]

## Search Strategies

To find the most accurate coordinates, try multiple search strategies in order:

### 1. Exact Name Search

Start with the exact location name provided.

```bash
curl "https://nominatim.openstreetmap.org/search?q=University+of+Bristol+Botanic+Gardens&format=json&limit=3"
```

**Best for:** Well-known landmarks, specific venues

### 2. Name + Country/Region

Add geographic context if exact search fails or returns too many results.

```bash
curl "https://nominatim.openstreetmap.org/search?q=Dishoom+Edinburgh&countrycodes=gb&format=json&limit=3"
```

**Best for:** Common names, chain locations

### 3. Structured Search

Use structured query parameters for addresses.

```bash
GET /search?street={street}&city={city}&country={country}&format=json
```

**Best for:** Full addresses, specific properties

### 4. Reverse Search Variations

Try alternative name formats or common misspellings.

```bash
# Try without special characters
curl "https://nominatim.openstreetmap.org/search?q=Old+Man+Storr&format=json"

# Try alternative names
curl "https://nominatim.openstreetmap.org/search?q=The+Old+Man+of+Storr&format=json"
```

## Selecting Best Result

When multiple results returned, select based on:

1. **Type relevance:** Match expected type (restaurant, peak, park, etc.)
2. **Importance score:** Higher is generally more relevant
3. **Display name:** Should match expected location/region
4. **Bounding box:** Smaller box = more specific location

**Example logic:**
```python
# Sort by importance (descending)
results.sort(key=lambda x: float(x['importance']), reverse=True)

# Filter by expected type if known
if location_type == "restaurant":
    results = [r for r in results if r['type'] in ['restaurant', 'cafe', 'bar']]

# Take first (most relevant)
best_result = results[0]
coordinates = [float(best_result['lat']), float(best_result['lon'])]
```

## Error Handling

### No Results Found

**Causes:**
- Misspelled location name
- Very obscure or new location
- Location not in OpenStreetMap database

**Solutions:**
1. Try alternative name formats
2. Add geographic context (country, region)
3. Search for nearby landmark instead
4. Leave coordinates empty (graceful degradation)

### Rate Limit Exceeded

**Error:** HTTP 429 or "Too Many Requests"

**Solution:**
- Wait 1 second between requests
- Use `time.sleep(1)` in scripts
- Respect Nominatim usage policy

### Ambiguous Results

**Issue:** Multiple equally relevant results

**Solutions:**
1. Check `display_name` for region match
2. Use `countrycodes` parameter to filter
3. Compare `importance` scores
4. Ask user to confirm if uncertain

## Best Practices

### API Usage

1. **Add User-Agent header:**
   ```bash
   -H "User-Agent: ObsidianLocationNotes/0.1.0"
   ```
   Required by Nominatim usage policy

2. **Respect rate limit:** 1 request/second maximum

3. **Cache results:** Don't re-query same location

4. **Use countrycodes:** Filter results when country known
   ```bash
   &countrycodes=gb,ie  # UK and Ireland only
   ```

### Search Quality

1. **Remove special characters:** Convert "Old Man of Storr" → "Old Man Storr" if needed

2. **Try variations:** "Botanic Garden" vs "Botanical Gardens"

3. **Include city for businesses:** "Dishoom Edinburgh" not just "Dishoom"

4. **Check display_name:** Verify result matches expected region

### Coordinate Format

Convert API strings to numbers:

```python
lat = float(result['lat'])  # "57.5062935" → 57.5062935
lon = float(result['lon'])  # "-6.180885" → -6.180885
```

Store as array for Obsidian:
```yaml
location:
  - 57.5062935   # Latitude
  - -6.180885    # Longitude
```

## Common Use Cases

### Case 1: Find Coordinates for Landmark

```bash
# Query
curl -H "User-Agent: ObsidianLocationNotes/0.1.0" \
  "https://nominatim.openstreetmap.org/search?q=Eiffel+Tower&format=json&limit=1"

# Response
[{
  "lat": "48.8583701",
  "lon": "2.2944813",
  "display_name": "Eiffel Tower, Avenue Anatole France, Paris, France"
}]

# Result
[48.8583701, 2.2944813]
```

### Case 2: Geocode Restaurant with City

```bash
# Query with country filter
curl -H "User-Agent: ObsidianLocationNotes/0.1.0" \
  "https://nominatim.openstreetmap.org/search?q=Dishoom+Edinburgh&countrycodes=gb&format=json&limit=3"

# Select best result based on type=restaurant
# Result
[55.9533, -3.1883]
```

### Case 3: Handle Failed Lookup

```bash
# Query returns empty array
[]

# Fallback: Leave location empty
location: null  # or omit field entirely
```

## Utility Script

A bash script for coordinate lookup is provided:

### scripts/geocode.sh

```bash
#!/bin/bash
# Geocode a location using Nominatim API
# Usage: ./geocode.sh "Location Name" [country_code]

LOCATION="$1"
COUNTRY="${2:-}"

# Build query
QUERY="https://nominatim.openstreetmap.org/search"
QUERY+="?q=$(echo "$LOCATION" | sed 's/ /+/g')"
QUERY+="&format=json&limit=5"

if [ -n "$COUNTRY" ]; then
    QUERY+="&countrycodes=$COUNTRY"
fi

# Query API (with rate limit)
sleep 1  # Respect rate limit
RESPONSE=$(curl -s -H "User-Agent: ObsidianLocationNotes/0.1.0" "$QUERY")

# Parse first result
echo "$RESPONSE" | jq -r '.[0] | "\(.lat)\n\(.lon)\n\(.display_name)"'
```

**Usage:**
```bash
./geocode.sh "Old Man of Storr"
./geocode.sh "Dishoom" "gb"
```

## Validation

Check coordinates are valid:
- ✅ Latitude: -90 to 90
- ✅ Longitude: -180 to 180
- ✅ Minimum 6 decimal places for accuracy
- ✅ Matches expected region (check display_name)

**Example validation:**
```python
def validate_coordinates(lat, lon):
    if not (-90 <= lat <= 90):
        return False
    if not (-180 <= lon <= 180):
        return False
    return True
```

## Troubleshooting

**Issue:** Empty results
**Cause:** Location not in OSM or misspelled
**Fix:** Try alternative names, add geographic context, or leave empty

**Issue:** Wrong location returned
**Cause:** Ambiguous name (e.g., "Springfield" exists in many countries)
**Fix:** Add country/region to query, check display_name

**Issue:** Rate limit error
**Cause:** Requests too frequent
**Fix:** Add sleep(1) between requests, respect 1 req/second limit

**Issue:** Coordinates seem inaccurate
**Cause:** OSM data quality or location ambiguity
**Fix:** Verify display_name matches expected location, try structured search

## Additional Resources

For detailed API documentation and advanced features:
- **`references/nominatim-api.md`** - Complete API reference
- **`examples/geocode-examples.sh`** - Working search examples
- **`scripts/geocode.sh`** - Utility script for coordinate lookup

Use these resources when working with complex queries or troubleshooting coordinate issues.

