# Ip Location Check (`abotapi/ip-location-check`) Actor

Look up geographic locations for IP addresses. Supports batch lookups with country, city, subdivision, coordinates, and timezone data.

- **URL**: https://apify.com/abotapi/ip-location-check.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Agents, Developer tools, SEO tools
- **Features:** Limited permissions
- **Stats:** 8 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## IP Location Checker: Country, City, Coordinates and Timezone for Any IP Address

IP Location Checker turns a list of IP addresses into structured geolocation records. Submit any number of IPv4 or IPv6 addresses in one run and get back country, region, city, postal code, coordinates, timezone and an approximate accuracy radius for each one, with place names in the language you choose. Read the results from the dataset, or pull them straight into your app through the API.

### Why This Scraper?

- **Batch lookups in one run.** Submit any number of IPv4 or IPv6 addresses in a single call and get one record back per address.
- **Country down to city and coordinates.** Country, region, city, postal code, latitude, longitude, timezone and an approximate accuracy radius for each address.
- **Multi-language place names.** Country, region and city names come back in the language you choose, not just English.
- **Honest failures, not silent nulls.** An address that cannot be resolved comes back with `success: false` and a plain-language `error`, instead of a record full of nulls that looks like a real match.
- **IPv4 and IPv6 side by side.** Mix both address families in the same input list.
- **No proxy or account setup needed.** Runs out of the box; there is no per-run proxy configuration to manage.
- **Fresh location data without extra work.** The location database is refreshed automatically: each run reuses a copy that is less than 24 hours old, and fetches the latest version once that copy is older.

### Use Cases

- **Ad targeting validation:** confirm ad impressions and click traffic are landing in the geographic regions you're paying to target.
- **Fraud and account-abuse checks:** flag sign-ups, orders or logins whose IP location doesn't match the address or region a user claims.
- **Content and pricing localization:** route visitors to the right language, catalog or price list based on where their IP resolves.
- **Access and compliance controls:** enforce geographic restrictions on an API or content library, or identify traffic from specific jurisdictions.
- **Analytics enrichment:** attach country, city and timezone to IP-based logs, sign-up funnels or usage analytics.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
| --- | --- |
| `ip` | `"203.0.113.42"` (the address exactly as given in `ipAddresses`) |
| `ip` (IPv6 form) | `"2001:db8::1"` |
| `country` | `"Example Country"` (localized to `language`; `null` when no country is known) |
| `countryCode` | `"ZZ"` (ISO 3166-1 alpha-2 code; `null` when `country` is `null`) |
| `subdivision` | `"Example Region"` (state, province or region; `null` when only a country level is known) |
| `city` | `"Example City"` (`null` when only a country or region level is known) |
| `postalCode` | `"00000"` (`null` for most addresses; coverage is uneven outside a handful of countries) |
| `latitude` | `12.345` (`null` when no coordinates are known) |
| `longitude` | `67.89` (`null` when no coordinates are known) |
| `timezone` | `"Etc/UTC"` (IANA timezone identifier; `null` when unknown) |
| `accuracyRadius` | `50` (approximate radius in kilometers around the coordinates; `null` when unknown) |
| `success` (`true`) | the address resolved to at least one location field (country, region, city, postal code or coordinates) |
| `success` (`false`) | the address could not be resolved; every field above is `null` on that row |
| `continent`, `continentCode` | `"Example Continent"`, `"ZZ"` (`null` when unknown) |
| `isInEuropeanUnion` | `false` (`true` when the country is an EU member; `null` when unknown) |
| `registeredCountry`, `registeredCountryCode` | the country the network is registered in, which can differ from where the address is located |
| `subdivisionCode` | `"EX"` (region code; `null` when unknown) |
| `network` | `"203.0.113.0/24"` (the CIDR range the record covers) |
| `metroCode` | `null` for most addresses (US metro code where known) |
| `asn`, `asOrganization` | `64500`, `"Example Network Ltd"` (autonomous system number and organization; `null` when the ASN database is unavailable) |
| `input`, `data` | the submitted string and the full record as one nested object |
| `changeType`, `changedFields`, `firstSeenAt`, `lastSeenAt` | incremental mode only: `NEW`, `UPDATED` or `REAPPEARED`, which fields changed, and first/last time the address was seen |
| `error` (on a successful row) | `null` |
| `error` (invalid or unmapped address) | a short message explaining the address string could not be parsed, or is private, reserved or otherwise absent from the location database |
| `error` (known network, no location) | a short message explaining the address matches a recognized network that carries no country, city or coordinate data, a known gap for some large shared address ranges |

### How to Use

1. Enter one or more **IP addresses** (IPv4 or IPv6).
2. Optionally set **Language** to get country, region and city names in that language.
3. Click **Start**.
4. Read the results from the dataset, or pull them through the API.

**Single address:**

```json
{
  "ipAddresses": ["203.0.113.42"]
}
```

**Batch lookup:**

```json
{
  "ipAddresses": ["203.0.113.10", "198.51.100.23", "192.0.2.77"]
}
```

**With a language:**

```json
{
  "ipAddresses": ["203.0.113.42", "198.51.100.23"],
  "language": "ja"
}
```

**IPv6 addresses:**

```json
{
  "ipAddresses": ["2001:db8::1", "2001:db8::a2"]
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/ip-location-check").call(run_input={"ipAddresses": ["203.0.113.42"]})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["ip"], item["country"], item["city"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/ip-location-check').call({ ipAddresses: ['203.0.113.42'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Batching and freshness

There is no fixed cap on how many addresses you can submit in one run; very large batches (over 10,000 addresses) automatically get more memory. Blank entries in the list are skipped. Every other entry produces exactly one record, including addresses that fail, except addresses skipped by **Resume from a previous run** (already in that run's dataset) and, in incremental mode, addresses whose data did not change. The location database copy is reused while it is less than 24 hours old and fetched again after that, so location data is never more than about a day behind the latest published version.

### Send results into your apps (MCP connectors)

Optionally pipe the returned records into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the lookups: the Apify dataset is never changed and nothing extra is charged.

1. Authorize a connector once under Apify, Settings, API & Integrations (Notion, Linear, Airtable, or Apify).
2. Select it in the "Pipe results into your apps" input field (`mcpConnectors`).
3. For Notion, also set `notionParentPageUrl` to the page under which result pages are created. `maxNotifyListings` caps how many records are written per connector (default 50).

Only records actually returned in the run are exported (in incremental mode, unchanged addresses are not). Leave `mcpConnectors` empty to skip.

#### Views and run summary

The dataset has two views: **IP Locations** (a compact table of address, country, region, city, coordinates, timezone and success) and **Full detail** (every field, including network, ASN and change tracking). Runs with more than one address also store an `OUTPUT` record in the key-value store with `total`, `successful`, `failed` and `unchangedSuppressed` counts.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `ipAddresses` | array | `8.8.8.8`, `81.2.69.142`, `2a02:26f0:1700::1` | List of IP addresses to look up, IPv4 or IPv6. If you leave this field out (for example in an API call), these three sample addresses are looked up and returned, so always send your own list. |
| `resumeFromRunId` | string | (empty) | Run ID of an interrupted run to continue; addresses already in that run's dataset are skipped. |
| `incrementalMode` | boolean | `false` | Return only new or changed addresses on repeated runs. |
| `ignoreFieldsForChanges` | array | (empty) | Field names that should not count as a change in incremental mode. |
| `mcpConnectors` | array | (empty) | Connectors to pipe returned records into. |
| `notionParentPageUrl` | string | (empty) | Notion parent page, Notion connector only. |
| `maxNotifyListings` | integer | `50` | Maximum records exported per connector. |
| `language` | string | `en` | Language for place names, as an ISO 639-1 code (for example `en`, `es`, `fr`, `de`, `ja`, `zh-CN`). Falls back to English when a name isn't available in the requested language. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live record.

```json
{
  "ip": "203.0.113.42",
  "country": "Example Country",
  "countryCode": "ZZ",
  "subdivision": "Example Region",
  "city": "Example City",
  "postalCode": "00000",
  "latitude": 12.345,
  "longitude": 67.89,
  "timezone": "Etc/UTC",
  "accuracyRadius": 50,
  "continent": "Example Continent",
  "continentCode": "ZZ",
  "isInEuropeanUnion": false,
  "registeredCountry": "Example Country",
  "registeredCountryCode": "ZZ",
  "subdivisionCode": "EX",
  "network": "203.0.113.0/24",
  "metroCode": null,
  "asn": 64500,
  "asOrganization": "Example Network Ltd",
  "success": true,
  "error": null,
  "input": "203.0.113.42",
  "data": { "ip": "203.0.113.42", "country": "Example Country", "asn": 64500 }
}
```

### Plan Requirement

This actor does not use a proxy connection: lookups run against a location database loaded inside the run, so there is no proxy to configure. If the database download fails and an older cached copy exists in your account, the run logs a warning and uses that older copy. If it fails and no cached copy exists (for example on a first-ever run), the run fails with the message "Could not download the IP location database and no cached copy is available. Please retry later." The default memory is enough for typical batches and is raised automatically for very large ones.

### FAQ

#### How much does it cost?

You pay a small fee per run start plus a fee per record returned. Every address you submit produces one record, including lookups that come back with `success: false` (except addresses skipped by resume, or unchanged in incremental mode, which are not returned and not billed), so remove addresses you don't need before the run. The **Pricing** tab shows the current rates.

#### Is it legal to look up IP address locations?

The actor matches each address against a published location database; it does not contact or access the addresses you submit. You are responsible for how you use the results: IP addresses can count as personal data in some places, so follow the privacy laws that apply to you.

#### Can I check the same addresses on a schedule?

Yes. Save your input as a task and run it from the **Schedules** tab. Each run looks up every address again against the current database copy, so you can track when an address's location changes.

Turn on **Incremental changes for scheduled runs** to get only what changed. Each address is tracked together with its language. The first run returns every address as `NEW`; later runs return only `NEW` and `UPDATED` addresses. An address is `UPDATED` when any of these fields changes: `country`, `countryCode`, `subdivision`, `city`, `postalCode`, `latitude`, `longitude`, `timezone`, `accuracyRadius`, `success`, `error`, `continent`, `continentCode`, `isInEuropeanUnion`, `registeredCountry`, `registeredCountryCode`, `subdivisionCode`, `network`, `metroCode`, `asn` and `asOrganization`. `changedFields` names exactly which of them changed. The `input` and `data` fields are never compared. A monthly rename of an ASN organization in the database therefore counts as a change. If the ASN database is temporarily unavailable, the remembered `asn` and `asOrganization` are kept, so that is not reported as a change. Unchanged addresses are not returned and therefore not billed, since billing applies per returned record. Add field names under **Ignore fields when detecting changes (incremental mode only)** to stop them counting as changes; they are still returned. Addresses you remove from the list are not reported as expired. Use **Resume from a previous run** to continue one interrupted run instead; it skips addresses already in that run's dataset. Tracking state is kept in a small named storage in your account.

#### Why did my run finish with an empty dataset?

Either the **IP addresses** list was empty or held only blank entries (the run logs a warning and ends without looking anything up), or **Incremental changes for scheduled runs** was on and no address changed since the last run, or **Resume from a previous run** pointed at a run that already covered every address. Addresses that can't be located never make the run fail: each one still returns a record with `success: false`. A run only fails outright when the location database itself can't be loaded; run it again in a few minutes.

#### Does this include proxy, VPN or fraud-risk detection?

No. This actor returns geographic location data (country, region, city, postal code, coordinates, timezone, continent, EU membership, network range) plus the autonomous system number and organization. The free databases it uses carry no privacy (proxy, VPN, hosting) or company data, so those fields are not offered and never guessed. It does not flag whether an address is a proxy, VPN, hosting or datacenter address, and it carries no other reputation or risk signal.

#### What do `input` and `data` contain?

`input` is the exact string you submitted, before whitespace is trimmed. `data` repeats the full lookup record as one nested object, for pipelines that expect a single object per address. `asn` and `asOrganization` are `null` when the ASN database is temporarily unavailable (in incremental mode the remembered values are kept instead). The databases are cached in a small named storage in your account (about 31 MB in total, kept between runs).

#### Can it look up my own IP address automatically?

No. There is no auto-detect option. List the address or addresses you want to look up in **IP addresses**.

#### Why did a lookup come back with success: false and every location field null?

Three cases produce this: the address string isn't a valid IPv4 or IPv6 address, the address is private, reserved or otherwise not covered by the location database, or the address matches a known network that the database has no country, city or coordinate data for. Check that record's `error` field for which one applies.

#### Can I use this actor with AI agents or MCP?

Yes. Call it from your agent framework's tool interface, or through the Apify API or client shown above, and feed the returned JSON straight into your prompt or pipeline.

### 🔗 Want more SEO data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>🤖 <a href="https://apify.com/abotapi/doc-to-markdown"><b>Doc To Markdown</b></a><br>Convert documents (PDF, Word, PowerPoint, Excel, HTML, images) to clean Markdown...</td><td>📇 <a href="https://apify.com/abotapi/yellow-pages-au-scraper"><b>Yellow Pages AU</b></a><br>Scrape business listings from Yellow Pages Australia by type and location. Get names...</td></tr>
<tr><td>✈️ <a href="https://apify.com/abotapi/fuel-prices-anz-scraper"><b>Fuel Prices AU Scraper</b></a><br>Scrapes petrol and fuel prices data across Australia and New Zealand. Search by address...</td><td>🧩 <a href="https://apify.com/abotapi/yandex-maps-scraper"><b>Yandex Maps Scraper</b></a><br>Scrape Yandex Maps businesses and places by keyword or URL for lead generation, research...</td></tr>
<tr><td>🛒 <a href="https://apify.com/abotapi/ikea-scraper"><b>IKEA Scraper</b></a><br>Scrape IKEA products across 50+ markets. Extract names, prices, currencies, ratings, full...</td><td>🛒 <a href="https://apify.com/abotapi/dealroom-co-scraper"><b>Dealroom.net Scraper</b></a><br>Scrape Dealroom.net market maps, company lookup results, live signals, and newly founded...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/ip-location-check/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `ipAddresses` (type: `array`):

List of IP addresses to look up (IPv4 or IPv6)

## `language` (type: `string`):

Language for location names (ISO 639-1 code)

## `resumeFromRunId` (type: `string`):

Optional. ID of a previous run of this actor (or of its dataset). Addresses already in that dataset are skipped, so this run returns only the remaining ones. For recurring monitoring use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for scheduled runs. Each address is tracked together with its language. The first run returns every address as NEW; later runs return only NEW and UPDATED addresses, and unchanged addresses are not returned and not billed. An address counts as UPDATED when any of these fields changes: country, countryCode, subdivision, city, postalCode, latitude, longitude, timezone, accuracyRadius, success, error, continent, continentCode, isInEuropeanUnion, registeredCountry, registeredCountryCode, subdivisionCode, network, metroCode, asn and asOrganization. The input and data fields are not compared. If the ASN database is temporarily unavailable, the remembered asn and asOrganization are kept so that is not reported as a change. Every returned row gets changeType, changedFields, firstSeenAt and lastSeenAt. Fields listed under 'Ignore fields' below never count as changes though they are still returned. Addresses you stop submitting are not reported as expired. To continue one interrupted run instead, use Resume above.

## `ignoreFieldsForChanges` (type: `array`):

Output field names that should NOT make an address count as UPDATED, for example accuracyRadius or postalCode. By default every field counts. Ignored fields are still returned in the output.

## `mcpConnectors` (type: `array`):

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write or digest. Leave empty to skip; never changes the dataset output.

## `notionParentPageUrl` (type: `string`):

URL or id of the Notion page under which result pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on results written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "ipAddresses": [
    "8.8.8.8",
    "81.2.69.142",
    "2a02:26f0:1700::1"
  ],
  "language": "en",
  "incrementalMode": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset containing geolocation results for all queried IP addresses.

## `overview` (type: `string`):

Compact table: IP, country, region, city, coordinates, timezone.

## `detail` (type: `string`):

All fields including continent, EU flag, network CIDR and ASN.

## `summary` (type: `string`):

Multi-IP runs: total, successful and failed counts.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "ipAddresses": [
        "8.8.8.8",
        "81.2.69.142",
        "2a02:26f0:1700::1"
    ],
    "language": "en",
    "incrementalMode": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/ip-location-check").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "ipAddresses": [
        "8.8.8.8",
        "81.2.69.142",
        "2a02:26f0:1700::1",
    ],
    "language": "en",
    "incrementalMode": False,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/ip-location-check").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "ipAddresses": [
    "8.8.8.8",
    "81.2.69.142",
    "2a02:26f0:1700::1"
  ],
  "language": "en",
  "incrementalMode": false
}' |
apify call abotapi/ip-location-check --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/ip-location-check"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/xCeVH1l8vytE1IUEt/builds/K0Nldk83vYJRhyxZG/openapi.json
