Skip to main content

Enrich a CSV of addresses with Census demographics (Python)

Turn a plain list of US addresses into an enriched table with rooftop coordinates, the 15-digit Census block, and official Census demographics — in about 40 lines of Python, using the Weganar / geocodercloud API.

This is the exact workflow behind demographic enrichment, HMDA/fair-lending prep, and market analysis: geocode each address, get its Census geography, then pull the numbers for that geography.

What you'll need

  • A free account at weganar.com and an API key (create one on your dashboard). New accounts get 5,000 geocodes/month plus 150 free credits on first sign-in.

  • Python 3.9+ and requests (pip install requests).

  • A CSV with an address column, e.g.:

    address
    "1600 Pennsylvania Ave NW, Washington, DC 20500"
    "782 N Lakewood Ave, Ocoee, FL 34761"
    

The two calls

Both endpoints are POST /api/v1/..., take {"address": "..."}, and authenticate with an X-API-Key: gck_... header.

1. Geocode — resolve the address to a point and its Census block:

curl -X POST "https://weganar.com/api/v1/geocode" \
  -H "X-API-Key: gck_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"address": "1600 Pennsylvania Ave NW, Washington, DC 20500"}'
{
  "matchCode": "NAD_PARCEL",
  "locationCode": "ROOFTOP",
  "lat": 38.897675,
  "lon": -77.036547,
  "fips": "11001",
  "censusBlock": "110010062021031"
}

That censusBlock is a 2020 GEOID: state (2) + county (3) + tract (6) + block (4). Slice it for tract or block group.

2. Demographics — pull Census/ACS data for that address (20 credits per successful report; nothing is charged when data isn't available):

curl -X POST "https://weganar.com/api/v1/demographics" \
  -H "X-API-Key: gck_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"address": "1600 Pennsylvania Ave NW, Washington, DC 20500"}'

The script

A ready-to-run version lives at examples/enrich_csv_demographics.py. The core is just:

import requests

BASE = "https://weganar.com"
HEADERS = {"X-API-Key": "gck_your_api_key", "Content-Type": "application/json"}

def enrich(address):
    geo = requests.post(f"{BASE}/api/v1/geocode",
                        headers=HEADERS, json={"address": address}).json()
    row = {"lat": geo.get("lat"), "lon": geo.get("lon"),
           "census_block": geo.get("censusBlock"), "fips": geo.get("fips")}
    # Only spend credits on demographics if the address actually matched.
    if geo.get("matchCode") not in (None, "NO_MATCH"):
        demo = requests.post(f"{BASE}/api/v1/demographics",
                             headers=HEADERS, json={"address": address}).json()
        if demo.get("available"):
            row["population"] = demo.get("population")
            row["median_household_income"] = demo.get("medianHouseholdIncome")
    return row

Run it over a file:

export WEGANAR_API_KEY=gck_your_api_key
python examples/enrich_csv_demographics.py addresses.csv --out enriched.csv

Notes & good habits

  • A no-match is an HTTP 200, not an error — check matchCode == "NO_MATCH" (with a noMatchReason) rather than relying on the status code.
  • Guard your credits. The script only calls /demographics when the geocode matched, so you never spend credits on an address that didn't resolve.
  • You own the output. Unlike Google Maps, there's no restriction on storing the coordinates or GEOIDs you get back — write them to your warehouse and keep them.
  • Batching. Call per address at your tier's throughput; add --sleep if you want to pace requests. Higher volumes are available on the Growth/Enterprise plans.

Where to go next

  • Swap /demographics for /demographic-trend, /schools, /hazards, /crime, or /property-intel to enrich with other datasets on the same address.
  • See per-state rooftop coverage at /coverage/states.

Run this on your own addresses

Start free with 5,000 geocodes a month, Census block included.

Get your API key — 150 free credits