Nominatim Address Geocoder avatar

Nominatim Address Geocoder

Pricing

from $1.00 / 1,000 location geocodeds

Go to Apify Store
Nominatim Address Geocoder

Nominatim Address Geocoder

Batch geocode addresses to GPS coordinates (forward geocoding) or convert latitude/longitude coordinates back to street addresses (reverse geocoding) using the OpenStreetMap Nominatim API. Powered by the world's largest open geographic database with global coverage across 200+ countries.

Pricing

from $1.00 / 1,000 location geocodeds

Rating

0.0

(0)

Developer

Ryan Clinton

Ryan Clinton

Maintained by Community

Actor stats

0

Bookmarked

26

Total users

6

Monthly active users

7 days ago

Last modified

Share

Turn messy addresses into decisions — audit, validate, repair, deduplicate and enrich address data on OpenStreetMap

Raw geocoding APIs tell you where an address is. This actor tells you whether you should trust it, repair it, route it, or reject it.

Audit, validate, repair, deduplicate, and enrich address datasets at scale on OpenStreetMap. The output is not a coordinate. It's an action.

Input: 50,000 messy addresses Output: 42,108 use • 5,124 repair • 1,932 verify • 836 reject

…without reading a single address manually. No API key, 200+ countries, automatic rate-limit compliance.


The difference, in one picture

A raw geocoder This actor
───────────── ──────────
Address Address
│ │
▼ ▼ quality + normalization
Geocoder Geocoding
│ │
▼ ▼ validation
Coordinates Repair
(done)
▼ deduplication
Risk analysis
▼ deliverability + territory
┌─────────────────┐
DECISION
│ use · repair · │
│ verify · reject │
└─────────────────┘

Why address data fails

Bad address data quietly creates duplicate CRM records, failed deliveries, incorrect territory assignment, broken lead routing, wasted sales outreach, and inaccurate reporting. Raw geocoding APIs make this worse: they return coordinates for almost anything, even a vague, misspelled, or duplicate address, with no signal that something is wrong.

Raw geocoding APIs return coordinates. This actor tells you whether you should trust them.


Most geocoders stop here

{ "lat": 38.8977, "lon": -77.0365 }

Your workflow still doesn't know:

  • ❌ Can I trust it?
  • ❌ Can I deliver to it?
  • ❌ Should I repair it?
  • ❌ Is it a duplicate?
  • ❌ Should I reject it?

This actor ends here

{
"recommendedAction": "repair",
"addressPersona": "repairable",
"riskFlags": ["postcode_mismatch"],
"repairSuggestion": "1600 Pennsylvania Avenue NW, Washington, DC 20500",
"territory": "Washington DC",
"explanation": ["address resolved at street-level", "source address is incomplete (no postcode)", "a clean canonical address is available", "recommended action: repair"]
}

Your workflow knows exactly what to do next.


The most important field

{ "recommendedAction": "repair" }

Possible values: use (trustworthy, act on it) · repair (resolved, but clean the source address first) · verify (needs a human look) · reject (unusable).

Not the latitude. Not the longitude. Not the confidence score. Everything else in this actor — normalization, validation, risk scoring, deliverability, territory assignment — exists to produce this one decision, so your CRM, dialler, routing engine, or ETL job can act on it automatically.


This isn't one address. It's your whole dataset.

Point the actor at 50,000 CRM records (via queries, structuredAddresses, or inputDatasetId) and the run-ending summary classifies every one and tells you what to do — without reading a single address manually:

{
"recordType": "summary",
"auditReport": { "valid": 42108, "needsReview": 1932, "duplicates": 1056, "countryConflicts": 318, "poorQuality": 836 },
"datasetRecommendations": [
{ "action": "repair", "count": 5124, "reason": "postcode_added_from_match" },
{ "action": "review", "count": 1932, "reason": "ambiguous" },
{ "action": "reject", "count": 836, "reason": "too_vague" }
],
"stewardReport": { "highestPriorityIssue": "postcode_added_from_match", "recordsAffected": 5124, "estimatedQualityGain": 10 }
}

Without this actor: someone manually reviews 50,000 rows to find the 7,892 that are broken. With this actor: every record is classified automatically, and datasetRecommendations hands you a ranked fix-list. stewardReport (use workflow: "steward") names the single highest-priority issue and the quality points you'd recover by fixing it.


Why not just use Google, HERE, Mapbox, or OpenCage?

QuestionRaw geocoderThis actor
Where is it?
Can I trust it?
Should I repair it?
Is it a duplicate?
Is it deliverable?
Which territory owns it?
What should I do next?

At a glance

CapabilityRaw geocoding APIThis actor
Coordinates + address breakdown
Validation (country / boundary / postcode)
Repair suggestions for messy addresses
Deduplication + entity resolution
Deliverability scoring (logistics)
Sales-territory assignment
Whole-dataset audit reports
A use / repair / verify / reject decision

(See Key features for the full list — enrichment, geofencing, caching, urbanicity, and more.)


What problem are you solving?

Pick the row that matches your pain and the actor configures itself:

If you have…Use workflow
Dirty CRM addressescrm-cleanse
Duplicate customer recordsdeduplicate
Failed deliveriesdelivery-validation
Bad data importsaudit
Territory / lead assignmentlead-routing
Addresses needing enrichmentenrich
"Find everything wrong with my dataset"steward

In outcomes: prevent duplicate CRM records, reject bad delivery locations automatically, fix messy customer addresses, route leads to the correct territory, and audit an entire address dataset in a single run — for CRM teams, logistics teams, revenue operations, and data engineers.

Who this is not for

If you only need raw latitude/longitude, basic reverse geocoding, or a one-off single-address lookup, a plain geocoder is simpler and cheaper — you don't need this. Reach for this actor when you're processing a dataset and need validation, repair, deduplication, deliverability, territory assignment, or a quality audit — decisions, not just coordinates.


Choose your workflow

Set workflow to match your job — it composes with mode (forward/reverse) and tunes the output for your use case. The full decision layer is always computed.

WorkflowUse caseExample
auditGrade a CRM/dataset's address quality{ "workflow": "audit", "queries": [...] }
validateConfirm addresses resolve in the right country/boundary{ "workflow": "validate", "expectedCountry": "GB", "queries": [...] }
enrichAdd full location intelligence (timezone, Plus Code, category){ "workflow": "enrich", "queries": [...] }
deduplicateCollapse addresses that point to the same place{ "workflow": "deduplicate", "queries": [...] }
deliveryScore logistics serviceability for each location{ "workflow": "delivery", "queries": [...] }

(Customer-named aliases also work: crm-cleanse, lead-routing, delivery-validation.)


How the decision is made

What this actor adds on top of raw geocoding: input quality, geocoding, normalization and repair, validation, risk and deduplication, deliverability and territory, then a decision

This actor is an Address Intelligence Engine: five independent signals feed one decision, and you can see every one of them.

recommendedAction (the decision)
┌─────────┬───────┼───────┬──────────────┐
confidence inputQuality validation risk deliverability

Every record runs through a deterministic pipeline — no AI, no black box. Each score, flag, and recommendation traces back to a documented rule, and every result carries an explanation[] array spelling out the reasoning in plain English.

INPUT (address or coordinate)
▼ Input quality scored (structure, completeness) → inputQuality
▼ Normalization (clean address components) → normalizedAddress, repairSuggestion
▼ Geocoding (OpenStreetMap Nominatim)
▼ Match classification (precision + match type) → precision, matchType, candidateCount
▼ Confidence scoring (transparent components) → confidenceScore, confidenceBreakdown
▼ Validation (country, boundary, postcode) → validation, geofencing, territory
▼ Risk assessment (consolidated signals) → riskScore, riskFlags, reviewReasons
▼ Deliverability + serviceability (precision rule) → deliverySuitability, serviceability
▼ DECISION → recommendedAction + explanation

How a few of the derived signals are calculated (the full rules are in the dataset schema field descriptions):

  • confidenceScore = a base from the precision tier (rooftop 90 → country 20) plus small documented bonuses for a resolved house number (+4), postcode (+3), country-filter match (+3), and a single candidate (+3). The confidenceBreakdown object shows each component.
  • deliverySuitability / serviceability.deliverable = precision-driven: rooftop/street precision is deliverable; city-level or coarser is not precise enough for last-mile delivery. The reason field states which rule applied.
  • recommendedAction = reject if no match; verify if ambiguous or a boundary violation; repair if it resolved but the source address is messy; use if high-confidence and unambiguous. The explanation[] and reviewReasons[] show exactly which conditions fired.
  • riskScore = a weighted sum of the risk flags present (e.g. country mismatch +30, ambiguous +20, postcode mismatch +15); the riskFlags[] array lists every contributor.

The output is not a coordinate. The output is an action.


Example automation rules

Because the output is a decision, you wire it straight into your tools — no parsing, no scripting. Branch on recommendedAction:

recommendedActionWhat your automation does
useWrite the record straight to your CRM / database / map layer
repairUpdate the source record with repairSuggestion, then re-import
verifySend to a human review queue (with reviewReasons attached)
rejectBlock the import / flag for correction

In Zapier, Make, n8n, or Dify, that's a single if/else node on one field. This actor isn't returning data — it's returning workflow decisions.


Four features: returns a decision, repairs dirty addresses, audits whole datasets, 100% deterministic

Why use this actor?

  • Two-way address resolution -- forward geocode addresses to coordinates or reverse geocode coordinates to addresses in a single actor, eliminating the need for separate tools
  • Batch processing built in -- submit hundreds of addresses or coordinate pairs at once instead of writing custom scripts to loop through individual API calls
  • Automatic rate limit compliance -- Nominatim enforces a strict 1 request/second policy and will block violators; this actor spaces requests at 1.1 seconds automatically so you never get banned
  • Structured, consistent output -- every result returns the same fields with null-safe handling for failed lookups, making downstream data processing predictable and reliable
  • Cloud-native scheduling -- run geocoding jobs on recurring schedules via Apify, trigger runs via webhooks, and pipe results directly into Google Sheets, CRMs, or databases without local infrastructure

Key features

  • Forward geocoding -- convert street addresses, landmarks, city names, or any place description into precise latitude/longitude GPS coordinates
  • Reverse geocoding -- convert GPS coordinate pairs back into fully structured street addresses with city, state, country, and postcode
  • Batch processing -- geocode hundreds of addresses or coordinate pairs in a single actor run with automatic queuing
  • Country code filtering -- restrict forward geocoding results to a specific country using ISO 3166-1 alpha-2 codes (e.g., US, GB, DE, JP) for higher accuracy
  • Multi-language results -- retrieve address components in English, German, French, Spanish, Japanese, or any language supported by OpenStreetMap
  • Full address decomposition -- every result includes house number, road, city, state, country, and postcode as separate fields
  • OpenStreetMap metadata -- includes OSM type, OSM ID, place type classification, importance ranking score, and geographic bounding box
  • Match-quality decision layer -- every result is classified by matchType, precision, and confidenceScore, then given a recommendedAction (use / verify / reject) your workflow can branch on directly
  • Address standardization -- a normalizedAddress object with clean house number, street, city, county, state, postcode, and country, plus an administrativeHierarchy from broad to narrow
  • Input quality scoring -- each address gets an inputQuality score so you can tell garbage source data from good data before trusting the geocode
  • Ambiguity & duplicate detection -- flags vague queries with multiple candidates (ambiguous, candidateCount) and marks repeat places in a batch (isDuplicate, duplicateOf)
  • Country validation -- set expectedCountry to verify every result landed in the country you expected (countryMatched)
  • Spatial enrichment -- every resolved coordinate carries its Plus Code, IANA timezone, current UTC offset, continent, and hemisphere, computed offline at no extra cost
  • Batch analytics -- a per-run summary record with dataQualityScore, duplicates found, countries detected, ambiguous count, and the top failure reason
  • Dataset chaining -- read addresses straight from another Apify dataset with inputDatasetId instead of re-pasting them
  • Structured address input -- feed clean, field-separated addresses ({ houseNumber, street, city, state, postcode, country }) for higher-precision matching, perfect for CRM, Salesforce, HubSpot, and ERP exports
  • Location categories -- every place is classified government, commercial, residential, landmark, transport, and more, from OpenStreetMap tags
  • Boundary & postcode validation -- check results against allowedCountries / allowedStates and verify the input postcode resolved correctly
  • Distance & bearing -- set a reference point and every result reports its distance (km and miles) and compass bearing, with optional radius geofencing
  • Cross-run cache -- name a cache and repeated addresses are served instantly without re-calling Nominatim and without being charged again
  • Risk flags & levels -- every record carries a riskLevel (none/low/medium/high) and stable riskFlags (ambiguous, country mismatch, boundary violation, low confidence, duplicate, poor input) so you can auto-reject or route bad data
  • Deliverability scoring -- a logistics deliverySuitability score answers "can a parcel actually reach this point?", distinct from match confidence
  • Address repair suggestions -- when input is messy but resolves, the actor suggests the clean canonical address, with concrete inputQuality fix recommendations
  • Entity resolution -- a stable cross-run entity id means "IBM HQ", "IBM Headquarters", and "1 New Orchard Road" all collapse to the same entity for deduplication
  • Geofencing -- pass circular or polygon geofences (delivery zones, territories) and every result reports which it falls inside
  • Dataset audit & diagnosis -- every run produces an auditReport (valid / needs-review / duplicates / country-conflicts / poor-quality counts) and a graded datasetDiagnosis with per-dimension risk levels
  • Job workflows -- pick audit, validate, enrich, deduplicate, or delivery and the actor tunes its output for your use case (composes with forward/reverse mode)
  • Repair decisions -- messy-but-resolvable addresses route to a repair action with a repairConfidence, so you clean source data instead of just flagging it
  • Logistics serviceability -- boolean serviceability (deliverable / urban / rural) drops straight into delivery-routing automation rules
  • Sales territory assignment -- define geographic or administrative salesTerritories and every result is tagged with its territory for CRM routing and ownership
  • Automatic rate limiting -- built-in 1.1-second delay between requests keeps you compliant with Nominatim usage policy without manual throttling
  • Null-safe failure handling -- when an address cannot be resolved, the actor returns a record with the original query preserved and all location fields set to null
  • Zero configuration -- no API keys, no account registration, no billing setup; just provide addresses and run

How to use Nominatim Address Geocoder

Using the Apify Console

  1. Navigate to the Nominatim Address Geocoder actor page on Apify Store.
  2. Click Try for free to open the actor in the Apify Console.
  3. Select the Geocoding Mode -- choose "Forward" to convert addresses to coordinates, or "Reverse" to convert coordinates to addresses.
  4. For forward mode, enter your addresses in the Addresses to Geocode field, one per line. Optionally set a Country Code to restrict results.
  5. For reverse mode, enter matching lists of Latitudes and Longitudes, one value per line. Both lists must have the same length.
  6. Optionally change the Language from the default "en" to receive results in another language.
  7. Click Start and wait for the run to complete.
  8. View results in the Dataset tab, or export to JSON, CSV, Excel, or other formats.

Using the Apify API or CLI

apify call ryanclinton/nominatim-geocoder \
--input='{"mode":"forward","queries":["1600 Pennsylvania Ave, Washington DC","Eiffel Tower, Paris","Big Ben, London"],"countryCode":"","language":"en"}'

Input parameters

ParameterTypeRequiredDefaultDescription
modeSelectNoforwardGeocoding direction. "forward" converts addresses to coordinates. "reverse" converts coordinates to addresses.
workflowSelectNostandardJob preset (composes with mode): audit, validate, enrich, deduplicate, delivery. Tunes default output detail; the full decision layer always computes.
queriesString listNo--List of addresses, place names, or landmarks to geocode. Used in forward mode only. One address per line.
latitudesString listNo--List of latitude values for reverse geocoding. Must match the length of the longitudes list.
longitudesString listNo--List of longitude values for reverse geocoding. Must match the length of the latitudes list.
countryCodeStringNo--Restrict forward geocoding to a specific country. Use ISO 3166-1 alpha-2 codes such as "US", "GB", "DE", "FR", "JP".
languageStringNoenPreferred language for results. Use ISO 639-1 codes: "en", "de", "fr", "es", "ja", "zh", "ar", etc.
maxAlternativesIntegerNo0Forward mode only. When greater than 0, also return up to N alternative candidate matches per address in an alternatives array, so you can disambiguate when the top match might be wrong.
minConfidenceIntegerNo0Quality gate (0-100). Matches scoring below this confidence still appear in the dataset flagged suppressed: true, but are not charged.
outputProfileSelectNostandardHow many fields each result carries. minimal = coordinates plus the decision layer. standard = full address plus the decision layer. full = everything including OSM internals, bounding box, decision trail, and next-actor suggestions.
structuredAddressesArrayNo--Forward mode: addresses as structured objects ({ houseNumber, street, city, county, state, postcode, country }) for higher-precision matching. Overrides queries when set. Ideal for CRM/ERP exports.
expectedCountryStringNo--ISO 3166-1 alpha-2 code. When set, validation.countryMatched verifies each result resolved to this country.
allowedCountriesString listNo--Boundary validation: ISO alpha-2 codes a result must fall within. Outside results get validation.boundaryViolation: true.
allowedStatesString listNo--Boundary validation: state/region names a result must fall within (case-insensitive, e.g. "England", "California").
referenceLat / referenceLonNumberNo--A reference point. When both are set, every result reports geospatial.distanceKm, distanceMiles, and bearing from it.
maxRadiusKmNumberNo--With a reference point set, results within this many km are flagged geospatial.insideRadius: true.
geofencesArrayNo--Circular ({name, lat, lon, radiusKm}) or polygon ({name, polygon:[[lat,lon],…]}) geofences. Each result reports which it falls inside. Ideal for delivery zones.
salesTerritoriesArrayNo--Named territories — geographic ({name, polygon} / {name, lat, lon, radiusKm}) or administrative ({name, countries:["GB"], states:["England"]}). Each result is assigned the first matching territory.
cacheNameStringNo--Opt-in cross-run cache. When set, repeated addresses are served instantly from a named store (no re-fetch, no charge). Leave blank to disable.
cacheMaxAgeDaysIntegerNo30How long a cached result stays valid before being re-fetched.
inputDatasetIdStringNo--Read forward-mode addresses from another Apify dataset (e.g. a previous actor's output) instead of, or in addition to, the queries field.
addressFieldStringNoaddressThe field name to read the address from when inputDatasetId is set.

Forward geocoding input example

{
"mode": "forward",
"queries": [
"1600 Pennsylvania Ave, Washington DC",
"Eiffel Tower, Paris, France",
"Shibuya Crossing, Tokyo",
"Colosseum, Rome, Italy"
],
"countryCode": "",
"language": "en"
}

Reverse geocoding input example

{
"mode": "reverse",
"latitudes": ["48.8584", "40.7484", "51.5014"],
"longitudes": ["2.2945", "-73.9857", "-0.1419"],
"language": "en"
}

Tips for input

  • For forward geocoding, include as much detail as possible -- street number, street name, city, state, and country yield the best results.
  • Always set the countryCode when you know the target country. This prevents the geocoder from returning matches in the wrong country (e.g., "Springfield" exists in 30+ US states and in other countries).
  • For reverse geocoding, use at least 4 decimal places of precision for street-level accuracy.
  • The latitudes and longitudes lists must be the same length -- each latitude at index N is paired with the longitude at index N.

Output

Sample output table: query, recommended action, address persona, confidence grade, precision, risk level and territory per row

Each geocoding result pairs a deterministic decision layer with a standardized address and spatial enrichment. Here is an example of a forward geocoding result (standard profile):

{
"recordType": "result",
"schemaVersion": "2.6.0",
"query": "1600 Pennsylvania Ave, Washington DC",
"matched": true,
"matchType": "exact",
"precision": "rooftop",
"confidenceScore": 100,
"confidenceLevel": "high",
"confidenceGrade": "A",
"confidenceBreakdown": { "base": 90, "importance": 8, "houseNumber": 4, "postcode": 3, "countryFilter": 0, "singleCandidate": 3 },
"recommendedAction": "use",
"addressPersona": "trusted",
"explanation": ["address resolved at rooftop-level (exact match)", "confidence 100/100 (high)", "recommended action: use"],
"reviewReasons": [],
"riskScore": 0,
"riskLevel": "none",
"riskFlags": [],
"deliverySuitability": { "score": 100, "level": "high", "reason": "rooftop precision with postcode — deliverable" },
"serviceability": { "deliverable": true, "urban": true, "rural": false, "reason": "rooftop precision with postcode — deliverable" },
"summary": "\"1600 Pennsylvania Ave, Washington DC\" geocoded to rooftop-level (exact match, confidence 100/100) — use.",
"candidateCount": 1,
"ambiguous": false,
"isDuplicate": false,
"duplicateOf": null,
"duplicateCluster": 0,
"entity": { "id": "osm_way_238241022", "confidence": "high" },
"territory": null,
"recommendedOwner": null,
"failureReason": null,
"repairSuggestion": null,
"repairConfidence": null,
"repairReasons": [],
"inputQuality": { "score": 70, "level": "rich", "signals": ["contains a street/house number", "comma-delimited components"], "issues": ["no postcode"], "recommendation": "Add a postcode to confirm the exact location." },
"validation": { "countryMatched": null, "matchedCountry": "United States", "insideAllowedBoundary": null, "boundaryViolation": null, "postcodePresent": false, "postcodeMatched": null },
"geofencing": null,
"geospatial": null,
"latitude": 38.8976763,
"longitude": -77.0365298,
"displayName": "White House, 1600, Pennsylvania Avenue Northwest, Washington, District of Columbia, 20500, United States",
"normalizedAddress": {
"houseNumber": "1600", "street": "Pennsylvania Avenue Northwest", "city": "Washington",
"county": null, "state": "District of Columbia", "postcode": "20500", "country": "United States", "countryCode": "US"
},
"administrativeHierarchy": { "country": "United States", "state": "District of Columbia", "city": "Washington" },
"locationCategory": "government",
"addressCompleteness": 83,
"enrichment": { "plusCode": "87C4VXX7+39", "hemisphere": "NW", "continent": "North America", "urbanicity": "urban", "timezone": "America/New_York", "utcOffset": "-04:00" },
"placeType": "house",
"importance": 0.782,
"extractedAt": "2025-01-15T14:32:08.123Z"
}

Decision & quality fields

FieldTypeDescription
matchedBooleantrue when the query resolved to a location
matchTypeStringHow it matched: exact, normalized, partial, ambiguous, fallback, or none
precisionStringPrecision tier: rooftop, street, neighborhood, city, region, country, unknown
confidenceScoreNumberDeterministic 0-100 score from precision, importance, and match completeness
confidenceLevelStringStable band: high (>=75), medium (>=45), low (>0), none (0)
confidenceFactorsArrayPlain-English drivers behind the score, for auditability
confidenceBreakdownObjectNumeric point contributions: { base, importance, houseNumber, postcode, countryFilter, singleCandidate }
confidenceGradeStringA–F letter grade on the confidence score
recommendedActionStringThe decision to branch on: use (high & unambiguous), verify (ambiguous/boundary), repair (resolved but the source address is messy), reject (no match)
addressPersonaStringOne-word dashboard label: trusted, repairable, ambiguous, unusable, duplicate
explanationArrayPlain-English account of why this decision was reached (what resolved, what's wrong, confidence, action)
reviewReasonsArrayAction-scoped codes for why the record needs attention — empty when the action is use
riskScore / riskLevel / riskFlagsNumber / String / ArrayNumeric 0-100 risk, the none/low/medium/high band, and the stable flag codes behind it
deliverySuitabilityObject / nullLogistics deliverability { score, level, reason } — can a parcel reach this point?
serviceabilityObject / nullBoolean logistics projection { deliverable, urban, rural, reason } for if/then automation
entityObjectStable cross-run { id, confidence } for deduplicating addresses that resolve to the same place
territory / recommendedOwnerString / nullThe first matching salesTerritories name and its owner, for CRM lead routing
repairSuggestion / repairConfidence / repairReasonsString / Number / ArrayA clean canonical address, a 0-100 confidence, and what it fixed (e.g. street_name_expanded, postcode_added_from_match)
summaryStringOne-line plain-English verdict an LLM or agent can quote directly
candidateCountNumberHow many candidate matches the geocoder returned
ambiguous / needsDisambiguationBooleantrue when multiple plausible candidates exist at a coarse precision
isDuplicate / duplicateOf / duplicateClusterBoolean / NumberDuplicate flag, the first index, and a stable cluster id shared by all members of the same place
failureReasonString / nullWhen unmatched: not_found, too_vague, country_conflict, or invalid_coordinates
inputQualityObject / null{ score, level, signals[], issues[], recommendation } rating the input address string and how to improve it (null in reverse mode)
validationObject{ countryMatched, matchedCountry, insideAllowedBoundary, boundaryViolation, postcodePresent, postcodeMatched } from expectedCountry / allowedCountries / allowedStates / input postcode
geofencingObject / nullWhen geofences are provided: { insideGeofence, matched[], results[] }
geospatialObject / nullWhen a reference point is set: { distanceKm, distanceMiles, bearing, insideRadius }
cacheHit / cacheSource / cacheAgeDaysBoolean / String / NumberWhether the result came from the cross-run cache, and how old it was
decisionTrailArrayStep-by-step processing audit (full profile)

Address & enrichment fields

FieldTypeDescription
latitude / longitudeNumber / nullGPS coordinates of the resolved location
displayNameString / nullFull formatted address as returned by Nominatim
normalizedAddressObject / nullStandardized components: houseNumber, street, city, county, state, postcode, country, countryCode
administrativeHierarchyObject / nullPopulated administrative levels broad → narrow (country, state, county, district, city)
locationCategoryString / nullBroad place category from OSM tags: government, commercial, residential, landmark, education, healthcare, transport, area, other
addressCompletenessNumber / null0-100 fraction of the core address components the geocoder populated
enrichmentObject / nullplusCode (Open Location Code), hemisphere, continent, urbanicity (urban/suburban/rural), timezone (IANA), utcOffset
placeTypeString / nullPlace classification such as "house", "street", "city", "country"
placeRankNumber / nullNominatim place_rank (0-30); higher is more specific (full profile)
importanceNumber / nullNominatim importance ranking score between 0 and 1
osmType / osmIdString / NumberOpenStreetMap object type and identifier (full profile)
boundingBoxArray / nullGeographic bounding box as [south lat, north lat, west lon, east lon] (full profile)
alternativesArrayCandidate matches when maxAlternatives > 0, each with coordinates, display name, and importance
extractedAtStringISO 8601 timestamp of when the result was extracted

When a query cannot be resolved, matched is false, recommendedAction is reject, failureReason explains why, and the location fields are null while query, summary, inputQuality, and extractedAt stay populated. Filter on recommendedAction, matchType, or confidenceLevel to separate clean matches from ones that need review.

Coverage summary record

After the result records, the actor pushes one recordType: "summary" record so you can read the health of the whole batch at a glance:

{
"recordType": "summary",
"schemaVersion": "2.6.0",
"mode": "forward",
"workflow": "audit",
"coverage": { "requested": 100, "succeeded": 92, "failed": 8, "successRate": 0.92 },
"dataQualityScore": 89,
"healthGrade": "B",
"duplicatesFound": 6,
"duplicateClusters": 3,
"duplicateRate": 0.06,
"ambiguityRate": 0.04,
"countryMismatchRate": 0.01,
"countriesDetected": 3,
"ambiguousQueries": 4,
"topFailureReason": "too_vague",
"precisionBreakdown": { "rooftop": 61, "street": 24, "neighborhood": 0, "city": 7, "region": 0, "country": 0, "unknown": 8 },
"matchTypeBreakdown": { "exact": 58, "normalized": 27, "partial": 3, "ambiguous": 4, "fallback": 0, "none": 8 },
"auditReport": { "valid": 85, "needsReview": 7, "duplicates": 6, "countryConflicts": 1, "poorQuality": 11 },
"datasetDiagnosis": { "qualityGrade": "B", "duplicateRisk": "medium", "ambiguityRisk": "low", "deliverabilityRisk": "low", "countryConflictRisk": "low" },
"rateLimited": false,
"summary": "92/100 geocoded. Grade B (quality 89/100). 85 ready, 7 to review, 8 unresolved. 6 duplicate(s) in 3 cluster(s), 4 ambiguous, 3 countries.",
"timestamp": "2025-01-15T14:34:01.500Z"
}

The auditReport is your address-quality audit in one object (valid / needs-review / duplicates / country-conflicts / poor-quality counts); the datasetDiagnosis grades the batch and assigns a risk level to each quality dimension; datasetRecommendations ranks what to fix next; and stewardReport names the single highest-priority issue and the quality points recoverable by fixing it. The per-dimension rates feed automation thresholds.


Use cases

  • Real estate analysis -- geocode property addresses to plot them on maps, calculate distances between listings, or enrich property datasets with GPS coordinates
  • Logistics and delivery routing -- convert customer delivery addresses into coordinates for route optimization and distance calculations
  • Lead enrichment -- add geographic coordinates to business contact lists for proximity-based sales targeting and territory mapping
  • Data cleaning and normalization -- standardize messy address data by geocoding free-text addresses and extracting structured components (city, state, postcode)
  • Store locator databases -- build store finder features by geocoding retail locations and storing their coordinates for nearest-store lookups
  • Academic research -- geocode survey respondent locations, historical site addresses, or field study coordinates for spatial analysis and GIS mapping
  • Event planning -- convert venue addresses to coordinates for generating maps, calculating travel times, and finding nearby hotels or restaurants
  • IoT and sensor data -- reverse geocode GPS coordinates from tracking devices, fleet vehicles, or mobile apps into human-readable addresses
  • Market research -- map competitor locations, analyze geographic distribution of customers, or identify underserved areas by geocoding address datasets

API & integrations

Python

from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("i4BCLB2eHbePe78aj").call(run_input={
"mode": "forward",
"queries": [
"1600 Pennsylvania Ave, Washington DC",
"221B Baker Street, London",
"Champs-Elysees, Paris"
],
"language": "en"
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(f"{item['query']} -> {item['latitude']}, {item['longitude']}")

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('i4BCLB2eHbePe78aj').call({
mode: 'forward',
queries: [
'1600 Pennsylvania Ave, Washington DC',
'221B Baker Street, London',
'Champs-Elysees, Paris',
],
language: 'en',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
console.log(`${item.query} -> ${item.latitude}, ${item.longitude}`);
});

cURL

curl -X POST "https://api.apify.com/v2/acts/i4BCLB2eHbePe78aj/runs?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mode": "forward",
"queries": ["1600 Pennsylvania Ave, Washington DC", "Big Ben, London"],
"language": "en"
}'

Integration platforms

  • Google Sheets -- export geocoded results directly to spreadsheets for mapping and visualization
  • Zapier -- trigger geocoding runs and route results to 5,000+ connected apps
  • Make (Integromat) -- build multi-step automation workflows with geocoded address data
  • Webhooks -- receive HTTP notifications when geocoding runs complete for event-driven pipelines
  • Slack / Email -- get notified of completed runs or failed lookups automatically
  • Apify datasets API -- fetch results programmatically in JSON, CSV, XML, or Excel format from any language

Use in Dify

Drop this actor into Dify workflows via the Apify plugin's Run Actor node. Each address returns geocoded, scored, and classified as structured JSON — use / verify / reject plus the precision tier and confidenceScore your downstream node branches on. A raw geocoding API pointed at the same address returns a coordinate with no quality signal; this returns a decision about whether that coordinate is trustworthy.

  • Actor ID: ryanclinton/nominatim-geocoder
  • Sample input (geocode a batch of customer addresses and only auto-accept the clean ones):
{
"mode": "forward",
"queries": [
"1600 Pennsylvania Ave, Washington DC",
"Eiffel Tower, Paris",
"221B Baker Street, London"
],
"minConfidence": 75,
"outputProfile": "standard"
}

Branching on the decision. Wire a Dify if/else node to the recommendedAction field so each address routes itself without anyone reading the coordinates:

  • recommendedAction == "use" → write the coordinates straight to your database / CRM / map layer
  • recommendedAction == "verify" → send to a human-review queue (medium/low confidence — the match resolved but may be coarse)
  • recommendedAction == "reject" → flag the address as undeliverable / unresolvable and request a correction

For tighter control, branch on precision (e.g. only accept rooftop or street for last-mile delivery, allow city for analytics) or threshold on the numeric confidenceScore. The summary field is a plain-English one-liner an LLM node can quote verbatim into a notification.

Opt-in modes Dify workflows can leverage: set minConfidence to have the actor pre-filter low-quality matches (they still appear flagged, but routing can skip them); set maxAlternatives to receive candidate matches in an alternatives array for a disambiguation step; set outputProfile: "minimal" to keep the Dify variable payload lean. The end-of-run recordType: "summary" record gives a single node the batch coverage (successRate, precision/confidence distributions) without aggregating per-row.


How it works

The actor processes geocoding requests through the following pipeline:

  1. Input validation -- the actor reads the input configuration and validates the selected mode, checking that queries are provided for forward mode or that matching latitude/longitude arrays exist for reverse mode.
  2. Request construction -- for each item in the batch, the actor builds a Nominatim API request URL with the appropriate parameters (/search for forward, /reverse for reverse) including format, address detail, country code, and language settings.
  3. Rate-limited execution -- requests are sent sequentially with a 1.1-second delay between each call. A custom User-Agent header identifies the actor to comply with Nominatim's terms of service.
  4. Response parsing -- the Nominatim JSON response is parsed and mapped into a standardized 16-field output structure. The city field is intelligently resolved from city, town, village, or municipality depending on what Nominatim returns.
  5. Null-safe fallback -- if a query returns no results or encounters an error, a result record is still created with the original query and all location fields set to null.
  6. Dataset push -- all results are pushed to the Apify dataset in a single batch for efficient storage and retrieval.
Input Addresses Nominatim API Structured Output
+------------------+ +------------------+ +------------------+
| "Eiffel Tower" | --> | /search?q=... | --> | lat: 48.8584 |
| "Big Ben" | | format=jsonv2 | | lon: 2.2945 |
| "Colosseum" | | addressdetails=1 | | city: Paris |
+------------------+ +------------------+ | country: France |
| 1.1s delay +------------------+
| between each |
v request v
Batch Queue Rate-Limited Fetch Apify Dataset

Performance & cost

The actor runs on minimal resources since it only performs lightweight HTTP API calls with no browser rendering or HTML parsing.

Batch sizeEstimated timeEstimated Apify costNominatim API cost
10 addresses~12 seconds< $0.01Free
50 addresses~1 minute< $0.01Free
100 addresses~2 minutes$0.01 -- $0.02Free
500 addresses~9 minutes$0.05 -- $0.08Free
1,000 addresses~18 minutes$0.10 -- $0.15Free
  • Memory usage: 256 MB (minimum tier) is sufficient for all batch sizes
  • Processing speed: ~1.1 seconds per address due to Nominatim's mandatory rate limit
  • Cost driver: Apify compute time is the only cost; the Nominatim API itself is completely free
  • Comparison: Google Maps Geocoding API charges $5.00 per 1,000 requests; this actor geocodes the same volume for approximately $0.10 in Apify compute

Limitations

  • Rate limit of 1 request per second -- Nominatim enforces this strictly, so large batches (1,000+ addresses) will take 18+ minutes. This cannot be bypassed without hosting your own Nominatim instance.
  • Single best result by default -- forward geocoding returns the top-ranked result unless you set maxAlternatives, which adds up to 10 candidate matches per address in an alternatives array for disambiguation.
  • OpenStreetMap data coverage varies -- accuracy is excellent in North America, Europe, and major cities worldwide, but may be lower in rural or less-mapped regions of developing countries.
  • Address component language availability -- multi-language results depend on translations existing in OpenStreetMap. Less common languages may fall back to the local language of the location.
  • Confidence is a deterministic heuristic -- the confidenceScore is derived from the match precision and OpenStreetMap importance, not a probabilistic model. It tells you how specific and prominent the match is, which is the right signal for filtering, but it is not a statistical match probability.
  • Sequential processing only -- due to the rate limit, requests are processed one at a time. Parallel geocoding is not supported by the public Nominatim instance.

Responsible use

  • Respect Nominatim usage policies -- this actor complies with the Nominatim Usage Policy by enforcing rate limits and providing a descriptive User-Agent header. Do not attempt to bypass these limits.
  • Attribute OpenStreetMap -- Nominatim data comes from OpenStreetMap contributors. If you display geocoded results publicly, include appropriate attribution as required by the ODbL license.
  • Avoid excessive batch sizes -- while the actor handles rate limiting automatically, submitting extremely large batches (10,000+ addresses) places unnecessary load on the free public Nominatim infrastructure. For very large workloads, consider hosting your own Nominatim instance.
  • Do not use for real-time applications -- the 1-second rate limit makes this unsuitable for user-facing real-time geocoding. Use it for batch processing and data enrichment workflows instead.
  • Handle personal data responsibly -- if you are geocoding personal addresses, ensure compliance with applicable data protection regulations (GDPR, CCPA, etc.) regarding the processing and storage of location data.

FAQ

Q: Is the Nominatim geocoding API free to use? A: Yes. Nominatim is a free, open-source geocoding service powered by OpenStreetMap data. There are no API keys, subscriptions, or per-request charges. The only cost is Apify compute time for running the actor.

Q: How accurate is Nominatim compared to Google Maps Geocoding? A: For well-mapped regions (North America, Europe, Australia, major cities worldwide), Nominatim accuracy is comparable to commercial services. OpenStreetMap data is community-maintained and coverage varies by region. The importance field provides a rough indicator of place prominence, though it is not a match confidence score.

Q: Do I need an API key or account to use this actor? A: No. The Nominatim API requires no authentication. You only need an Apify account to run the actor. The actor handles all Nominatim communication including the required User-Agent header.

Q: What happens if an address cannot be found? A: The actor returns a result record with the original query preserved in the query field and all location fields (latitude, longitude, displayName, city, etc.) set to null. This makes it easy to identify and retry failed lookups.

Q: Can I geocode addresses in any country? A: Yes. OpenStreetMap has global coverage spanning 200+ countries. Use the countryCode parameter with an ISO 3166-1 alpha-2 code (e.g., "US", "GB", "JP", "BR", "IN") to restrict results and improve accuracy for a specific country.

Q: How many addresses can I geocode in one run? A: There is no hard limit on batch size. Processing time scales linearly at approximately 1.1 seconds per address. A batch of 100 addresses takes about 2 minutes; 1,000 addresses takes about 18 minutes. For batches larger than 1,000, consider splitting across multiple scheduled runs.

Q: Can I get results in languages other than English? A: Yes. Set the language parameter to any ISO 639-1 language code (e.g., "de" for German, "fr" for French, "ja" for Japanese, "ar" for Arabic). Address components will be returned in the specified language when translations exist in OpenStreetMap.

Q: What is the difference between forward and reverse geocoding? A: Forward geocoding converts a text address (like "1600 Pennsylvania Ave, Washington DC") into GPS coordinates (38.8977, -77.0365). Reverse geocoding does the opposite -- it takes GPS coordinates and returns the corresponding street address.

Q: Why does the actor take over a second per address? A: The public Nominatim API enforces a strict rate limit of 1 request per second. The actor waits 1.1 seconds between requests to ensure compliance and prevent your requests from being blocked. This is a limitation of the free public service, not the actor itself.

Q: Can I use the results for commercial purposes? A: Yes. OpenStreetMap data is licensed under the Open Database License (ODbL), which permits commercial use provided you give appropriate attribution and share any modifications to the data itself. Geocoding results derived from the data can be used freely.

Q: What coordinate format does reverse geocoding expect? A: Latitudes and longitudes should be provided as decimal degree strings (e.g., "48.8584" for latitude, "2.2945" for longitude). Use at least 4 decimal places for street-level accuracy. The latitudes and longitudes lists must be the same length.

Q: How does the actor handle errors or API failures? A: If a Nominatim request fails due to a network error or API issue, the actor logs the error and returns a result with null location fields for that query. The batch continues processing remaining items. No data is lost -- you can identify failures by checking for null latitude values.


ActorDescription
OpenStreetMap POI SearchSearch for points of interest (restaurants, shops, parks, hospitals) near geocoded coordinates using OpenStreetMap data
Open Charge Map EV StationsFind electric vehicle charging stations near any geocoded location worldwide
Weather Forecast SearchGet weather forecasts and current conditions for geocoded GPS coordinates
IP Geolocation LookupConvert IP addresses to geographic locations -- a complementary approach to address-based geocoding
REST Countries Data SearchLook up country details including ISO codes, currencies, and languages to pair with geocoded country results