{"_id":"@apimonster/ip-api","name":"@apimonster/ip-api","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@apimonster/ip-api","version":"1.0.0","description":"Simple client for real-time IPV4 and IPV6 lookup and validation. Over 99% of IP addresses covered Worldwide. Over 30 distinct attributes for each request.","main":"index.js","scripts":{"test":"node test.js"},"engines":{"node":">=18.0.0"},"keywords":["ip lookup","ip location","ip lookup","ip geolocation","ip","enrichment","geolocation","api","isp","ip-lookup","timezone","network","bestipapi"],"author":{"name":"API Monster"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/apimonstercloud/ip-api.git"},"bugs":{"url":"https://github.com/apimonstercloud/ip-api/issues"},"homepage":"https://github.com/apimonstercloud/ip-api#readme","_id":"@apimonster/ip-api@1.0.0","_nodeVersion":"23.9.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-ZDCbwe8ntyvbcpVJkSKQp05CiLFx+nDUyS99sV0mGlduOvtzSKRJtHLB9BXLEBZyQInqmEF0nfWvLqbpaqEpPg==","shasum":"ee6710d040cc245f7d6bec4d901420c9d27dddea","tarball":"https://registry.npmjs.org/@apimonster/ip-api/-/ip-api-1.0.0.tgz","fileCount":3,"unpackedSize":14091,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFzi3JQy9b5JMrMZPUIhzjl42CxdUFfh4lpvBk1eS4QPAiBxONMIHBU9GJg9V8rhLUmgN6XSSGuPyPHkrFM/f5ibeQ=="}]},"_npmUser":{"name":"apimonster","email":"releases@apimonster.cloud"},"directories":{},"maintainers":[{"name":"apimonster","email":"releases@apimonster.cloud"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ip-api_1.0.0_1754434703303_0.5031266021602976"},"_hasShrinkwrap":false}},"time":{"created":"2025-08-05T22:58:23.197Z","1.0.0":"2025-08-05T22:58:23.488Z","modified":"2025-08-05T22:58:23.745Z"},"maintainers":[{"name":"apimonster","email":"releases@apimonster.cloud"}],"description":"Simple client for real-time IPV4 and IPV6 lookup and validation. Over 99% of IP addresses covered Worldwide. Over 30 distinct attributes for each request.","homepage":"https://github.com/apimonstercloud/ip-api#readme","keywords":["ip lookup","ip location","ip lookup","ip geolocation","ip","enrichment","geolocation","api","isp","ip-lookup","timezone","network","bestipapi"],"repository":{"type":"git","url":"git+https://github.com/apimonstercloud/ip-api.git"},"author":{"name":"API Monster"},"bugs":{"url":"https://github.com/apimonstercloud/ip-api/issues"},"license":"MIT","readme":"# IP API\n\nSimple, lightweight client for the IP API enrichment service. Get comprehensive geolocation, ISP, timezone, and network data for any IP address with just one line of code.\n\n## Installation\n\n```bash\nnpm install @apimonster/ip-api\n```\n\n## Getting Started\n\n1. **Get your API key**: Create a free account at [bestipapi.com/register](https://bestipapi.com/register) to get your API key\n2. **Install the package**: `npm install @apimonster/ip-api`\n3. **Start using**: Configure your API key and make calls\n\n## Quick Start\n\n```javascript\nconst IPMonster = require('@apimonster/ip-api');\n\n// Configure your API key (do this once)\nIPMonster.configure({ apiKey: 'your-api-key-here' });\n\n// Validate IP addresses\nconsole.log(IPMonster.validate('192.168.1.1')); // true\nconsole.log(IPMonster.validate('invalid-ip')); // false\n\n// Look up IP enrichment data\nconst data = await IPMonster.lookup('8.8.8.8');\nconsole.log(data);\n```\n\n## Configuration\n\n### Method 1: Configure programmatically\n```javascript\nIPMonster.configure({\n  apiKey: 'your-api-key',\n  baseUrl: 'https://api.bestipapi.com/query', // optional\n  timeout: 5000 // optional, in milliseconds\n});\n```\n\n### Method 2: Environment variable\n```bash\nexport IPMONSTER_API_KEY=your-api-key\n```\n\n## API Reference\n\n### `IPMonster.validate(ip)`\n\nValidates IP address format (both IPv4 and IPv6).\n\n```javascript\nIPMonster.validate('192.168.1.1');    // true\nIPMonster.validate('2001:db8::1');    // true\nIPMonster.validate('invalid');        // false\n```\n\n**Parameters:**\n- `ip` (string): IP address to validate\n\n**Returns:** `boolean`\n\n### `IPMonster.lookup(ip, [options])`\n\nLook up enrichment data for a single IP address.\n\n```javascript\nconst result = await IPMonster.lookup('8.8.8.8');\n\n// Example response:\n{\n  \"ip_address\": \"8.8.8.8\",\n  \"ip_type\": \"IPv4\",\n  \"network\": \"8.8.8.0/24\",\n  \"latitude\": 37.751,\n  \"longitude\": -97.822,\n  \"postal_code\": null,\n  \"accuracy_radius\": 1000,\n  \"city_name\": null,\n  \"country_name\": \"United States\",\n  \"country_iso_code\": \"US\",\n  \"subdivision_1_name\": null,\n  \"subdivision_1_iso_code\": null,\n  \"subdivision_2_name\": null,\n  \"continent_name\": \"North America\",\n  \"continent_code\": \"NA\",\n  \"time_zone\": \"America/Chicago\",\n  \"time_zone_offset\": -5,\n  \"is_in_european_union\": false,\n  \"currency_code\": \"USD\",\n  \"currency_name\": \"US Dollar\",\n  \"primary_language_code\": \"EN\",\n  \"primary_language_name\": \"English\",\n  \"isp\": \"Google LLC\",\n  \"isp_name\": \"Google LLC\",\n  \"asn\": 15169,\n  \"aso\": \"GOOGLE\",\n  \"mobile_country_code\": null,\n  \"mobile_network_code\": null,\n  \"tor_detected\": false\n}\n```\n\n**Parameters:**\n- `ip` (string): IP address to lookup\n- `options` (object, optional): Request options\n  - `apiKey` (string): API key override\n  - `baseUrl` (string): API base URL override\n  - `timeout` (number): Request timeout in milliseconds\n  - `output` (string): Response format ('json', 'xml', 'plain')\n\n**Returns:** `Promise<Object>` - Enrichment data\n\n### `IPMonster.batchLookup(ips, [options])`\n\nLook up multiple IP addresses in a single request (maximum 300 IPs).\n\n```javascript\nconst results = await IPMonster.batchLookup([\n  '8.8.8.8',\n  '1.1.1.1',\n  '192.168.1.1'\n]);\n\n// Example response:\n{\n  \"results\": [\n    {\n      \"ip_address\": \"8.8.8.8\",\n      \"ip_type\": \"IPv4\",\n      \"country_name\": \"United States\",\n      \"city_name\": null,\n      // ... full enrichment data\n    },\n    {\n      \"ip_address\": \"192.168.1.1\",\n      \"error\": \"No location data found for this IP address\",\n      \"error_code\": \"NOT_FOUND\"\n    }\n  ],\n  \"summary\": {\n    \"total_processed\": 3,\n    \"successful\": 2,\n    \"errors\": 1,\n    \"skipped\": 0\n  }\n}\n```\n\n**Parameters:**\n- `ips` (string[]): Array of IP addresses (max 300)\n- `options` (object, optional): Same as lookup options plus:\n  - `output` (string): Response format ('json', 'xml', 'text', 'plain')\n\n**Returns:** `Promise<Object>` - Object with results array and summary\n\n## Response Fields\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `ip_address` | string | The queried IP address |\n| `ip_type` | string | IP version (IPv4 or IPv6) |\n| `network` | string | Network range in CIDR notation |\n| `latitude` | number | Geographic latitude coordinate |\n| `longitude` | number | Geographic longitude coordinate |\n| `postal_code` | string\\|null | Postal/ZIP code |\n| `accuracy_radius` | number | Accuracy radius in kilometers |\n| `city_name` | string\\|null | City name |\n| `country_name` | string | Country name |\n| `country_iso_code` | string | ISO 3166-1 alpha-2 country code |\n| `subdivision_1_name` | string\\|null | State/province/region name |\n| `subdivision_1_iso_code` | string\\|null | State/province/region ISO code |\n| `subdivision_2_name` | string\\|null | Secondary subdivision name |\n| `continent_name` | string | Continent name |\n| `continent_code` | string | Two-letter continent code |\n| `time_zone` | string | IANA timezone identifier |\n| `time_zone_offset` | number | UTC timezone offset in hours |\n| `is_in_european_union` | boolean | Whether IP is in European Union |\n| `currency_code` | string | ISO 4217 currency code |\n| `currency_name` | string | Currency name |\n| `primary_language_code` | string | ISO 639-1 language code |\n| `primary_language_name` | string | Primary language name |\n| `isp` | string | Internet Service Provider name |\n| `asn` | number | Autonomous System Number |\n| `aso` | string | Autonomous System Organization |\n| `mobile_country_code` | string\\|null | Mobile Country Code (for cellular networks) |\n| `mobile_network_code` | string\\|null | Mobile Network Code (for cellular networks) |\n| `tor_detected` | boolean | Whether the IP is associated with Tor network |\n\n## Error Handling\n\nThe package throws descriptive errors for various scenarios:\n\n```javascript\ntry {\n  const result = await IPMonster.lookup('8.8.8.8');\n} catch (error) {\n  console.error(error.message);\n  // Possible errors:\n  // - \"Invalid IP address format\"\n  // - \"API key not configured\"\n  // - \"Request timeout after 5000ms\"\n  // - \"IP API API error: Invalid API key\"\n  // - \"IP API API error: Rate limit exceeded\"\n}\n```\n\n## Requirements\n\n- Node.js 18+ (for built-in fetch support)\n- IP API API key\n\n## Examples\n\n### Basic Usage\n```javascript\nconst IPMonster = require('ipmonster');\n\nIPMonster.configure({ apiKey: process.env.IPMONSTER_API_KEY });\n\nasync function checkIP(ip) {\n  if (!IPMonster.validate(ip)) {\n    console.log('Invalid IP address');\n    return;\n  }\n  \n  try {\n    const data = await IPMonster.lookup(ip);\n    console.log(`${ip} is from ${data.city_name || 'Unknown City'}, ${data.country_name}`);\n    console.log(`ISP: ${data.isp}, Timezone: ${data.time_zone}`);\n  } catch (error) {\n    console.error('Lookup failed:', error.message);\n  }\n}\n\ncheckIP('8.8.8.8');\n```\n\n### Batch Processing\n```javascript\nasync function analyzeIPs(ipList) {\n  const validIPs = ipList.filter(ip => IPMonster.validate(ip));\n  \n  if (validIPs.length === 0) {\n    console.log('No valid IPs found');\n    return;\n  }\n  \n  try {\n    const response = await IPMonster.batchLookup(validIPs);\n    \n    console.log(`Processed ${response.summary.total_processed} IPs`);\n    console.log(`Successful: ${response.summary.successful}, Errors: ${response.summary.errors}`);\n    \n    response.results.forEach(result => {\n      if (result.error) {\n        console.log(`${result.ip_address}: Error - ${result.error}`);\n      } else {\n        console.log(`${result.ip_address}: ${result.country_name} (${result.isp})`);\n      }\n    });\n  } catch (error) {\n    console.error('Batch lookup failed:', error.message);\n  }\n}\n\nanalyzeIPs(['8.8.8.8', '1.1.1.1', '192.168.1.1']);\n```\n\n### Custom Output Format\n```javascript\n// Get XML response\nconst xmlResult = await IPMonster.lookup('8.8.8.8', { output: 'xml' });\n\n// Get plain text response  \nconst plainResult = await IPMonster.lookup('8.8.8.8', { output: 'plain' });\n```\n\n### Custom Configuration\n```javascript\n// Use custom timeout and base URL\nconst result = await IPMonster.lookup('8.8.8.8', {\n  timeout: 10000,\n  baseUrl: 'https://custom-api.bestipapi.com/query'\n});\n```\n\n### Processing Large Datasets\n```javascript\nasync function processLargeIPList(allIPs) {\n  const batchSize = 300; // API maximum\n  const results = [];\n  \n  for (let i = 0; i < allIPs.length; i += batchSize) {\n    const batch = allIPs.slice(i, i + batchSize);\n    const validBatch = batch.filter(ip => IPMonster.validate(ip));\n    \n    if (validBatch.length > 0) {\n      try {\n        const response = await IPMonster.batchLookup(validBatch);\n        results.push(...response.results);\n        \n        // Add delay to respect rate limits\n        await new Promise(resolve => setTimeout(resolve, 1000));\n      } catch (error) {\n        console.error(`Batch ${i / batchSize + 1} failed:`, error.message);\n      }\n    }\n  }\n  \n  return results;\n}\n```\n\n## License\n\nMIT","readmeFilename":"README.md","_rev":"1-cd8b90c64d0704e2f01610480450af4a"}