Evaluating geocoding vendors for government RFPs: a technical guide
How public-sector teams evaluate geocoding vendors during an RFP: test files, match rates, batch throughput, confidence scores, and transparent pricing.
Government geocoding procurement is a slow, expensive, and frequently unreliable process. The typical sequence: someone writes a requirements document that specifies "95% match rate at rooftop accuracy," three vendors respond with marketing claims that all reach exactly 95%, and the contract goes to the lowest bidder. Two quarters later the first data run produces a 71% match rate on addresses in rural counties and the programme team spends the next year arguing over cure periods and remedies.
The root cause is straightforward. Most government RFPs are written without a technical pre-evaluation. Nobody runs actual address data through competing services before the procurement is closed. The requirements are written from a wishlist, not from a measurement.
This post is a practical guide for the technical lead on a government programme team — the person who has to make the geocoding work, not just procure it. The goal is to give you a repeatable method to evaluate any geocoding vendor before your agency is locked into a contract. That method uses CSV2GEO's free tier (3,000 calls per day, no credit card required) as a concrete worked example, but the pattern applies to any vendor who offers a REST interface and a trial.
By the end you will have a test harness, a scoring spreadsheet, a set of questions to ask every vendor, and a clear view of what "transparent pricing" actually looks like in practice.
Why government addresses are harder than they look
Before building the test file, it is worth being precise about why government use cases stress geocoding services in ways that typical commercial workloads do not.
Rural and tribal addressing. Most commercial geocoding services are tuned on urban and suburban data where density is high and address formats are consistent. A rural route address — "RR 4 Box 119, Hayward WI" — or a tribal address that references a highway mile marker rather than a street number will often fail silently: the geocoder returns a ZIP centroid or a county centroid and reports a match. Coordinate accuracy at those fallback levels is measured in kilometres, not metres. If your programme is routing ambulances or delivering benefit letters, a county-centroid match is effectively a wrong answer.
PO Box and non-delivery addresses. Government datasets frequently include PO Boxes, unit addresses, and mailstop codes that are valid postal addresses but have no rooftop coordinate. A geocoder that normalises these to the post office location rather than the underlying physical address will silently degrade your dataset quality. The match will register as "success" in a naive count, but the coordinate is wrong.
Historical or non-standard street names. Older GIS datasets in county assessors' offices use street names that pre-date USPS standardisation. A street recorded as "S. Broad St." in 1987 might not match a geocoder trained on "South Broad Street." Parse errors here cost you match rate on addresses that are otherwise entirely correct.
Volume and throughput. A state tax authority geocoding its annual property roll has 10–15 million records. A transit authority doing a service-area analysis has hundreds of thousands of trip-origin addresses per month. These are not the workloads a free-tier trial was designed for, but you need to understand the throughput ceiling before the contract is signed, not after.
A representative test file has to include all four categories or your evaluation will look better than reality.
Building a representative test file
This is the single step most procurement teams skip, and it is the most important one.
A good government test file has five components:
1. Urban addresses with building-level precision. Pull 200 addresses from a city in your programme's service area: a mix of residential, commercial, and municipal addresses. These are the easy cases; every vendor should score well here. Include them as a sanity check — any vendor that scores below 90% on clean urban addresses has already failed.
2. Rural and small-town addresses. Pull 200 addresses from rural counties. Include RR and HC box addresses if your data has them. Include tribal land addresses if applicable. Include addresses where the ZIP code alone would be a multi-kilometre bounding box. This is where vendors diverge sharply.
3. Known-bad or messy addresses. Pull 50 addresses with deliberate imperfections: misspelled street names, missing unit numbers, street-type abbreviation variants, addresses where the city field is a neighbourhood name rather than the postal city. Every production dataset has these. A vendor that fails on all 50 is less useful than one that recovers on 35 of them.
4. Non-residential addresses. Pull 50 government facility addresses: courthouses, utility substations, fire stations, vehicle maintenance depots. These often sit on large parcels where "rooftop" is a multi-acre footprint and coordinate precision is inherently lower.
5. Address-only records with no coordinate. Include 50 records where you have no lat/lng at all — you are entirely dependent on the geocoder. If you can, include five of these from outside the country; knowing how a vendor handles an out-of-scope address gracefully matters.
Total test file: 550 rows. Small enough to run on the free tier in a single day. Large enough to reveal real failure modes.
Give the file a column header row: id,address_line1,address_line2,city,state,zip,expected_lat,expected_lng. For the urban and some rural records where you have good existing GIS data, populate expected_lat and expected_lng — you will use these to measure coordinate accuracy, not just match rate. Leave them blank for the records where you do not have ground truth.
How to submit the test file to CSV2GEO
CSV2GEO offers two routes for evaluation: the web batch tool and the REST API. Both are accessible under the free tier without procurement friction — no sales call, no quote, no NDAs before you can run a test.
The web batch tool
Navigate to the CSV2GEO batch tool, upload your 550-row CSV, and map your columns. The credit cost is one credit per address row — 550 credits from your free tier's 3,000-per-day allowance. Results download as a CSV with the geocoder's returned lat/lng, a normalised address, a match type, and a confidence score. This is the fastest way to get results without writing a line of code, which matters if the technical lead for evaluation is a GIS analyst rather than a software engineer.
The confidence score column is the first thing to look at. CSV2GEO returns a confidence field between 0 and 1 on every result. A confidence of 1.0 indicates a full rooftop or parcel-level match. A confidence of 0.5 or below typically indicates the geocoder fell back to a street-level interpolation, a postal-code centroid, or a city centroid. Your acceptance threshold — the minimum confidence you will accept as a "match" in your programme — belongs in the RFP's technical specification. A vendor who does not return a machine-readable confidence score on every response cannot be evaluated this way, and that alone should be a disqualifying criterion in your requirements document.
For a deeper treatment of how to interpret these scores, see Geocoding Confidence Scores Explained.
The REST API for automated evaluation
If your evaluation team is comfortable with curl or Python, the REST interface gives you more control over what you log and measure. Here is a minimal example that processes a single address and returns the confidence and coordinates:
curl -s "https://csv2geo.com/api/v1/geocode" \
--data-urlencode "q=123 Main Street, Springfield, IL 62701" \
--data-urlencode "api_key=$CSV2GEO_API_KEY" \
-G | jq '{lat: .results[0].lat, lng: .results[0].lng, confidence: .results[0].confidence}'And a Python script that processes every row in your test file and writes a scored output CSV:
import csv
import os
import time
import requests
API = "https://csv2geo.com/api/v1/geocode"
KEY = os.environ["CSV2GEO_API_KEY"]
def geocode(address: str) -> dict:
r = requests.get(
API,
params={"q": address, "api_key": KEY},
timeout=30,
)
r.raise_for_status()
results = r.json().get("results", [])
if not results:
return {"lat": None, "lng": None, "confidence": None, "match_type": "no_result"}
top = results[0]
return {
"lat": top.get("lat"),
"lng": top.get("lng"),
"confidence": top.get("confidence"),
"match_type": top.get("match_type", "unknown"),
}
with open("test_file.csv") as fin, open("results.csv", "w", newline="") as fout:
reader = csv.DictReader(fin)
out_fields = reader.fieldnames + ["result_lat", "result_lng", "confidence", "match_type"]
writer = csv.DictWriter(fout, fieldnames=out_fields)
writer.writeheader()
for row in reader:
address = " ".join(filter(None, [
row.get("address_line1"), row.get("address_line2"),
row.get("city"), row.get("state"), row.get("zip")
]))
result = geocode(address)
row.update({
"result_lat": result["lat"],
"result_lng": result["lng"],
"confidence": result["confidence"],
"match_type": result["match_type"],
})
writer.writerow(row)
time.sleep(0.05) # stay comfortably below free-tier rate limitsAnd the equivalent Node script for teams whose stack is JavaScript:
import { createReadStream, createWriteStream } from 'node:fs';
import { parse } from 'csv-parse';
import { stringify } from 'csv-stringify';
const API = 'https://csv2geo.com/api/v1/geocode';
const KEY = process.env.CSV2GEO_API_KEY;
async function geocode(address) {
const url = `${API}?q=${encodeURIComponent(address)}&api_key=${KEY}`;
const r = await fetch(url);
if (!r.ok) throw new Error(`http ${r.status}`);
const body = await r.json();
const top = body.results?.[0];
if (!top) return { lat: null, lng: null, confidence: null, match_type: 'no_result' };
return { lat: top.lat, lng: top.lng, confidence: top.confidence, match_type: top.match_type ?? 'unknown' };
}
// Wrap in an async IIFE, process rows, write output.csv — pattern omitted for brevity.
// The geocode() function above is the core; wire it into your CSV pipeline as needed.Both scripts write a results.csv that you can open in any spreadsheet to begin scoring.
Step 1: Score match rate by address segment
Open your results CSV. Add a column: accepted — 1 if confidence >= 0.7, else 0. (You can adjust this threshold; 0.7 is a reasonable starting point for most government programmes.)
Calculate acceptance rate for each of your five address segments separately:
- Urban residential and commercial
- Rural and small-town
- Deliberately messy addresses
- Non-residential government facilities
- Address-only (no coordinate)
A vendor that scores 97% overall but 51% on rural addresses is not a 97% vendor for a state-wide programme. The segmented score is the only number that tells you the truth. Include this segmentation methodology in your RFP's evaluation criteria — require every vendor to report match rate per segment, not as an aggregate. Any vendor that refuses to accept a segmented test file should be treated with the same scepticism you would apply to a surveyor who refuses to show their working.
Step 2: Measure coordinate accuracy on records where you have ground truth
For the subset of your test file where you populated expected_lat and expected_lng, compute the haversine distance between the geocoder's returned coordinate and your known coordinate. Express it in metres.
A simple Python snippet:
import math
def haversine_m(lat1, lng1, lat2, lng2):
R = 6_371_000 # Earth radius in metres
phi1, phi2 = math.radians(lat1), math.radians(lat2)
dphi = math.radians(lat2 - lat1)
dlambda = math.radians(lng2 - lng1)
a = math.sin(dphi / 2) ** 2 + math.cos(phi1) * math.cos(phi2) * math.sin(dlambda / 2) ** 2
return R * 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))Calculate the median distance error, the 90th percentile, and the maximum. Median and 90th percentile together tell the story — a vendor with a 15 m median but a 3,500 m 90th percentile has a rural centroid problem hiding inside an acceptable average. The maximum error is where the real failures live.
For a thorough treatment of why averages mislead on coordinate accuracy, see Benchmarking Geocoding APIs — Honest Numbers.
Step 3: Test batch throughput under realistic load
Government workloads are not steady-state. They come in large periodic runs: a state property roll once a year, a voter file refresh before an election, a benefits eligibility recalculation at fiscal year end. The question to answer before the contract is signed is: can this vendor sustain the throughput I need during a bulk run, and at what cost?
CSV2GEO's batch endpoint accepts address rows in bulk and processes them as a job. The web batch tool exposes this for files; the REST API exposes it programmatically. For your evaluation, the important test is: submit a 1,000-row batch, measure wall-clock time, confirm all rows are returned and none are silently dropped.
A pattern for programmatic batch submission using the REST API:
import requests, os, json
BATCH_API = "https://csv2geo.com/api/v1/geocode/batch"
KEY = os.environ["CSV2GEO_API_KEY"]
addresses = [
"742 Evergreen Terrace, Springfield, IL",
# ... up to your batch size
]
r = requests.post(
BATCH_API,
headers={"Content-Type": "application/json"},
data=json.dumps({"addresses": addresses, "api_key": KEY}),
timeout=120,
)
r.raise_for_status()
results = r.json()["results"]
print(f"Submitted {len(addresses)}, received {len(results)}")Log the following from your throughput test: total rows submitted, rows returned, rows with confidence < 0.5 (these are the low-quality fallbacks), and wall-clock seconds. This data belongs in your RFP evaluation scoring matrix as a vendor-provided artefact — ask every vendor to run the same 1,000-row test file and submit their throughput results alongside their pricing response.
For monitoring this kind of pipeline in production, the patterns in Observability for Geocoding Pipelines apply directly.
Step 4: Stress test your acceptance threshold with confidence scores
This step is often skipped in government evaluations and is the most operationally useful one.
Your programme will eventually need to define an automated acceptance rule: "accept this geocoded coordinate for downstream use if the confidence score is at or above X." Too low and you are feeding bad coordinates into routing, mapping, or statistical analysis. Too high and you are rejecting valid matches that happen to be rural or non-standard in format.
Run your results CSV through a confidence threshold sweep. For each threshold from 0.5 to 1.0 in steps of 0.1, compute:
- Acceptance rate (percentage of rows that pass)
- Mean coordinate error on accepted rows (using your haversine calculation)
- Mean coordinate error on rejected rows (to quantify what you are filtering out)
Plot the acceptance rate and mean error together. The threshold you want is where the mean error drops to an acceptable level without acceptance rate collapsing below your programme's coverage requirement. For most government programmes, a threshold somewhere between 0.65 and 0.80 balances coverage against accuracy. Build that threshold into your data pipeline as a first-class configuration parameter, not a hard-coded constant — different use cases within the same contract may warrant different thresholds.
Step 5: Compare pricing with total-cost transparency
This is where government procurement most frequently goes wrong. A vendor quotes a per-call price; the procurement team multiplies by estimated annual volume; the contract is signed. Two surprises arrive in the first year: the "per call" definition is narrower than expected (a batch of 1,000 counts as 1,000 calls, not 1 call), and the vendor requires a minimum annual commit that the programme cannot exit gracefully.
For a transparent pricing evaluation, ask every vendor the same three questions in writing:
- What exactly counts as a billable call? Does a batch of 500 addresses cost 500 credits or 1 credit?
- Is there a minimum annual commit, and what are the terms if you consume fewer?
- Is the pricing on your public pricing page the actual price, or is it a base rate that adjusts based on data type, geography, or volume tier?
CSV2GEO publishes its pricing at csv2geo.com/pricing/api and the published numbers are the actual prices — no quote process for the standard tiers, no annual minimum. The free tier (3,000 calls per day) is genuinely usable for pilot evaluation without providing procurement justification to a sales team. Paid tiers start at $54/month for 100,000 calls. Credits equal address rows — a batch file with 200 rows costs 200 credits. There is no ambiguity to arbitrage in the billing model.
That model may or may not be the best fit for your programme's volume and budget. The point is that you can verify the claim before the contract is signed by running the evaluation and watching the credit counter — not by reading a vendor's terms sheet and hoping.
Questions to ask every vendor in the RFP response
These belong in the technical evaluation section of your RFP as required written responses. Vendors who decline to answer them in writing are telling you something important.
Coverage claim. "State that your address dataset size, the date it was last updated, and the number of countries covered." A vendor who references "504 million addresses across 63 countries" (as CSV2GEO does) can be tested directly. A vendor who says "comprehensive coverage" has told you nothing.
Confidence scoring. "Does every response include a machine-readable confidence or match-quality score? Describe the scoring scale and what each level represents." A vendor without machine-readable confidence scoring cannot be integrated into an automated acceptance pipeline without significant custom work on your end.
Fallback behaviour. "When a full rooftop match is not available, describe the fallback hierarchy — street interpolation, postal centroid, city centroid, county centroid — and whether each fallback is distinguishable in the response." Silent fallbacks are the root cause of most post-award quality disputes.
Data lineage. "Describe the data sources used to geocode addresses in rural areas and tribal lands. What is the update cadence for those sources?" You do not need the source names — but you do need to know that the vendor can answer the question at all.
Compliance posture. "Which of the following certifications or assessments does your platform hold, and can you provide documentation: FedRAMP, StateRAMP, SOC 2 Type II, HIPAA/BAA availability?" Compliance status is a vendor claim that requires documentation; it is not something to accept on the basis of a checkbox in a sales form. Whether these certifications are required for your specific programme depends on your legal team and your agency's data classification rules — ask the question, then verify the answer.
SLA and remedies. "State your uptime commitment, measurement methodology, and the remedies available to the contracting agency if the commitment is not met." An SLA that offers a prorated credit for downtime is a different commercial instrument from one that triggers contract termination rights.
None of these questions should surprise a reputable vendor. A vendor who pushes back on providing written answers to any of them in an RFP response has given you useful information about how the relationship will go after the contract is signed.
A note on the free-tier evaluation workflow
The practical advantage of the free tier for government evaluation is that it removes procurement friction from the technical assessment. A GIS analyst who wants to test 500 addresses this afternoon does not need a signed NDA, a vendor demo call, a sandbox access request, or a purchase order. They create an account, retrieve an API key from /api-keys, and run the test. The 3,000-call daily limit is enough to cover the full 550-row test file described above with room for reruns and debugging.
The web batch tool is the fastest path for an analyst who is comfortable with CSV but not with curl or Python. Upload the file, map the columns, download the results. The REST API is the right path if the evaluation needs to be scripted, logged, and reproduced — which it should, since the evaluation results become an artefact in the procurement record.
One practical note: when you retrieve your API key for evaluation purposes, treat it with the same access controls you would use for a production key. Government IT environments often have strict controls on credential storage; do not paste an API key into a spreadsheet or an email thread. The /api-keys page allows you to create evaluation-specific keys and revoke them independently of any production keys you later provision.
Turning the evaluation into RFP language
Once you have run the evaluation and scored the results, the numbers feed directly into the technical requirements section of your RFP. Reasonable thresholds based on what a well-performing service produces on a clean urban-rural mix:
- Minimum acceptance rate (confidence ≥ 0.70): 88% overall, 80% on rural segment
- Maximum coordinate error at 90th percentile: 150 metres for rooftop/parcel matches, 500 metres for street-level matches
- Batch throughput: 10,000 rows completable within 60 minutes
- Response format: JSON with machine-readable confidence score on every result
- Availability of a no-cost evaluation tier or sandbox environment prior to contract award
These numbers are not universal — adapt them to your programme's actual use case. An ambulance routing programme has different accuracy requirements from a survey-sampling frame. The point is that having run the evaluation yourself, you can write requirements that are anchored to measurements rather than to marketing copy, and you can score competing proposals against those requirements in a technically defensible way.
---
Frequently Asked Questions
Can I run the evaluation entirely on the free tier without involving a sales team?
Yes. CSV2GEO's free tier is 3,000 calls per day and requires no credit card or sales contact. You create an account, retrieve your API key from /api-keys, and start running test data immediately. The 3,000-call daily limit covers the full 550-row test file described in this post — including reruns — without any commercial commitment. If your evaluation scales to tens of thousands of test rows, you will need a paid plan, but the methodology and scoring framework established on the free tier transfers directly.
What should I do if a vendor refuses to provide a segmented match-rate result?
Treat it as a significant yellow flag. An aggregate match rate across a mixed address dataset is meaningless for government procurement because it averages away the rural and non-standard address failure modes that matter most to programme delivery. Ask the vendor specifically: "Please provide match rate separately for urban addresses, rural addresses, and addresses with non-standard formatting." If they refuse or say their system cannot generate this report, you are likely looking at a vendor whose product performs well on clean urban data and has not invested in the address types your programme actually has.
How do confidence scores map to practical accuracy?
This varies by vendor, so measure it directly during evaluation rather than taking the vendor's word for it. The method in Step 4 of this post — sweeping the acceptance threshold and measuring mean coordinate error at each level — gives you an empirical answer for the specific dataset and the specific vendor you are evaluating. As a rough rule of thumb for CSV2GEO's scoring, a confidence of 0.9 or above almost always indicates a rooftop or parcel-level match with a coordinate error well under 50 metres. A confidence below 0.5 usually indicates a centroid fallback of some kind. The exact boundaries depend on your address mix.
Is the batch tool appropriate for the actual production workload, or just for evaluation?
The web batch tool is appropriate for one-off production runs where a staff member uploads a file and downloads results — an annual property roll refresh, a voter file update, a one-time address normalisation project. For automated pipelines that run on a schedule without human intervention, the REST batch API is the right pattern. Both use the same underlying geocoding engine and produce the same confidence scores; the tool is just a UI wrapper around the API.
What compliance certifications does CSV2GEO hold?
We are not making compliance certification claims in this post, and you should not accept any vendor's compliance claims without documentation. For your RFP, ask every vendor to provide written evidence of any certifications they claim — FedRAMP authorisation letters, SOC 2 Type II audit reports, HIPAA BAA availability documentation. Whether a particular certification is required for your programme depends on your agency's data classification rules, your legal team, and the nature of the address data involved. Those are questions to put to your agency counsel, not to the vendor's sales team.
How do I handle addresses that fall below my acceptance threshold in a production pipeline?
Low-confidence results need a defined handling path before you go live — not an ad hoc decision when the first batch of failures arrives. Three common patterns: (1) route low-confidence records to a manual review queue where a GIS analyst corrects the address and re-submits; (2) accept them but flag them in the output with a geocode_quality = low marker so downstream consumers know to treat them differently; (3) reject them entirely and return them to the data owner for correction. Which pattern is right depends on whether a downstream miss is recoverable and how large your team is. Build the threshold as a configuration parameter so you can adjust it without a code change when policy or data quality shifts.
Does batch pricing mean 1,000 addresses cost 1,000 credits or 1 credit?
For CSV2GEO, credits equal address rows. A batch file with 1,000 address rows costs 1,000 credits. The batch tool saves you HTTP round-trip overhead and simplifies your pipeline, but it does not change the per-address cost. This is stated plainly on the pricing page at csv2geo.com/pricing/api. Ask every vendor you evaluate the same question in writing — the answer varies significantly and the difference compounds quickly at government-programme volumes.
---
Related Articles
- Benchmarking Geocoding APIs — Honest Numbers — what to measure, what to ignore, and why aggregated match rate numbers are almost always misleading
- Geocoding Confidence Scores Explained — a detailed treatment of what confidence values mean and how to set acceptance thresholds for automated pipelines
- Caching Geocoding Results — 90% Cost Reduction — how to structure a caching layer that dramatically reduces cost on large recurring government workloads
- Observability for Geocoding Pipelines — metrics, alerting, and logging patterns for a geocoding pipeline running in a government production environment
- Rate Limiting — Token Bucket vs Leaky Bucket — understanding rate-limit mechanics so bulk evaluation runs and production batch jobs stay within tier limits without manual throttling
---
*I.A. / CSV2GEO Creator*
Use our batch geocoding tool to convert thousands of addresses to coordinates in minutes. Start with 100 free addresses.
Try Batch Geocoding Free →