npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@digiphilo/opencage-javascript

v1.1.0

Published

JavaScript SDK for OpenCage Geocoding API - Frontend optimized with zero dependencies

Readme

OpenCage JavaScript SDK

NPM Version Bundle Size License Test Coverage

A zero-dependency, frontend-optimized JavaScript SDK for the OpenCage Geocoding API. Built for modern browsers with comprehensive TypeScript definitions and enterprise-grade features.

✨ 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

🚀 Quick Start

Installation

npm install @digiphilo/opencage-javascript

Basic Usage

import 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`)

Browser Usage (UMD)

<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>

📚 Documentation

Configuration Options

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
})

Forward Geocoding

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 delay

Reverse Geocoding

Convert 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)

Batch Geocoding

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`)
  }
})

Cache Management

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
})

Statistics and Monitoring

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)
}

Error Handling

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')
  }
}

API Key Validation

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)
}

🛠️ Utilities

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
})

🎛️ Advanced Configuration

Custom HTTP Configuration

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
})

Performance Tuning

// 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
})

Runtime Configuration Updates

// 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)

🔧 Browser Compatibility

  • Chrome 60+
  • Firefox 55+
  • Safari 12+
  • Edge 79+
  • iOS Safari 12+
  • Android Chrome 60+

For older browsers, use the UMD build with appropriate polyfills.

📊 Bundle Size

  • ES Module: ~8KB gzipped
  • UMD Build: ~10KB gzipped
  • Minified UMD: ~7KB gzipped

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📋 Development

# 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 format

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • 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

📞 Support


Made with ❤️ by Rome Stone