Back to articles

Why Location Normalization Is Harder Than It Looks

CleanJobData Engineering

Location looks simple until you try to filter it. A human can understand SF, San Francisco, Remote US, London / New York, and California. A database cannot do that reliably unless the data has been normalized first.

JobsDataAPI turns messy location strings into structured location rows with city, state, and country IDs.

The Problem with Raw Strings

Raw location strings are inconsistent across sources:

  • NYC
  • New York, NY
  • San Francisco / Remote
  • Remote - United States
  • London, UK
  • CA
  • North America

String matching fails quickly. Searching for CA can match California, Canada, or unrelated text. Searching for Remote can accidentally include jobs that are only partially remote.

The Normalized Location Row

JobsDataAPI returns a locations array. Each row can include:

{
  "kind": "city_state_country",
  "is_primary": true,
  "city_id": 123,
  "city_name": "San Francisco",
  "state_id": 456,
  "state_code": "CA",
  "country_id": 233,
  "country_code": "US",
  "lat": 37.7749,
  "lng": -122.4194,
  "timezone": "America/Los_Angeles"
}

That structure gives your application precise filters without guessing.

How Normalization Works

The backend combines multiple signals:

  1. Structured provider data — some ATS platforms provide addresses or location arrays.
  2. Parsed location strings — free-text locations are split into candidate segments.
  3. Country hints — source context helps disambiguate ambiguous names.
  4. Geo resolution — city, state, and country IDs are resolved against the geographic database.
  5. Deduplication — repeated or overlapping rows are removed.
  6. Remote handling — remote jobs are marked with has_remote and location rows can include remote context.

The result is a stable locations array that can be filtered, displayed, and indexed.

Filtering by Location

Use IDs when you have them:

curl "$CLEANJOBDATA_API_BASE_URL/jobs?city_id=123&remote=true" \
  -H "Authorization: Bearer $CLEANJOBDATA_API_KEY"

You can also filter by country code:

curl "$CLEANJOBDATA_API_BASE_URL/jobs?location=US&title=engineer" \
  -H "Authorization: Bearer $CLEANJOBDATA_API_KEY"

The backend supports:

  • city_id
  • state_id
  • country_id
  • location as an ISO country code fallback

This makes it possible to build reliable feeds for cities, states, countries, and remote roles.

Why It Matters for Product

Normalized locations power better product experiences:

  • city-specific job boards
  • state and country landing pages
  • remote-only filters
  • location chips
  • map views
  • analytics by region
  • SEO pages that match user intent

Without normalization, every page becomes a string-matching problem. With normalized locations, filtering becomes a structured query.

Why It Matters for Search

Location normalization also improves search relevance. A job in San Francisco should not appear because the description mentions California, and a remote job should not be treated the same as an office job unless the filter explicitly asks for it.

That is why JobsDataAPI separates:

  • location as the original display string
  • locations as the structured normalized array
  • has_remote as the remote-work flag

The Takeaway

Location normalization is hard because source data is inconsistent. JobsDataAPI solves it once in the backend so your frontend can filter by city, state, country, and remote status with confidence.