Add distance and ETA functions with Maps
Fill drive times and distances between two cells inline using the Maps service.
Publicado em 9 de jul. de 2025
Northwind delivers studio kits to clients across the country, and the logistics sheet needs a drive time and distance for every job. Looking each one up in a maps app and typing the answer back in is tedious, and the numbers go stale the moment a route plan changes.
These two custom functions put the lookup in the cell. =DRIVE_TIME(A2, B2)
returns the driving ETA between two addresses, and =DRIVE_DISTANCE_KM(A2, B2)
returns the distance in kilometres. Both share a cached route lookup, so a sheet
full of formulas does not hammer the Maps service.
What you’ll need
- A Google Sheet with an origin and a destination in their own columns. Each can be a postcode, a full address or a place name.
- Nothing else — the Maps service and
CacheServiceare built into Apps Script, no API key required.
The functions
// How long a route lookup stays cached, in seconds (6 hours).
const ROUTE_CACHE_TTL = 6 * 60 * 60;
/**
* Custom function: driving ETA between two locations.
* Use it in a cell, e.g. =DRIVE_TIME("London", "Manchester")
*
* @param {string} from Origin address, postcode or place name.
* @param {string} to Destination address, postcode or place name.
* @return {string} A human-readable duration, or '' if not found.
* @customfunction
*/
function DRIVE_TIME(from, to) {
// Bail out on empty inputs so the Maps service is never called for nothing.
if (!from || !to) return '';
const route = lookupRoute(from, to);
return route ? route.duration.text : '';
}
/**
* Custom function: driving distance between two locations, in kilometres.
* Use it in a cell, e.g. =DRIVE_DISTANCE_KM("London", "Manchester")
*
* @param {string} from Origin address, postcode or place name.
* @param {string} to Destination address, postcode or place name.
* @return {number|string} Distance in km, or '' if not found.
* @customfunction
*/
function DRIVE_DISTANCE_KM(from, to) {
if (!from || !to) return '';
const route = lookupRoute(from, to);
// Maps returns distance in metres — convert to km.
return route ? route.distance.value / 1000 : '';
}
/**
* Looks up the first driving route between two points and returns its
* leg. Results are cached so repeated formulas reuse one Maps call.
*
* @param {string} from Origin.
* @param {string} to Destination.
* @return {Object|null} The route leg, or null if no route exists.
*/
function lookupRoute(from, to) {
// 1. Check the cache first — a hit means no Maps call at all.
const cache = CacheService.getScriptCache();
const key = `route:${from}->${to}`;
const hit = cache.get(key);
if (hit) return JSON.parse(hit);
// 2. Cache miss — ask the Maps service for driving directions.
const directions = Maps.newDirectionFinder()
.setOrigin(from)
.setDestination(to)
.setMode(Maps.DirectionFinder.Mode.DRIVING)
.getDirections();
// 3. No route found (bad address, no road link) — give up cleanly.
if (!directions.routes.length) return null;
// 4. Cache the first leg for later formulas, then return it.
const leg = directions.routes[0].legs[0];
cache.put(key, JSON.stringify(leg), ROUTE_CACHE_TTL);
return leg;
}
How it works
DRIVE_TIMEandDRIVE_DISTANCE_KMare custom functions — the@customfunctiontag makes each callable straight from a cell.- Both check their two arguments are present first. An empty origin or destination returns a blank cell instead of a wasted lookup.
- Both delegate to
lookupRoute, which is where the real work — and the caching — happens. lookupRoutebuilds a cache key from the origin and destination and checksCacheServicefirst. On a hit it returns the stored route leg without touching the Maps service at all.- On a miss it calls
Maps.newDirectionFinderfor a driving route. If no route comes back it returnsnull, and the caller shows an empty cell. - A successful lookup is cached for six hours (
ROUTE_CACHE_TTL), so a column of formulas — or a recalculation — reuses one Maps call per unique pair. DRIVE_TIMEreturns the human-readableduration.text;DRIVE_DISTANCE_KMtakesdistance.valuein metres and divides by 1000.
Example run
With origins and destinations in columns A and B and the formulas in C and D:
| From | To | =DRIVE_TIME(A,B) | =DRIVE_DISTANCE_KM(A,B) |
|---|---|---|---|
| Northwind HQ, London | Manchester | 4 hours 12 mins | 335.6 |
| Northwind HQ, London | Brighton | 1 hour 38 mins | 86.4 |
| Northwind HQ, London | (blank) |
The third row is blank because the destination cell is empty — the guard skips the lookup.
Use them
There is nothing to schedule — these are custom functions:
- Paste the script into the spreadsheet’s bound Apps Script project and save.
- Back in the sheet, reference your origin and destination cells:
=DRIVE_TIME("Northwind HQ, London", B2)
=DRIVE_DISTANCE_KM("Northwind HQ, London", B2)
- Approve the authorisation prompt the first time a function runs.
Watch out for
- The Maps service has a daily directions quota. A cache miss costs one lookup; the six-hour cache absorbs repeats, but a sheet full of unique routes recalculated often can still hit the limit.
- Custom functions run with a 30-second limit. A slow cluster of fresh lookups in one recalculation can time cells out — let the cache warm up, or paste results as static values once correct.
CacheServiceentries are capped at 100 KB each and can be evicted under pressure. A route leg is small, so this is rarely an issue, but do not treat the cache as permanent storage.- A cached route does not update for live traffic or roadworks. The six-hour
TTL keeps numbers reasonably fresh; shorten
ROUTE_CACHE_TTLif you need tighter accuracy. - Vague inputs give vague routes. “Manchester” picks a city centre point — use full addresses or postcodes when the exact start and end matter.
Relacionados
Parse messy mixed-format dates
Normalise inconsistently formatted strings into real date values with a single formula.
Atualizado em 2 de ago. de 2025
Scrape a web table into cells with one formula
Pull HTML tables into Sheets as a custom function — no IMPORTHTML quirks.
Atualizado em 30 de jul. de 2025
Mask sensitive columns for shareable copies
Redact PII with a custom function so you can share a copy of the sheet without exposing names, emails, or numbers.
Atualizado em 26 de jul. de 2025
Build a sentiment-scoring function without AI
Rate text positive or negative with a tiny built-in lexicon — no API key, no quota.
Atualizado em 23 de jul. de 2025
Build a unit-conversion function library
Convert between any units with one custom formula — kg/lb, km/mi, °C/°F, and the rest.
Atualizado em 19 de jul. de 2025