Skip to content

Accuracy & Relevance Scoring

CSV2GEO returns an accuracy_score (0 – 1) and an accuracy label on every geocode and reverse-geocode result. This page explains exactly how those values are computed, what each label means, and how to use them in your application.

We split scoring into two halves because they answer different questions:

  • Forward geocoding (address → coordinates): the score reflects which search phase produced the hit and whether the returned address matches the input components you gave us.
  • Reverse geocoding (coordinates → address): the score reflects how far the returned address point is from your pin. Closer = higher.

Quick reference

accuracy labelMeaningTypical accuracy_score
rooftopExact match on a known address point0.95 – 1.00
buildingReverse hit on the nearest building, 30 – 200 m off the pin0.90
streetForward: street-level match (no exact house number) · Reverse: 200 – 500 m off0.70 – 0.90
interpolatedPosition interpolated along a road segment0.75 – 0.90
postcodeForward: postcode anchor match · Reverse: 500 – 1500 m off (rural) · UK Code-Point0.50 – 0.80
centroidReturned the centroid of a postcode, city, or division0.50 – 0.65
building (reverse)30 – 200 m off pin0.90
cityReverse: > 1500 m off (very rural) — town-level only0.30
approximateState-anchored fallback when no city match existed0.30 – 0.55

Forward Geocoding (address → coordinates)

Forward geocoding runs through a series of search phases, anchored by the strongest geographic signal in your query. The score is calibrated to the phase that produced the result.

Phase-based base score

Search phaseWhat we matchedBase accuracy_scoreaccuracy label
1acountry + postcode + street + house number1.00rooftop
1bcountry + postcode + street0.90interpolated
1ccountry + postcode + house number0.75centroid
1dcountry + postcode only0.65centroid
2acountry + city + street + house number0.95rooftop
2bcountry + city + street0.85interpolated
2ccountry + split city + street + house number0.75interpolated
2.5country + state + house number + street0.55approximate
2.5country + state + street0.40approximate
3acountry + street + house number (no geographic anchor)0.45approximate
3bcountry + street only0.30approximate
divisions fallbackcity centroid (when no street match found)0.50centroid
UK Code-Pointpostcode centroid (UK only, free Ordnance Survey data)0.80postcode

Cross-validation penalty

The base score is multiplied by penalty factors when the returned address disagrees with the input components you supplied:

Field that disagreesMultiplier applied
Postcode (strongest disagreement signal)× 0.5
State / region× 0.4
City× 0.7

Empty input fields are skipped — if you didn't supply a postcode, we can't say the result's postcode is wrong.

If cross-validation pulls the score below 0.85, the accuracy label is downgraded to approximate so downstream consumers don't mistake a flagged result for a clean match.

Why this exists: before cross-validation was added, every result was hard-coded to 1.0 / rooftop regardless of agreement. The motivating bug was a query for Tuttle, OK 73089 silently resolving to Wilson, OK 73463 (~100 mi away) while the API still reported a full match.

Reverse Geocoding (coordinates → address)

Reverse geocoding has a single search phase (a geo-spatial nearest-neighbor query). The score reflects how far the returned address point is from your query pin.

Distance bands

Distance from pinaccuracy labelaccuracy_score
≤ 30 mrooftop1.00
30 – 200 mbuilding0.90
200 – 500 mstreet0.70
500 – 1500 mpostcode0.50
> 1500 mcity0.30

Boundaries are inclusive on the lower edge — a hit at exactly 30.0 m is building (0.90), and exactly 200.0 m is street (0.70).

Why distance bands, not a continuous formula

The thresholds anchor to the canonical lat/long decimal-precision ladder:

DecimalsApproximate accuracyMaps to band
4 – 5~10 mrooftop
3~110 mbuilding (the nearest known address is within a street-width of your pin)
2~1.1 kmpostcode (same neighbourhood)
1~11 kmcity (town-level only)

This is the same ladder every major geocoder uses internally; we surface it as a public, predictable enum so you can compare values across calls without re-deriving them from raw distance.

The radius query parameter

By default, reverse geocoding only returns results within 100 m of your pin. This preserves the legacy behavior of the endpoint — callers who don't pass radius see no change in coverage.

You can opt into a wider search via the ?radius= query parameter (in metres):

GET /v1/reverse?lat=46.49125&lng=-120.395&radius=1000&api_key=geo_live_...
Parameter valueBehavior
OmittedDefault 100 m cap (legacy behavior)
1 – 1500Used as the max search radius
> 1500Clamped to 1500 m
0 or negativeFalls back to default (100 m)
Malformed (non-numeric)Falls back to default (100 m)

Why 1500 m as the max: at greater distances the result has degraded to "town centroid only," which is what the Administrative Divisions and Places APIs are designed for.

Source Attribution

Every result includes a source field telling you where the underlying data came from. Our scoring methodology only applies to data we control. For supplier-sourced rows, we preserve the supplier's own confidence value as-is.

source valueOriginScoring on this source
overtureOverture Maps Foundation — our primary address datasetForward: phase-based + cross-validation · Reverse: distance bands (see above)
hereHERE Geocoder, called as a forward-geocoding fallback when Overture misses. Results are imported into our address store with their confidence preserved.Supplier confidence preserved as-is. We do not re-score HERE results.
googleGoogle Geocoding, called as a final forward fallback. Results imported with their confidence preserved.Supplier confidence preserved as-is. We do not re-score Google results.
divisionsOur own divisions collection (Overture-derived city / region polygons) — used as a city-centroid fallback when no street match is foundFixed 0.50 (centroid)
maxmind-geolite2MaxMind's free IP-geolocation database, used only on /v1/ipNot applicable — the /v1/ip endpoint has its own confidence model

No HERE or Google fallback exists on reverse geocoding. Reverse hits are always source: overture (or empty).

Worked Examples

Forward — clean rooftop match

bash
GET /v1/geocode?q=1600+Pennsylvania+Ave+NW,+Washington,+DC+20500&country=US
json
{
  "results": [{
    "formatted_address": "1600 PENNSYLVANIA Avenue Northwest, Washington, DC 20500, US",
    "accuracy": "rooftop",
    "accuracy_score": 1.0,
    "source": "overture",
    "rank": { "confidence": 1.0, "match_type": "full_match" }
  }]
}

Phase 1a match (postcode + street + house number all anchored). No cross-validation penalty.

Forward — postcode supplied, city wrong

bash
GET /v1/geocode?q=123+Main+St,+Wilson,+OK,+73089&country=US

If 73089 is actually Tuttle and Main St in Tuttle resolves cleanly, the returned address will show city=Tuttle (not Wilson). Cross-validation detects the city disagreement:

base score:    1.00  (Phase 1a)
city penalty:  × 0.7  (returned "TUTTLE" ≠ input "Wilson")
final:         0.70  → label downgrades to "approximate"

The result is still returned (in case the customer mis-typed the city), but the score makes the disagreement explicit.

Reverse — urban rooftop

bash
GET /v1/reverse?lat=38.8977&lng=-77.0365
json
{
  "results": [{
    "formatted_address": "1600 PENNSYLVANIA Avenue Northwest, Mall/East Potomac Park, ...",
    "accuracy": "rooftop",
    "accuracy_score": 1.0,
    "source": "overture"
  }]
}

Pin lands on an indexed address point. Distance ≤ 30 m → rooftop.

Reverse — rural pin, default radius

bash
GET /v1/reverse?lat=46.49125&lng=-120.395
json
{ "results": [] }

The nearest known address is 577 m away. The default 100 m cap returns nothing.

Reverse — rural pin, widened radius

bash
GET /v1/reverse?lat=46.49125&lng=-120.395&radius=1000
json
{
  "results": [{
    "formatted_address": "165 East PARKER HEIGHTS Road, WAPATO, WA 98951, US",
    "accuracy": "postcode",
    "accuracy_score": 0.5,
    "source": "overture"
  }]
}

577 m distance lands in the postcode band → 0.50. You're getting the nearest known address in the same neighbourhood, not the exact parcel at the pin.

How to use accuracy_score in your application

ThresholdBehavior
≥ 0.85Safe to use as a confirmed match. Show on maps without disclaimer.
0.60 – 0.84Useful, but flag it — show "approximate" indicator in UI, ask user to confirm.
0.40 – 0.59Best-effort. Use for analytics / aggregation, not for "this is your delivery address."
< 0.40Treat as a hint, not an answer. Often city-level only.

Combine the score with the accuracy label for richer logic:

python
if result["accuracy"] == "rooftop" and result["accuracy_score"] >= 0.95:
    # Pin on map, no disclaimer
    ...
elif result["accuracy"] in ("building", "street", "interpolated"):
    # Show with "approximate" badge
    ...
elif result["accuracy"] in ("postcode", "centroid", "city", "approximate"):
    # Aggregate-only, don't pin
    ...

What we explicitly don't claim

  • Per-component confidence. Geoapify and HERE expose separate confidence_street_level, confidence_city_level, etc. We currently emit a single overall accuracy_score only.
  • A first-class match_level field. Our accuracy label combines precision (rooftop vs approximate) with granularity (building vs postcode vs city). Major providers separate these into two fields. We may split them in a future API version.
  • Rooftop precision for hits beyond 30 m on reverse. Before May 2026 the API returned accuracy_score: 1.0 for any reverse hit within 100 m. That was overstated. The new distance bands correct it — a hit at 50 m now scores building / 0.90, not rooftop / 1.00.
  • Re-scored supplier results. HERE and Google returns carry their original confidence values, computed by their own matching logic. We expose them as-is and do not re-derive them. Compare scores across source values with that in mind.

Changes

  • 2026-05-23 — Reverse geocoding gained distance-aware scoring (rooftop/building/street/postcode/city bands). Added ?radius= parameter (default 100, max 1500). Default search-cap behavior unchanged; the per-hit score now reflects actual distance rather than hard-coded 1.0.
  • Earlier 2026 — Forward MatchStrength + crossValidate introduced after the Tuttle / Wilson OK misroute. Replaced uniform 1.0 / rooftop with phase-aware scoring.

Batch Geocoding Made Easy