Google Sheets formulas for maps, addresses and routes

30 free Google Sheets formulas that geocode, clean, measure, route, publish and report β€” straight from your spreadsheet. They work like native formulas: type one, fill a whole column.

Cheat sheet

One line each. Ranges everywhere an address goes: =GEOCODE(A2:A50) fills fifty rows.

Geocode & clean

=GEOCODE(address)Latitude and longitude for an address, a range, or Plus Codes.
=CLEAN_ADDRESS(address)The standardised, geocoder-verified version of a messy address.
=REVERSE_GEOCODE(lat, lng)The nearest street address for coordinates.
=COORD_CONVERT(coords, to?)Convert coordinates between decimal and degrees/minutes/seconds.
=GEOCODE_IP(ip)City, country and coordinates for an IP address (or range of them).

Fill address columns

=POSTCODE(address)The postcode / ZIP. Aliases: =ZIP, =ZIPCODE.
=CITY(address)The city or town. Alias: =TOWN.
=COUNTY(address)The county / district.
=STATE(address)The state / region. Alias: =REGION.
=COUNTRY(address)The country.

Distances & questions

=DISTANCE(from, to, unit?)Straight-line distance between two places.
=TRAVEL_TIME(from, to, mode?)Real road travel time between two places, in minutes.
=DISTANCE_MATRIX(origins, destinations, mode?, unit?)Every-to-every road distances (or times): origins down, destinations across.
=CLOSEST_TO(anchor, candidates, n?)The nearest location(s) to an anchor, from a list.
=WITHIN_RADIUS(anchor, candidates, radius, unit?)Everything from a list inside a radius, sorted nearest-first.
=SORT_BY_DISTANCE(range, anchor, unit?)Your rows re-sorted nearest-first, with a distance column added.

Run the day

=GEOCODE_WORKFLOW(stops, start?, end?)The whole route day in one formula: coordinates, best visiting order, and one Google Maps route link.
=VISIT_ORDER(stops, start?, end?)The best visiting order (1, 2, 3…) aligned to your rows β€” on real routes this cuts 20–50% of the miles.
=ROUTE_LINK(stops, mode?)One Google Maps link for the whole run β€” up to 100 stops (10x Google's usual 10).
=WAZE_LINK(address)A tap-to-navigate Waze link per row.
=TERRITORY(addresses, reps, balanceBy?)Splits a list into balanced geographic territories, one per rep.
=LOGBOOK(mapLink, limit?, refresh?, override?)The full visit journal, newest first: every check-off ever, like a bank statement. Answers "what happened, in order?"
=VISIT_STATUS(range, mapLink, refresh?, override?)One row per customer, aligned with YOUR list: their current status only, like an account balance. Answers "where does each customer stand?"

Publish & share

=INSTAMAP(range, title?)A hosted, live, shareable map from your rows β€” the URL lands in the cell.
=EMBED_MAP(range, siteName)A white-label embed link for your website: no branding, light theme, your name on the loading screen.
=STREETVIEW_LINK(address)A Google Street View link per row β€” tap to look at the building.

Full reference

Geocode & clean

=GEOCODE(address)

The workhorse: coordinates for anything address-shaped. Handles street addresses, postcodes, landmarks, and Plus Codes β€” both full (772CH947+CV) and short with a locality (H963+HV Maracaibo).

ArgumentWhat it takes
addressAn address, or a range of addresses (=GEOCODE(A2:A50) fills every row).
=GEOCODE(A2)
=GEOCODE(A2:A50)

Ranges above 400 rows: use Extensions β†’ InstaMaps β†’ Add coordinates to this sheet (no formula time limits).

=CLEAN_ADDRESS(address)

The standardised, geocoder-verified version of a messy address.

ArgumentWhat it takes
addressAn address, or a range of addresses (=GEOCODE(A2:A50) fills every row).
=CLEAN_ADDRESS(A2:A50)
=REVERSE_GEOCODE(lat, lng)

The nearest street address for coordinates.

ArgumentWhat it takes
latLatitude β€” or a single "lat,lng" string as the only argument.
lngLongitude.
=REVERSE_GEOCODE(51.5007, -0.1246)
=REVERSE_GEOCODE(A2)
=COORD_CONVERT(coords, to?)

Convert coordinates between decimal and degrees/minutes/seconds.

ArgumentWhat it takes
coordsThe coordinates to convert (either format).
toOptional target: "dms" (default) or "decimal".
=COORD_CONVERT("51.5007, -0.1246")
=COORD_CONVERT(A2, "decimal")
=GEOCODE_IP(ip)

City, country and coordinates for an IP address (or range of them).

ArgumentWhat it takes
ipAn IP address, or a range of IPs.
=GEOCODE_IP(A2:A50)

Fill address columns

=POSTCODE(address)

The postcode / ZIP. Aliases: =ZIP, =ZIPCODE.

ArgumentWhat it takes
addressAn address, or a range of addresses (=GEOCODE(A2:A50) fills every row).
=POSTCODE(A2:A50)
=CITY(address)

The city or town. Alias: =TOWN.

ArgumentWhat it takes
addressAn address, or a range of addresses (=GEOCODE(A2:A50) fills every row).
=CITY(A2:A50)
=COUNTY(address)

The county / district.

ArgumentWhat it takes
addressAn address, or a range of addresses (=GEOCODE(A2:A50) fills every row).
=COUNTY(A2:A50)
=STATE(address)

The state / region. Alias: =REGION.

ArgumentWhat it takes
addressAn address, or a range of addresses (=GEOCODE(A2:A50) fills every row).
=STATE(A2:A50)
=COUNTRY(address)

The country.

ArgumentWhat it takes
addressAn address, or a range of addresses (=GEOCODE(A2:A50) fills every row).
=COUNTRY(A2:A50)

Distances & questions

=DISTANCE(from, to, unit?)

Straight-line distance between two places.

ArgumentWhat it takes
fromAn address or "lat,lng".
toAn address or "lat,lng".
unitOptional: "km" (default) or "mi".
=DISTANCE(A2, B2, "mi")
=TRAVEL_TIME(from, to, mode?)

Real road travel time between two places, in minutes.

ArgumentWhat it takes
fromAn address or "lat,lng".
toAn address or "lat,lng".
modeOptional: driving (default), walking, cycling.
=TRAVEL_TIME(A2, B2)
=TRAVEL_TIME(A2, B2, "walking")
=DISTANCE_MATRIX(origins, destinations, mode?, unit?)

Every-to-every road distances (or times): origins down, destinations across.

ArgumentWhat it takes
originsAddresses down the side (up to 25).
destinationsAddresses across the top (up to 25).
modeOptional: driving (default), walking, cycling.
unitOptional: "km" (default), "mi", or "min" for travel time.
=DISTANCE_MATRIX(A2:A10, C2:C6, "driving", "min")
=CLOSEST_TO(anchor, candidates, n?)

The nearest location(s) to an anchor, from a list.

ArgumentWhat it takes
anchorThe reference address (or "lat,lng").
candidatesThe list to search (e.g. A2:A200).
nOptional: how many nearest to return (default 1).
=CLOSEST_TO(B1, A2:A200)
=CLOSEST_TO(B1, A2:A200, 5)
=WITHIN_RADIUS(anchor, candidates, radius, unit?)

Everything from a list inside a radius, sorted nearest-first.

ArgumentWhat it takes
anchorThe centre address (or "lat,lng").
candidatesThe list to search.
radiusThe radius number.
unitOptional: "km" (default) or "mi".
=WITHIN_RADIUS(B1, A2:A200, 25, "mi")
=SORT_BY_DISTANCE(range, anchor, unit?)

Your rows re-sorted nearest-first, with a distance column added.

ArgumentWhat it takes
rangeThe rows to sort (address in any column).
anchorThe reference address (or "lat,lng").
unitOptional: "km" (default) or "mi".
=SORT_BY_DISTANCE(A2:C50, "Manchester")

Run the day

=GEOCODE_WORKFLOW(stops, start?, end?)

The three-formula chain as a single spill: per row you get Lat, Lng and Visit order; the first row also carries the Route link for the whole run in visiting order (up to 100 stops).

ArgumentWhat it takes
stopsYour stops (2–100), e.g. A2:A101. Plus Codes work.
startOptional starting address (default: the first row).
endOptional end point: the run finishes at the row nearest this address, or gets a final leg back to it (your depot). Same address for start and end = a round trip.
=GEOCODE_WORKFLOW(A2:A26)
=GEOCODE_WORKFLOW(A2:A26, "The depot, Salford")
=VISIT_ORDER(stops, start?, end?)

The best visiting order (1, 2, 3…) aligned to your rows β€” on real routes this cuts 20–50% of the miles.

ArgumentWhat it takes
stopsThe stops to order.
startOptional starting address (default: the first row).
endOptional end point: the run finishes at the row nearest this address, or gets a final leg back to it (your depot). Same address for start and end = a round trip.
=VISIT_ORDER(B2:B26)
=VISIT_ORDER(B2:B26, "The depot, Salford")
=TERRITORY(addresses, reps, balanceBy?)

Splits a list into balanced geographic territories, one per rep.

ArgumentWhat it takes
addressesThe addresses to split.
repsA number of territories, or a range of rep names.
balanceByOptional value column to balance by (e.g. revenue).
=TERRITORY(A2:A500, 4)
=TERRITORY(A2:A500, D2:D5, C2:C500)
=LOGBOOK(mapLink, limit?, refresh?, override?)

Pairs with the map's Logbook page: your crew checks off stops on their phones, this formula pulls the dated history back into the sheet β€” every event, repeat visits included, on its own tab. For "where does each customer stand right now?", use =VISIT_STATUS instead: same data, one current row per customer.

ArgumentWhat it takes
mapLinkYour map link from =INSTAMAP, or the map id.
limitOptional: number of entries (default 200, max 500).
refreshOptional: point at a refresh cell β€” any change to it refetches. "Set up visit tracking" wires this automatically (and bumps it as you work); ⚑ Live sync turns it into a count that changes on every check-off. NOW() is not allowed as a custom-function argument.
overrideOptional: point at a spare cell; change that cell to refetch instantly.
=LOGBOOK($M$3)
=LOGBOOK($M$3, 200, $D$1)
=VISIT_STATUS(range, mapLink, refresh?, override?)

The other projection of the same data as =LOGBOOK: where the journal is time-ordered history (many rows per stop), this is customer-ordered state (exactly one row each, beside your data). Put it next to your customer list and the latest check-off lands on the right row by itself.

ArgumentWhat it takes
rangeYour client rows (first cell = the name, same as =INSTAMAP).
mapLinkYour map link from =INSTAMAP, or the map id.
refreshOptional: point it at COUNTA over your =LOGBOOK journal β€” each new check-off changes the count, which refetches the statuses. Start the range at column B of the spill: Sheets blocks custom functions from touching the NOW() cell itself.
overrideOptional: a spare cell for instant manual refetch.
=VISIT_STATUS(A2:A50, $M$3, COUNTA(Logbook!$B$3:$F))

Publish & share

=INSTAMAP(range, title?)

The map updates itself when the sheet changes. Same title = same map, updated in place, so the link you share stays good forever.

ArgumentWhat it takes
rangeThe rows to map (first cell of each row becomes the pin name).
titleOptional map title β€” also its stable identity.
=INSTAMAP(A2:D50, "Client visits")
=EMBED_MAP(range, siteName)

A white-label embed link for your website: no branding, light theme, your name on the loading screen.

ArgumentWhat it takes
rangeRows to map (first cell = the pin name).
siteNameYour site's name β€” shows while the map loads, and pins the map's identity.
=EMBED_MAP(A2:C50, "Palouse Mindfulness")

Paste the returned link into an iframe: <iframe src="THE_LINK" width="100%" height="600" style="border:0"></iframe>

All of it, free, inside Google Sheetsβ„’

Install InstaMaps