A zero-dependency, frontend-optimized JavaScript SDK for the OpenCage Geocoding API. Built for modern browsers with comprehensive TypeScript definitions and enterprise-grade features.
- π Zero Dependencies - Pure JavaScript with no external dependencies
- π― Frontend Optimized - Built specifically for browser environments
- πΎ Intelligent Caching - Memory-based LRU cache with TTL support
- β‘ Debounced Requests - Automatic rate limiting for user input scenarios
- π Retry Logic - Automatic retry with exponential backoff
- π Usage Statistics - Built-in request tracking and analytics
- π‘οΈ Input Validation - Comprehensive parameter validation and sanitization
- π Multiple Formats - ES6 modules, CommonJS, and UMD builds
- π± Mobile Friendly - Optimized for mobile and low-bandwidth connections
- π§ TypeScript Ready - Full TypeScript definitions included
npm install @digiphilo/opencage-javascriptimport OpenCageClient from '@digiphilo/opencage-javascript'
// Initialize client
const client = new OpenCageClient({
apiKey: 'YOUR_API_KEY'
})
// Forward geocoding (address β coordinates)
const forwardResult = await client.geocode('1600 Pennsylvania Avenue, Washington, DC')
console.log(forwardResult.results[0].geometry) // { lat: 38.8976633, lng: -77.0365739 }
// Reverse geocoding (coordinates β address)
const reverseResult = await client.reverseGeocode(38.8976633, -77.0365739)
console.log(reverseResult.results[0].formatted) // "White House, ..."
// Get rate limit info
const rateInfo = client.getRateLimitInfo()
console.log(`${rateInfo.remaining}/${rateInfo.limit} requests remaining`)<script src="https://unpkg.com/@digiphilo/opencage-javascript/dist/index.umd.min.js"></script>
<script>
const client = new OpenCage.OpenCageClient({
apiKey: 'YOUR_API_KEY'
})
client.geocode('London, UK').then(result => {
console.log(result.results[0].formatted)
})
</script>const client = new OpenCageClient({
apiKey: 'YOUR_API_KEY', // Required: Your OpenCage API key
timeout: 10000, // Request timeout in milliseconds (default: 10000)
retryAttempts: 3, // Number of retry attempts (default: 3)
retryDelay: 1000, // Base retry delay in milliseconds (default: 1000)
cache: true, // Enable caching (default: true)
cacheSize: 100, // Maximum cache entries (default: 100)
cacheTtl: 300000, // Cache TTL in milliseconds (default: 5 minutes)
debounce: 300, // Debounce delay for rapid requests (default: 300ms)
baseUrl: 'https://api.opencagedata.com/geocode/v1' // API base URL
})Convert addresses and place names to coordinates:
// Simple string query
const result = await client.geocode('Paris, France')
// Advanced query with options
const result = await client.geocode({
query: '10 Downing Street',
country: 'gb', // Restrict to UK
language: 'en', // Results in English
limit: 5, // Maximum results
bounds: [51.3, -0.2, 51.6, 0.1], // Bounding box [minlat, minlng, maxlat, maxlng]
proximity: [51.5074, -0.1278], // Bias results near this point
minConfidence: 7, // Minimum confidence score
noAnnotations: true, // Skip additional metadata
abbrv: true // Use abbreviated results
})
// Debounced geocoding (great for search-as-you-type)
const result = await client.debouncedGeocode('New Y') // Won't execute immediately
const result = await client.debouncedGeocode('New Yo') // Cancels previous
const result = await client.debouncedGeocode('New York') // Executes after delayConvert coordinates to addresses:
// Basic reverse geocoding
const result = await client.reverseGeocode(40.7128, -74.0060)
// With options
const result = await client.reverseGeocode(40.7128, -74.0060, {
language: 'es', // Results in Spanish
limit: 1, // Only one result
minConfidence: 5, // Minimum confidence
noAnnotations: true // Skip metadata
})
// Debounced reverse geocoding
const result = await client.debouncedReverseGeocode(lat, lng, options)Process multiple queries efficiently:
const queries = [
'London, UK',
'Paris, France',
{ query: 'Tokyo, Japan', language: 'ja' }
]
const { results, errors } = await client.batchGeocode(queries, (progress) => {
console.log(`Progress: ${progress.percentage}% (${progress.completed}/${progress.total})`)
if (progress.errors.length > 0) {
console.log('Errors:', progress.errors)
}
})
// Process results
results.forEach((result, index) => {
if (result) {
console.log(`Query ${index}:`, result.results[0].formatted)
} else {
console.log(`Query ${index} failed`)
}
})Control caching behavior:
// Clear all cached results
client.clearCache()
// Get cache statistics
const stats = client.getCacheStats()
console.log(`Cache: ${stats.size}/${stats.maxSize} entries, ${stats.hitRate}% hit rate`)
// Disable cache temporarily
client.updateOptions({ cache: false })
// Re-enable with different settings
client.updateOptions({
cache: true,
cacheSize: 200,
cacheTtl: 600000 // 10 minutes
})Track API usage and performance:
const stats = client.getStats()
console.log({
totalRequests: stats.totalRequests,
errors: stats.errors,
cacheHits: stats.cacheHits,
cacheMisses: stats.cacheMisses,
lastRequest: stats.lastRequest,
rateLimit: stats.rateLimit
})
// Reset statistics
client.resetStats()
// Check remaining API quota
const rateInfo = client.getRateLimitInfo()
if (rateInfo.remaining < 100) {
console.warn('Low API quota remaining:', rateInfo.remaining)
}Comprehensive error handling with context:
try {
const result = await client.geocode('invalid query')
} catch (error) {
console.error('Geocoding failed:', {
message: error.message,
code: error.code,
status: error.status,
operation: error.operation, // 'forward' or 'reverse'
context: error.context, // Original query/parameters
timestamp: error.timestamp,
rateLimitRemaining: error.rateLimitRemaining
})
// Handle specific error types
if (error.code === 402) {
console.error('Quota exceeded - upgrade your plan')
} else if (error.code === 401) {
console.error('Invalid API key')
} else if (error.code === 408) {
console.error('Request timeout - try again')
}
}Verify your API key:
try {
const isValid = await client.validateApiKey()
if (isValid) {
console.log('API key is valid')
} else {
console.error('Invalid API key')
}
} catch (error) {
console.error('Could not validate API key:', error.message)
}The SDK includes helpful utilities for common tasks:
import {
formatCoordinates,
calculateDistance,
getBestResult,
isWithinBounds,
COUNTRY_CODES,
LANGUAGE_CODES
} from '@geonot/javascript-sdk'
// Format coordinates for display
const formatted = formatCoordinates(40.7128, -74.0060, 4) // "40.7128, -74.0060"
// Calculate distance between points (in kilometers)
const distance = calculateDistance(40.7128, -74.0060, 34.0522, -118.2437) // ~3944 km
// Get best result from multiple results
const best = getBestResult(results) // Returns result with highest confidence
// Check if coordinates are within bounds
const inBounds = isWithinBounds(40.7128, -74.0060, [40, -75, 41, -73]) // true
// Use predefined constants
const result = await client.geocode({
query: 'Berlin',
country: COUNTRY_CODES.DE,
language: LANGUAGE_CODES.GERMAN
})const client = new OpenCageClient({
apiKey: 'YOUR_API_KEY',
timeout: 15000, // 15 second timeout
retryAttempts: 5, // More aggressive retries
retryDelay: 2000, // Longer base delay
userAgent: 'MyApp/1.0.0' // Custom user agent
})// High-performance configuration
const client = new OpenCageClient({
apiKey: 'YOUR_API_KEY',
cache: true,
cacheSize: 500, // Larger cache
cacheTtl: 600000, // 10 minute cache
debounce: 150, // Faster debouncing
timeout: 5000 // Aggressive timeout
})
// Low-bandwidth configuration
const client = new OpenCageClient({
apiKey: 'YOUR_API_KEY',
timeout: 20000, // Patient timeout
retryAttempts: 1, // Fewer retries
cache: true,
cacheSize: 50 // Smaller cache
})// Update configuration without creating new instance
client.updateOptions({
timeout: 8000,
cacheSize: 200,
debounce: 500
})
// Get current configuration
const config = client.getOptions()
console.log('Current timeout:', config.timeout)- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
- iOS Safari 12+
- Android Chrome 60+
For older browsers, use the UMD build with appropriate polyfills.
- ES Module: ~8KB gzipped
- UMD Build: ~10KB gzipped
- Minified UMD: ~7KB gzipped
- 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
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build the library
npm run build
# Lint code
npm run lint
# Format code
npm run formatThis project is licensed under the MIT License - see the LICENSE file for details.
- OpenCage Data for providing the excellent geocoding API
- Built with modern JavaScript standards and best practices
- Inspired by the needs of frontend developers working with location data
- π§ Email: support@geonot.com
- π Issues: GitHub Issues
- π Documentation: Full API Documentation
Made with β€οΈ by Rome Stone