# GeoNames Place Records Scraper (`automation-lab/geonames-place-record-export`) Actor

Search public GeoNames place records and export identifiers, coordinates, administrative geography, feature descriptions and available population for location-reference enrichment.

- **URL**: https://apify.com/automation-lab/geonames-place-record-export.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.30 / 1,000 place exporteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

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

## GeoNames Place Records Scraper

Enrich recurring location-name lists with **geonames place records**: stable GeoNames IDs, decimal coordinates, administrative geography, feature descriptions and available population. Search the public GeoNames website without a GeoNames API account. Results are bounded snapshots, not a complete database download.

### What does it do?

Submit one or more place-name searches, optionally restricted to a country. The Actor reads anonymous search pages, follows pagination and exports one row per unique GeoNames identifier. It does not fetch private records, use authenticated webservices or download the full corpus.

### Who is it for?

Data engineers can join location reference tables on GeoNames IDs. Analysts can distinguish identically named places using country and administrative context. Operations teams can periodically refresh a small set of location candidates before downstream review.

### Why use it?

- No GeoNames API registration or credential setup.
- Numeric coordinates and identifiers instead of raw HTML.
- Country validation on every accepted record.
- Run-wide ID deduplication and explicit coverage stop reasons.
- Search provenance retained for manual review.

Native GeoNames search is relevance-based. It can match alternate names or related nearby places. Do not treat the first result as a guaranteed exact geocode.

### Getting started

1. Enter `Paris` in **Place name searches**.
2. Set **Country code** to `FR`.
3. Choose a small **Maximum unique places**, such as 10.
4. Run the Actor and inspect the dataset and run summary.
5. Download JSON, CSV or Excel using Apify's dataset export options.

```json
{"queries":["Paris"],"countryCode":"FR","maxItems":10,"maxPagesPerQuery":5}
```

### Inputs

| Field | Meaning |
|---|---|
| `queries` | Required array of 1–20 nonempty strings, each at most 200 characters. Surrounding whitespace is trimmed; duplicate strings are removed. Queries run in order. |
| `countryCode` | Optional two-letter GeoNames country code, converted to uppercase. Empty means worldwide. Returned country codes are checked against this filter. |
| `maxItems` | Global unique-place limit across all queries; default 100, range 1–1000. Zero/unlimited is unsupported. |
| `maxPagesPerQuery` | Per-query page cap including the first page; default 5, range 1–20. Observed search pages contain up to 50 records. |

The global limit can stop collection before later queries run. Results shared by multiple queries appear once, attributed to the first query that emitted them. Invalid inputs fail rather than being silently ignored.

### GeoNames place records output

| Field | Meaning |
|---|---|
| `geonamesId` | Stable numeric source identifier |
| `name` | Displayed place name |
| `latitude`, `longitude` | Decimal coordinates |
| `countryCode`, `countryName` | Displayed country identity |
| `administrativeRegion` | Region displayed beside the country, or null |
| `administrativeHierarchy` | Administrative names in source order; empty if absent |
| `featureDescription` | Human-readable source feature description |
| `population` | Displayed numeric population, or null if unavailable |
| `url` | Canonical GeoNames place link |
| `query`, `searchUrl` | First matching query and search-page provenance |
| `scrapedAt` | UTC retrieval timestamp, not source modification time |

A representative public-source record:

```json
{
  "geonamesId": 2988507,
  "name": "Paris",
  "latitude": 48.85341,
  "longitude": 2.3488,
  "countryCode": "FR",
  "countryName": "France",
  "administrativeRegion": "Île-de-France",
  "administrativeHierarchy": ["Paris Department", "Paris", "Paris"],
  "featureDescription": "capital of a political entity",
  "population": 2138551,
  "url": "https://www.geonames.org/2988507/paris.html",
  "query": "Paris",
  "searchUrl": "https://www.geonames.org/search.html?q=Paris&country=FR",
  "scrapedAt": "2026-10-03T20:07:45.657Z"
}
```

### Coverage and limitations

The RUN_SUMMARY record in the key-value store reports saved count, visited queries, page counts and stop reasons: source exhaustion, page limit, item limit or charge limit. Pages and item limits produce partial snapshots. GeoNames determines ranking and available fields; administrative labels are not standardized administrative-level codes. Population is a displayed source estimate, not a current census guarantee.

There is no exact-name matching option, postal-code mode, history, automatic change detector, alerting service or complete-corpus export. Scheduling repeated snapshots is possible through Apify; compare them downstream. No proxy fallback is enabled. Sequential page fetching and brief delays reduce unnecessary load.

### How much does it cost to export GeoNames places?

Pay-per-event pricing charges a one-time `start` event and an `item` event for each unique place saved. Empty searches have no item event. Retry requests and duplicate records are not separately charged. Coverage metadata is included without another event.

Start: $0.0001 per run. Place prices by tier:

| Tier | Per place |
|---|---|
| FREE | $0.002484 |
| BRONZE | $0.00216 |
| SILVER | $0.0016848 |
| GOLD | $0.001296 |
| PLATINUM | $0.001296 |
| DIAMOND | $0.001296 |

BRONZE estimates: 1 place $0.00226; 10 places $0.0217; 100 places $0.2161. Store discount tiers depend on qualifying aggregate monthly Store spend, not the number of rows in this Actor. Apify limits and applicable infrastructure charges can also affect the final invoice.

### Integrations

Use Apify dataset exports for spreadsheets or join on `geonamesId` in a warehouse. Make, Zapier or n8n can schedule an authorized run and deliver its dataset to a location-review workflow. Keep human review where an ambiguous place could affect routing, tax or compliance decisions.

### API usage

Use your Apify token securely; never commit it. These calls execute the Actor and incur its applicable charges.

```bash
curl -X POST "https://api.apify.com/v2/acts/automation-lab~geonames-place-record-export/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" -H 'Content-Type: application/json' \
  -d '{"queries":["Paris"],"countryCode":"FR","maxItems":10}'
```

JavaScript:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/geonames-place-record-export').call({
  queries: ['Paris'], countryCode: 'FR', maxItems: 10
});
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 10 });
```

Python:

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/geonames-place-record-export').call(
    run_input={'queries': ['Paris'], 'countryCode': 'FR', 'maxItems': 10})
items = client.dataset(run['defaultDatasetId']).list_items(limit=10).items
```

### MCP setup

Claude Code:

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=automation-lab/geonames-place-record-export"
```

Claude Desktop, Cursor, and VS Code: use the client's supported HTTP MCP configuration with the Actor-scoped endpoint and authorized Apify authentication. An illustrative server entry is:

```json
{"mcpServers":{"apify":{"url":"https://mcp.apify.com?tools=automation-lab/geonames-place-record-export"}}}
```

Example prompt: “Search Paris in France and return up to 10 GeoNames place candidates with IDs and coordinates.”

Discover actual tool names and argument schemas through scoped `tools/list`. Actor selection also exposes run/data helpers; discovery itself does not authorize execution. Start an authorized run once and retain its run ID. If pending, check that same run with bounded backoff (2, 4, 8, then at most 10 seconds) up to a 120-second consumer deadline. A timeout is not permission to restart. Report pending or failed honestly.

After success, retrieve dataset pages of 20 source rows with explicit offsets and fields, at most 100 rows and 64 KiB serialized UTF-8 content admitted to model context. Enforce that byte budget host-side; disclose omitted or summarized oversized data. If your client cannot intercept responses, do not promise a hard byte ceiling. Report continuation offset and truncation. Full exports belong in downstream storage, not model context.

### Data handling and diagnostics

The Actor uses no AI during extraction and sends no input or place data to an AI model. It reads public geographic records; it does not intentionally collect contact details or private personal profiles. Apify stores input, dataset, summary and logs under your account's retention settings; delete those stores when no longer needed. No cross-run cache or session store is maintained.

Failed operations send sanitized diagnostic input, exceptions and actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL queries are removed and reports are retained for 30 days. Avoid secrets and personal data in search strings. The source website receives your searches. Apify provides execution/storage; GlitchTip receives failure diagnostics. Operator-owned service costs are not undisclosed off-platform charges.

### Legality and responsible use

Follow GeoNames' applicable terms and attribution requirements, including the source [license information](https://www.geonames.org/about.html). Public accessibility does not remove reuse obligations. Use moderate query volumes and respect source restrictions. This independent tool is not affiliated with or endorsed by GeoNames. Standard Apify user terms apply; no custom end-user terms are imposed.

### Troubleshooting and FAQ

**Why do some names not match my exact query?** GeoNames relevance search can use alternate names and related places. Validate identity using the country, feature and administrative context.

**Why are there fewer rows than requested?** Source exhaustion, deduplication, pagination limits, billing limits or a run timeout can reduce output. Check the run summary; the item limit is a ceiling, not a guarantee.

**Why is population null?** The search result did not expose it. Null is not a zero-population estimate.

**What happens on a challenge or changed layout?** The Actor fails closed rather than treating an unrecognized response as a legitimate empty result. Transient HTTP failures have bounded retries; prior rows on a failed run are partial.

**Can I use a GeoNames API key?** No. This Actor supports anonymous public HTML only.

### Related workflows and support

This is a standalone GeoNames identity-enrichment workflow. OSM geocoding and POI extraction use different source identities and are not interchangeable with these records. For issues, contact us through the Actor's Apify Store issue tab with a run link and a non-sensitive reproduction input. Do not include account tokens.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/geonames-place-record-export/changelog.md

# Actor input Schema

## `queries` (type: `array`):

One to twenty nonempty search strings, each at most 200 characters. Trimmed and exact duplicate strings removed. Uses GeoNames native relevance search, which may return alternate names or nearby related places; not exact-name matching. Queries run in order and share the global item limit.

## `countryCode` (type: `string`):

Optional two-letter GeoNames country code, case-insensitive. Empty searches worldwide. Sent to GeoNames on every page and checked against each returned record; unsupported codes can produce no matches.

## `maxItems` (type: `integer`):

Global run limit after ID deduplication across queries, not a per-query limit. Default 100; 1–1000. Zero and unlimited are unsupported. Source exhaustion, page limits, timeout or billing limit may return fewer records.

## `maxPagesPerQuery` (type: `integer`):

Maximum GeoNames search pages fetched separately for each query, including its first page. Default 5; 1–20. Each observed page has up to 50 results. Bounds snapshots rather than guaranteeing full source coverage.

## Actor input object example

```json
{
  "queries": [
    "Paris"
  ],
  "countryCode": "FR",
  "maxItems": 10,
  "maxPagesPerQuery": 5
}
```

# Actor output Schema

## `places` (type: `string`):

Unique GeoNames places in the default dataset.

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

Queries visited, page counts and collection stop reasons.

# 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 = {
    "queries": [
        "Paris"
    ],
    "countryCode": "FR",
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/geonames-place-record-export").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 = {
    "queries": ["Paris"],
    "countryCode": "FR",
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/geonames-place-record-export").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 '{
  "queries": [
    "Paris"
  ],
  "countryCode": "FR",
  "maxItems": 10
}' |
apify call automation-lab/geonames-place-record-export --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/geonames-place-record-export"
        }
    }
}
```

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/gyuvQnGHsORSauEE6/builds/adYsZIXBAP9Do9vjf/openapi.json
