# US Address Normalizer & Geocoder — No Login, $2/1k (`chimerical_quicklime/us-address-normalizer-geocoder`) Actor

Bulk-clean messy US addresses to USPS format (abbreviated suffixes, directionals, state codes, ZIP+4) and geocode them to latitude/longitude with county, tract and block FIPS. Census Geocoder + Nominatim fallback, one row per input, no API key. No login or API key. MCP-ready for AI agents. $2 per 1,

- **URL**: https://apify.com/chimerical\_quicklime/us-address-normalizer-geocoder.md
- **Developed by:** [Khrystyna Skotte](https://apify.com/chimerical_quicklime) (community)
- **Categories:** Developer tools, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 address processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## US Address Normalizer & Geocoder

Turn messy US address lists into clean, USPS-style addresses with latitude/longitude and Census geography codes. Feed it strings or `{street, city, state, zip}` objects; get back exactly one row per input, in order, whether it matched or not. No API key, no browser, batches of thousands of addresses in seconds.

Built for lead lists, permit and license exports, CRM cleanup, store/branch lists and any dataset where addresses were typed by humans.

### What normalisation does

| Input | Normalized |
|---|---|
| `1600 pennsylvania ave nw washington dc` | `1600 PENNSYLVANIA AVE NW, WASHINGTON, DC` |
| `350 Fifth Avenue, New York, NY 10118` | `350 5TH AVE, NEW YORK, NY 10118` |
| `233 S. Wacker Dr., Chicago IL 60606` | `233 S WACKER DR, CHICAGO, IL 60606` |
| `123 north main street apt 4b, saint louis, missouri 63101-1234` | `123 N MAIN ST APT 4B, SAINT LOUIS, MO 63101-1234` |
| `2000 Lake Shore Drive North East, Chicago, IL` | `2000 LAKE SHORE DR NE, CHICAGO, IL` |

- Upper-cases and strips punctuation
- USPS Publication 28 street-suffix abbreviations (`STREET` to `ST`, `BOULEVARD` to `BLVD`, `PARKWAY` to `PKWY`, 400+ entries incl. common misspellings) applied only in suffix position, so `LAKE SHORE DR` keeps its name
- Directionals (`NORTH EAST` to `NE`) after the house number and at the end of the street
- Secondary unit designators (`SUITE` to `STE`, `APARTMENT` to `APT`, `#` spacing)
- Ordinal street names (`FIFTH` to `5TH`)
- State names and aliases to two-letter codes (`California` to `CA`, `Washington DC` to city + `DC`)
- ZIP+4 split into `zip5` and `zip4`
- One-line strings without commas are parsed heuristically (`1600 pennsylvania ave nw washington dc` splits into street / city / state)

### Geocoding pipeline

1. **US Census Bureau Geocoder, batch endpoint** (`Public_AR_Current` benchmark, up to 10,000 addresses per request). Returns the Census-standardised address, coordinates, match type (exact / non-exact) and, with `includeCensusGeographies`, state FIPS, county FIPS, census tract and block.
2. **Census one-line endpoint** for anything the batch did not match, tried with the raw input, the normalized line and the normalized line without the unit number.
3. **Nominatim (OpenStreetMap)** fallback, optional, for the rest. Rate-limited to 1 request per second per their usage policy, so a run with many unmatched addresses is slower. Nominatim hits are back-filled with Census FIPS codes via a point lookup so every matched row has the same geography fields.

### Input

| Field | Default | Notes |
|---|---|---|
| `addresses` | 5 sample addresses | Array of strings (`"123 Main St, Austin, TX 78701"`) or objects (`{"id": "a1", "street": "123 Main St", "city": "Austin", "state": "TX", "zip": "78701"}`). Objects may also carry `{"id", "address"}` for a one-line string with your own id. |
| `fallbackToNominatim` | `true` | Try OpenStreetMap for Census non-matches |
| `includeCensusGeographies` | `true` | Add county / tract / block FIPS |
| `maxItems` | `10` | Process at most this many addresses |

```json
{
  "addresses": [
    "1600 pennsylvania ave nw washington dc",
    { "id": "hq-4", "street": "1 Apple Park Way", "city": "Cupertino", "state": "California", "zip": "95014" }
  ],
  "maxItems": 1000
}
```

### Output

One row per input address, in input order:

```json
{
  "inputAddress": "1600 pennsylvania ave nw washington dc",
  "id": 1,
  "normalizedAddress": { "street": "1600 PENNSYLVANIA AVE NW", "city": "WASHINGTON", "state": "DC", "zip5": null, "zip4": null },
  "normalizedAddressLine": "1600 PENNSYLVANIA AVE NW, WASHINGTON, DC",
  "matchStatus": "match",
  "matchType": "exact",
  "matchedAddress": "1600 PENNSYLVANIA AVE NW, WASHINGTON, DC, 20500",
  "latitude": 38.898702605246,
  "longitude": -77.035189204737,
  "geocoder": "census",
  "countyFips": "11001",
  "countyName": "District of Columbia",
  "stateFips": "11",
  "tract": "980000",
  "block": "1034",
  "confidence": 1,
  "processedAt": "2026-09-28T18:52:36.261Z"
}
```

- `matchStatus`: `match`, `tie` (Census found several candidates and none of the fallbacks resolved it) or `no_match`
- `matchType`: `exact` or `non_exact` (Census interpolated, or Nominatim)
- `geocoder`: `census`, `nominatim` or `none`
- `confidence`: `1.0` Census exact, `0.7` Census non-exact, `0.5` Nominatim, `0` no match
- `id`: your object's `id` if given, otherwise the 1-based position in the input

### Limits

- US addresses only (50 states, DC, PR and territories covered by the Census benchmark). Non-US input comes back as `no_match`.
- The Census Geocoder interpolates along TIGER street segments: coordinates are typically within 50 to 200 m of the rooftop, not parcel-exact. In a 300-address test against listing coordinates, 87% were within 200 m and 98% within 1 km.
- Very new subdivisions and apartment complexes may be missing from TIGER and OpenStreetMap; those rows come back `no_match` (you are still charged for them, since they were processed).
- Nominatim fallback runs at 1 address per second. 1,000 Census non-matches add about 18 minutes; set `fallbackToNominatim: false` for speed on large lists.
- PO boxes have no street location and will not geocode.

### Pricing

Pay per processed address: **$2.00 per 1,000 addresses** ($0.002 each, matched or not) plus $0.005 per run. Each address produces one dataset row, so what you pay is exactly what you get.

Typical throughput: 300 addresses in about 45 seconds including Nominatim fallbacks; Census-only batches of 10,000 complete in under a minute.

# Actor input Schema

## `addresses` (type: `array`):

US addresses to normalize and geocode. Each item is either a one-line string ("233 S. Wacker Dr., Chicago IL 60606") or an object {"id", "street", "city", "state", "zip"}. Every item produces exactly one output row.

## `fallbackToNominatim` (type: `boolean`):

When the Census Geocoder finds no match, try OpenStreetMap Nominatim (rate-limited to 1 request per second, so large no-match sets are slow).

## `includeCensusGeographies` (type: `boolean`):

Add state FIPS, county FIPS + name, census tract and block to each matched address.

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

Process at most this many addresses from the list (each address is one charged record).

## Actor input object example

```json
{
  "addresses": [
    "1600 pennsylvania ave nw washington dc",
    "350 Fifth Avenue, New York, NY 10118",
    "233 S. Wacker Dr., Chicago IL 60606",
    {
      "id": "hq-4",
      "street": "1 Apple Park Way",
      "city": "Cupertino",
      "state": "California",
      "zip": "95014"
    },
    "1 infinite loop cupertino ca"
  ],
  "fallbackToNominatim": true,
  "includeCensusGeographies": true,
  "maxItems": 10
}
```

# Actor output Schema

## `records` (type: `string`):

Dataset of normalized and geocoded addresses (JSON).

# 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 = {
    "addresses": [
        "1600 pennsylvania ave nw washington dc",
        "350 Fifth Avenue, New York, NY 10118",
        "233 S. Wacker Dr., Chicago IL 60606",
        {
            "id": "hq-4",
            "street": "1 Apple Park Way",
            "city": "Cupertino",
            "state": "California",
            "zip": "95014"
        },
        "1 infinite loop cupertino ca"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("chimerical_quicklime/us-address-normalizer-geocoder").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 = { "addresses": [
        "1600 pennsylvania ave nw washington dc",
        "350 Fifth Avenue, New York, NY 10118",
        "233 S. Wacker Dr., Chicago IL 60606",
        {
            "id": "hq-4",
            "street": "1 Apple Park Way",
            "city": "Cupertino",
            "state": "California",
            "zip": "95014",
        },
        "1 infinite loop cupertino ca",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("chimerical_quicklime/us-address-normalizer-geocoder").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 '{
  "addresses": [
    "1600 pennsylvania ave nw washington dc",
    "350 Fifth Avenue, New York, NY 10118",
    "233 S. Wacker Dr., Chicago IL 60606",
    {
      "id": "hq-4",
      "street": "1 Apple Park Way",
      "city": "Cupertino",
      "state": "California",
      "zip": "95014"
    },
    "1 infinite loop cupertino ca"
  ]
}' |
apify call chimerical_quicklime/us-address-normalizer-geocoder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,chimerical_quicklime/us-address-normalizer-geocoder"
        }
    }
}
```

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/dd3V6h0OA7fKcSeBV/builds/PhIQ1nDHFODxnTUDQ/openapi.json
