A command-line interface for the Geocodio API that lets you geocode addresses, reverse geocode coordinates, calculate distances, and process spreadsheets—all from your terminal.
Whether you're geocoding a single address or processing thousands in batch, this CLI gives you quick access to Geocodio's powerful geocoding capabilities without writing any code.
- Getting Started
- Configuration
- Cost and Billing
- Commands
- Output Formats
- Global Flags
- AI Coding Assistant Skill
- Development
- Troubleshooting
- License
- A Geocodio API key (get one at geocod.io)
Quick install (recommended):
curl -fsSL https://raw.githubusercontent.com/geocodio/geocodio-cli/main/install.sh | shInstall a specific version:
curl -fsSL https://raw.githubusercontent.com/geocodio/geocodio-cli/main/install.sh | sh -s -- --version v1.0.0With Go:
go install github.com/geocodio/geocodio-cli/cmd/geocodio@latestOnce installed, set your API key and try geocoding an address:
export GEOCODIO_API_KEY=your-api-key
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC"You'll see the latitude, longitude, and formatted address returned by the API.
You can provide your API key in two ways:
Environment variable (recommended):
export GEOCODIO_API_KEY=your-api-keyCommand-line flag:
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC" --api-key your-api-keyTip
Add the export command to your shell profile (~/.bashrc, ~/.zshrc, etc.) so you don't have to set it every session.
Geocodio API keys carry per-feature permissions. The lists and distance commands (distance, distance-matrix, and distance-jobs) only work when spreadsheet and distance access are enabled for the key you are using. You can turn them on at dash.geocod.io/apikey.
If those commands return a 403 while geocode works fine, the key is valid and the permission is missing.
Every command here spends lookups on your Geocodio account. One lookup is one credit, and a run costs:
records × (1 + number of append categories)
- Appends are not free. Each category in
--fieldsis a full extra lookup per record.--fields timezone,cdon 1,000 addresses costs 3,000 lookups, not 1,000. - Distance commands cost geocoding for any input given as an address, plus
origins × destinations × mode multiplier, plus any appends. Straightline counts 1× per pair, driving counts 2×. - Free tier: the first 2,500 lookups each day are free on pay-as-you-go and Flex plans. The allowance resets daily and does not roll over.
- Zero-result lookups are not billed. An address that returns no match costs nothing.
- Pass
--skip-geocodingwhen you already have coordinates and only need field appends. - Store the
stable_address_keyreturned by--show-address-key, then skip records you have geocoded before. - Pass coordinates instead of addresses to
distance,distance-matrix, anddistance-jobs, so there is nothing left to geocode. - Use
--mode straightlineunless you need real driving routes. Driving costs twice as much per pair. - Request only the append fields you use. Every extra category multiplies the whole run.
A usage limit on your account caps what a run can spend, which is worth setting before the first big file: Set a usage limit.
For plan and per-lookup rates, see Geocodio pricing. To size a plan against your own volume, use the plan calculator.
Convert addresses into geographic coordinates.
Single address:
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC"With data appends:
Geocodio can return additional data like timezone, congressional district, census data, and more. Specify fields with the --fields flag:
geocodio geocode "30 Rockefeller Plaza, New York NY" --fields timezone,cdImportant
Appends are not free. Each --fields category is a full extra lookup per record, so --fields timezone,cd on 1,000 addresses costs 3,000 lookups instead of 1,000. See Cost and Billing and Geocodio's field documentation.
United Kingdom data appends are available too — for example Westminster and devolved constituencies and local authority wards:
geocodio geocode "10 Downing St, London" --country "United Kingdom" --fields uk-westminster,uk-localUK field appends: uk-westminster, uk-westminster-next, uk-devolved, uk-devolved-next, uk-local, uk-local-next. The -next variants return upcoming boundary changes.
Note
United Kingdom addresses need a Flex or Unlimited+UK plan. UK geocoding is not available on pay-as-you-go. See Geocodio pricing.
Batch geocoding from a file:
For processing many addresses at once, create a file with one address per line and use the --batch flag:
geocodio geocode --batch addresses.txtWhen running in a terminal, you'll see a spinner while the batch processes.
Important
--batch caps at 10,000 lookups per request, and appends count toward that cap: 5,000 addresses with one --fields category already reaches the limit. A full 10,000-lookup batch can take around 600 seconds, so set script and client timeouts accordingly.
For anything larger, and for any spreadsheet, prefer lists upload. It runs asynchronously, handles up to 10 million lookups, needs no file splitting, and reports progress with --watch.
With inline distance calculations:
Geocode an address and calculate distances to one or more destinations in a single request:
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC" --destinations "New York" --destinations "Boston"With driving mode for actual driving distance and duration:
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC" --destinations "New York" --distance-mode drivingWith stable address key:
Show the stable address key for a result, which can be used in future requests instead of an address:
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC" --show-address-keyJSON output:
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC" --jsonAll geocode flags:
| Flag | Alias | Description |
|---|---|---|
--batch |
-b |
File containing addresses (one per line) |
--fields |
-f |
Data append fields (comma-separated) |
--limit |
-l |
Maximum number of results per address |
--country |
-c |
Country hint, recommended for non-US data (e.g. USA, Canada, United Kingdom) |
--destinations |
-d |
Destination addresses or coordinates for distance calculation (repeatable) |
--distance-mode |
-m |
Distance mode: straightline (default, 1 credit per calculation) or driving (2 credits per calculation) |
--distance-units |
-u |
Distance units: miles or km |
--distance-max-distance |
--distance-radius |
Radius limit: only keep destinations within this distance |
--distance-min-distance |
Only keep destinations at least this far away | |
--distance-max-duration |
Only keep destinations within this travel time in seconds (driving only) | |
--distance-min-duration |
Only keep destinations at least this many seconds away (driving only) | |
--distance-max-results |
Only keep the N nearest destinations per result | |
--distance-order-by |
Sort destinations by: distance or duration |
|
--distance-sort-order |
Sort direction: asc or desc |
|
--show-address-key |
Show stable address key in output |
Tip
Pass --country whenever your data is not from the United States. Without it the API falls back to the US, which returns confident but wrong matches for addresses elsewhere.
Convert coordinates back into addresses.
Single coordinate pair:
geocodio reverse "38.8976,-77.0365"Batch reverse geocoding:
geocodio reverse --batch coordinates.txtThe coordinates file should have one lat,lng pair per line:
38.8976,-77.0365
40.7128,-74.0060
34.0522,-118.2437
Skip geocoding (fields only):
Get only field appends (timezone, census data, etc.) for coordinates without reverse geocoding an address:
geocodio reverse "40.7588,-73.9788" --skip-geocoding --fields timezone,cdWith inline distance calculations:
geocodio reverse "38.8976,-77.0365" --destinations "New York" --distance-mode drivingAll reverse flags:
| Flag | Alias | Description |
|---|---|---|
--batch |
-b |
File containing coordinates (one per line) |
--fields |
-f |
Data append fields (comma-separated) |
--limit |
-l |
Maximum number of results per coordinate |
--skip-geocoding |
Skip reverse geocoding, only return field appends | |
--destinations |
-d |
Destination addresses or coordinates for distance calculation (repeatable) |
--distance-mode |
-m |
Distance mode: straightline (default, 1 credit per calculation) or driving (2 credits per calculation) |
--distance-units |
-u |
Distance units: miles or km |
--distance-max-distance |
--distance-radius |
Radius limit: only keep destinations within this distance |
--distance-min-distance |
Only keep destinations at least this far away | |
--distance-max-duration |
Only keep destinations within this travel time in seconds (driving only) | |
--distance-min-duration |
Only keep destinations at least this many seconds away (driving only) | |
--distance-max-results |
Only keep the N nearest destinations per result | |
--distance-order-by |
Sort destinations by: distance or duration |
|
--distance-sort-order |
Sort direction: asc or desc |
|
--show-address-key |
Show stable address key in output |
Calculate distances from one origin to one or more destinations.
Basic usage:
geocodio distance "Washington DC" "New York"Multiple destinations:
geocodio distance "Washington DC" "New York" "Boston" "Philadelphia"With options:
geocodio distance "Washington DC" "New York" --mode driving --units kmRadius limiting:
Use --radius (an alias for --max-distance) to drop destinations that fall outside a radius around the origin. The value is interpreted in whatever --units is set to.
# Only the destinations within 150 miles of Washington DC
geocodio distance "Washington DC" "New York" "Boston" "Philadelphia" --radius 150
# Same, in kilometers
geocodio distance "Washington DC" "New York" "Boston" "Philadelphia" --radius 250 --units km
# A ring: at least 50 miles out, at most 150
geocodio distance "Washington DC" "New York" "Boston" "Philadelphia" --min-distance 50 --max-distance 150You can also limit by travel time instead of distance, and keep only the nearest few:
# Within a two-hour drive
geocodio distance "Washington DC" "New York" "Boston" "Philadelphia" --mode driving --max-duration 7200
# The three closest destinations, longest drive first
geocodio distance "Washington DC" "New York" "Boston" "Philadelphia" \
--max-results 3 --order-by duration --sort-order descDistance flags:
| Flag | Alias | Default | Description |
|---|---|---|---|
--mode |
-m |
straightline |
Routing mode: straightline (1 credit per calculation) or driving (2 credits per calculation) |
--units |
-u |
miles |
Distance units: miles or km |
--country |
-c |
Country to append to addresses, recommended for non-US data (e.g. USA, Canada, United Kingdom) |
|
--max-distance |
--radius |
Radius limit: only keep destinations within this distance (in --units) |
|
--min-distance |
Only keep destinations at least this far away (in --units) |
||
--max-duration |
Only keep destinations within this travel time in seconds (driving mode only) | ||
--min-duration |
Only keep destinations at least this many seconds away (driving mode only) | ||
--max-results |
Only keep the N nearest destinations | ||
--order-by |
distance |
Sort destinations by: distance or duration |
|
--sort-order |
asc |
Sort direction: asc or desc |
Tip
straightline is the default: it gives "as the crow flies" distances and costs 1 credit per calculation. Pass --mode driving only when you need actual road distance or travel time — it costs 2 credits per calculation.
Note
--max-duration and --min-duration only apply in driving mode, since straightline results have no travel time. Pass --mode driving alongside them.
Note
distance-matrix and distance-jobs create print the calculation count, the mode, and an estimated credit cost to stderr before submitting anything larger than 10,000 calculations. You can cap spend on the account with a usage limit.
Important
A distance run costs geocoding for every input given as an address, plus one lookup per origin/destination pair in straightline mode or two per pair in driving mode, plus any appends. Passing coordinates instead of addresses removes the geocoding cost. See Cost and Billing.
Calculate distances between multiple origins and multiple destinations. This is useful for logistics, delivery routing, or finding the closest locations.
geocodio distance-matrix --origins origins.txt --destinations destinations.txtBoth files should contain one location per line (addresses or coordinates).
The same radius and travel-time limits available on distance apply here, per origin. This is how you answer "which of my stores is within 10 miles of each customer?" without post-processing the full matrix:
geocodio distance-matrix --origins customers.txt --destinations stores.txt --radius 10
# Nearest store to each customer, by driving time
geocodio distance-matrix --origins customers.txt --destinations stores.txt \
--mode driving --max-results 1 --order-by durationDistance matrix flags:
| Flag | Alias | Required | Default | Description |
|---|---|---|---|---|
--origins |
-o |
Yes | — | File containing origin locations |
--destinations |
-d |
Yes | — | File containing destination locations |
--mode |
-m |
No | straightline |
Routing mode: straightline (1 credit per calculation) or driving (2 credits per calculation) |
--units |
-u |
No | miles |
Distance units: miles or km |
--country |
-c |
No | Country to append to addresses, recommended for non-US data | |
--max-distance |
--radius |
No | Radius limit: only keep destinations within this distance (in --units) |
|
--min-distance |
No | Only keep destinations at least this far away (in --units) |
||
--max-duration |
No | Only keep destinations within this travel time in seconds (driving mode only) | ||
--min-duration |
No | Only keep destinations at least this many seconds away (driving mode only) | ||
--max-results |
No | Only keep the N nearest destinations per origin | ||
--order-by |
No | distance |
Sort destinations by: distance or duration |
|
--sort-order |
No | asc |
Sort direction: asc or desc |
Important
A matrix costs origins × destinations pairs, doubled in driving mode, plus geocoding for any inputs given as addresses. A 500 × 500 matrix is 250,000 pairs, so check the numbers (and your usage limit) before a large run. See Cost and Billing.
For large distance calculations, use async jobs. These run in the background and you can check their status or download results later.
Create a job:
geocodio distance-jobs create --name "My Job" --origins origins.txt --destinations destinations.txtCreate and watch progress:
geocodio distance-jobs create --name "My Job" --origins origins.txt --destinations destinations.txt --watchWhen running in a terminal, you'll see an animated progress bar showing the job's completion status.
List all jobs:
geocodio distance-jobs listCheck job status:
geocodio distance-jobs status 12345
# Watch until completion
geocodio distance-jobs status 12345 --watchDownload results:
# Output to stdout
geocodio distance-jobs download 12345
# Save to file
geocodio distance-jobs download 12345 --output results.csvDelete a job:
geocodio distance-jobs delete 12345Distance jobs create flags:
| Flag | Alias | Required | Default | Description |
|---|---|---|---|---|
--name |
-n |
Yes | — | Job name for identification |
--origins |
-o |
Yes | — | File containing origin locations |
--destinations |
-d |
Yes | — | File containing destination locations |
--mode |
-m |
No | straightline |
Routing mode: straightline (1 credit per calculation) or driving (2 credits per calculation) |
--units |
-u |
No | miles |
Distance units: miles or km |
--watch |
-w |
No | false |
Watch progress until completion |
Important
Async jobs are priced the same way as distance-matrix: origins × destinations pairs, doubled in driving mode, plus geocoding for address inputs. The job size is the whole matrix, so a job created by mistake can spend a lot of lookups. See Cost and Billing.
Geocode CSV or Excel files without splitting them. Geocodio processes the file asynchronously and returns results with coordinates appended to your data. This is the recommended path for spreadsheets and for anything above the 10,000-lookup --batch cap: a list handles up to 10 million lookups.
Upload a file:
geocodio lists upload data.csv --direction forward --format "{{A}} {{B}}, {{C}}"The --format flag tells Geocodio which columns contain address components. Use {{A}}, {{B}}, {{C}}, etc. to reference columns:
{{A}}= Column A (first column){{B}}= Column B (second column)- And so on...
Example: If your CSV has street in column A, city in column B, and state in column C:
geocodio lists upload addresses.csv --direction forward --format "{{A}}, {{B}}, {{C}}"Upload and watch progress:
geocodio lists upload data.csv --direction forward --format "{{A}}" --watchList all uploaded spreadsheets:
geocodio lists listCheck status:
geocodio lists status 12345
# Watch until completion
geocodio lists status 12345 --watchDownload results:
# Output to stdout
geocodio lists download 12345
# Save to file
geocodio lists download 12345 --output geocoded.csvDelete a spreadsheet:
geocodio lists delete 12345Lists upload flags:
| Flag | Alias | Required | Description |
|---|---|---|---|
--direction |
-d |
Yes | forward (address→coords) or reverse (coords→address) |
--format |
-f |
Yes | Column format template (e.g., {{A}} {{B}}, {{C}}) |
--watch |
-w |
No | Watch progress until completion |
--callback |
— | No | URL to receive a POST request when processing completes |
--fields |
-F |
No | Data append fields (comma-separated, e.g., cd,timezone) |
Warning
Large spreadsheets can take time to process. Use the --watch flag or check status periodically rather than waiting for immediate results.
Important
A list costs records × (1 + number of append categories) lookups, the same as batch geocoding. --fields cd,timezone on a 100,000-row spreadsheet is 300,000 lookups. Spreadsheet access also has to be enabled on your API key. See Cost and Billing.
The CLI supports multiple output formats to fit different workflows.
The default output is formatted for easy reading in your terminal. When connected to a terminal, you'll see:
- Colored output with status indicators (green for completed, yellow for processing, red for failed)
- Styled labels for better visual hierarchy
- Progress indicators during batch operations and watch mode
For scripting and programmatic use, get raw JSON with the --json flag:
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC" --jsonThis returns the complete API response, perfect for piping to jq or processing in scripts.
For AI assistants and LLMs, use the --agent flag to get clean markdown tables:
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC" --agentThis outputs structured markdown that's easy for language models to parse:
## Geocode Result
| Field | Value |
|-------|-------|
| Matched Address | 1600 Pennsylvania Ave NW, Washington, DC 20500 |
| Coordinates | 38.8976763, -77.0365298 |
| Accuracy | rooftop (1.00) |Colors are automatically disabled when output is piped or redirected. To explicitly disable colors:
# Using the flag
geocodio geocode "1600 Pennsylvania Ave NW, Washington DC" --no-color
# Using the environment variable
NO_COLOR=1 geocodio geocode "1600 Pennsylvania Ave NW, Washington DC"Tip
The NO_COLOR environment variable follows the no-color.org standard and works across many CLI tools.
These flags work with all commands:
| Flag | Description |
|---|---|
--api-key |
Geocodio API key (or use GEOCODIO_API_KEY env var) |
--json |
Output results as JSON |
--agent |
Output results as markdown (for LLM consumption) |
--no-color |
Disable colored output (also respects NO_COLOR env var) |
--base-url |
Override API base URL (useful for testing or enterprise endpoints) |
--debug |
Show HTTP request/response details |
--version |
Show version information |
--help |
Show help for any command |
The Geocodio CLI includes a skill that teaches AI coding assistants how to use it. Once installed, your assistant can geocode addresses, reverse geocode coordinates, calculate distances, and process spreadsheets on your behalf.
Works with any AI coding assistant that supports skills, including Claude Code, Cursor, Amp, and Codex.
npx skills add geocodio/geocodio-cliThe skill teaches your assistant:
- All CLI commands (geocode, reverse, distance, distance-matrix, distance-jobs, lists)
- Output format flags (
--json,--agent) and when to use each - Batch processing workflows and file size limits
- Data append fields (timezone, congressional district, census, etc.)
- Common multi-step workflows like geocoding a CSV and downloading results
Once installed, the skill activates automatically when you ask your assistant to geocode, look up an address, calculate distances, or process a spreadsheet. No special syntax needed.
Example prompts:
- "Geocode this list of addresses and save the results as JSON"
- "What congressional district is 1600 Pennsylvania Ave in?"
- "Calculate driving distances from our warehouse to these 50 customers"
- "Upload this CSV and geocode the addresses in columns B and C"
Before you let an assistant run large jobs on your account, point it at Cost and Billing. It covers how lookups are counted, why appends multiply a run, and when lists upload beats --batch, which is the context an agent needs to avoid an expensive surprise.
The skill definition is in skills/geocodio/SKILL.md.
# Build binary to ./bin/geocodio
make build
# Install to your $GOPATH/bin
make installTests use go-vcr to record and replay HTTP interactions. This lets tests run without hitting the live API.
Run tests:
make testRun tests with coverage:
make coverThis generates a coverage report at coverage.html.
Tests replay recorded API responses from "cassette" files stored in internal/api/testdata/. This approach:
- Makes tests fast and deterministic
- Avoids API rate limits and costs during development
- Allows tests to run without an API key
Recording new cassettes:
When adding new tests or updating existing ones, you'll need to record fresh API interactions:
GEOCODIO_API_KEY=your-real-key make record-cassettesImportant
API keys are automatically redacted from recorded cassettes, so they're safe to commit.
How VCR works in this project:
- When
VCR_MODE=recordis set, tests make real API calls and save responses to YAML cassette files - During normal test runs, requests are matched against recorded cassettes and replayed
- The matcher ignores API keys, so cassettes work regardless of which key was used during recording
- If a cassette doesn't exist and
VCR_MODEisn't set torecord, the test is skipped
Adding a new test with VCR:
func TestNewEndpoint(t *testing.T) {
client := newTestClient(t, "new_endpoint")
// Make your API call
resp, err := client.SomeMethod(ctx, req)
// Assert results
require.NoError(t, err)
assert.Equal(t, expected, resp)
}Then record the cassette:
GEOCODIO_API_KEY=your-key VCR_MODE=record go test -v -run TestNewEndpoint ./internal/api/...The unit tests use recorded VCR cassettes and don't hit the live API. To verify that the CLI works end-to-end against the real Geocodio API, run the smoke test:
GEOCODIO_API_KEY=your-real-key ./scripts/smoke-test.shThis exercises every command (geocode, reverse, distance, distance-matrix, distance-jobs, lists) with various flag combinations, output formats, and error cases. It also runs lifecycle tests that create and delete distance jobs and spreadsheet uploads.
Note
The smoke test makes real API calls, which may count against your usage. It creates temporary resources (distance jobs, spreadsheet uploads) that are automatically deleted during the test run.
make lintRequires golangci-lint.
make cleanYou haven't set your API key. Either:
export GEOCODIO_API_KEY=your-api-keyOr pass it directly:
geocodio geocode "address" --api-key your-api-keyGeocodio's batch endpoints accept a maximum of 10,000 lookups per request, and appends count toward that cap: 5,000 addresses with one --fields category reaches it.
Above that limit, upload the file as a list instead of splitting it. A list runs asynchronously, takes up to 10 million lookups, and reports progress:
geocodio lists upload large_file.csv --direction forward --format "{{A}}" --watch
geocodio lists download 12345 --output geocoded.csvSplitting the file still works if you need results in a single stream, but it costs the same lookups and takes longer end to end:
split -l 10000 large_file.txt chunk_
for f in chunk_*; do geocodio geocode --batch "$f"; doneA 403 from these commands usually means the API key is fine but the permission is not enabled. Spreadsheet and distance access are per-key settings at dash.geocod.io/apikey. If geocodio geocode "1600 Pennsylvania Ave NW, Washington DC" succeeds with the same key, the key itself is valid.
Reverse geocoding expects coordinates in lat,lng format:
# Correct
geocodio reverse "38.8976,-77.0365"
# Incorrect
geocodio reverse "38.8976 -77.0365" # Missing comma
geocodio reverse "-77.0365,38.8976" # Longitude first (should be latitude)Use the --debug flag to see the full HTTP request and response:
geocodio geocode "1600 Pennsylvania Ave" --debugIf you're not seeing colored output:
- Make sure you're running in a terminal (not piping output)
- Check that
NO_COLORisn't set in your environment - Try using
FORCE_COLOR=1to force color output
Behavior changes that affect existing scripts:
| Change | Before | After | What to do |
|---|---|---|---|
--mode default on distance, distance-matrix, and distance-jobs create |
driving — 2 credits per calculation |
straightline — 1 credit per calculation, matching the HTTP API's own default |
Pass --mode driving explicitly wherever you rely on road distance or travel time. --max-duration and --min-duration need --mode driving alongside them. |
If you're upgrading from the previous Geocodio CLI (v1.x), here are the breaking changes:
| v1.x | v2.x | Notes |
|---|---|---|
geocodio create file.csv "{{A}}" |
geocodio lists upload file.csv --direction forward --format "{{A}}" |
--direction is now required (forward or reverse) |
geocodio status 123 |
geocodio lists status 123 |
Commands are grouped under lists |
geocodio download 123 > out.csv |
geocodio lists download 123 --output out.csv |
Use --output flag instead of shell redirect (stdout still works too) |
geocodio remove 123 |
geocodio lists delete 123 |
Renamed for consistency |
geocodio list |
geocodio lists list |
Grouped under lists |
--follow |
--watch |
Flag renamed |
--apikey / -k |
--api-key |
Flag renamed (env var GEOCODIO_API_KEY unchanged) |
--hostname / -n |
--base-url |
Flag renamed |
MIT