Add travel-time buffers before offsite events
Insert commute events before any Northwind meeting outside the studio.
Published Aug 1, 2025
Northwind’s calendar shows a client meeting starting at 10:00 across town, and the half-hour it takes to get there is invisible. So the 09:30 slot looks free, someone books it, and now there is no way to make the offsite on time. The commute is real time that nothing on the calendar reflects.
This script blocks that time out. It scans the next week of events, finds the ones with a location outside the studio, asks the Maps service how long the journey takes, and drops a “Travel to…” event in front of each one. The commute becomes a visible, bookable-against block instead of an assumption.
What you’ll need
- A Google Calendar — the script uses your default calendar.
- Events with a real address in the location field. Events with no location are treated as in-studio and skipped.
- Nothing else — the Maps service is built into Apps Script, no API key needed.
The script
// Where journeys are measured from — the studio.
const HOME_LOCATION = 'Northwind Studios, Hoxton Square, London';
// How far ahead to scan, in days.
const SCAN_DAYS = 7;
// Tag used to mark events we've already added a buffer for.
const BUFFER_TAG = 'travel-buffered';
/**
* Scans the next week of calendar events and inserts a travel-time
* event before each one that has an external location.
*/
function addTravelBuffers() {
const now = new Date();
const until = new Date(now.getTime() + SCAN_DAYS * 86400000);
const calendar = CalendarApp.getDefaultCalendar();
const events = calendar.getEvents(now, until);
if (!events.length) {
Logger.log('No upcoming events to check.');
return;
}
let added = 0;
for (const event of events) {
// 1. Skip events with no location, or ones already buffered.
const location = event.getLocation();
if (!location) continue;
if (event.getTag(BUFFER_TAG) === 'yes') continue;
// 2. Ask Maps how long it takes to get there by public transport.
const directions = Maps.newDirectionFinder()
.setOrigin(HOME_LOCATION)
.setDestination(location)
.setMode(Maps.DirectionFinder.Mode.TRANSIT)
.getDirections();
// 3. No route found — skip rather than guess.
if (!directions.routes.length) {
Logger.log('No route to: ' + location);
continue;
}
// 4. Convert the journey duration (seconds) to milliseconds.
const travelMs = directions.routes[0].legs[0].duration.value * 1000;
// 5. Create a travel event ending exactly when the meeting starts.
const meetingStart = event.getStartTime();
calendar.createEvent(
'Travel to ' + location,
new Date(meetingStart.getTime() - travelMs),
meetingStart
);
// 6. Tag the meeting so a future run never double-buffers it.
event.setTag(BUFFER_TAG, 'yes');
added++;
}
Logger.log('Added ' + added + ' travel buffer(s).');
}
How it works
addTravelBuffersworks out a window from now to seven days ahead (SCAN_DAYS) and reads every event in it from the default calendar.- If there are no events it logs a message and stops.
- For each event it reads the location field. Events with no location are
treated as in-studio and skipped, as are events already carrying the
travel-bufferedtag. - It asks the Maps service for a transit route from the studio
(
HOME_LOCATION) to the event’s location. - If Maps returns no route it logs the location and moves on — better a missing buffer than a made-up one.
- It reads the journey duration, which Maps gives in seconds, and converts it to milliseconds.
- It creates a “Travel to…” event that ends exactly when the meeting starts and begins one journey-length earlier.
- Finally it tags the meeting with
travel-buffered, so the next run sees the tag and skips it — no duplicate buffers.
Example run
A meeting on the calendar:
| Event | Location | Start |
|---|---|---|
| Client review — Acme | Acme HQ, Canary Wharf | Tue 10:00 |
After a run, a new event sits in front of it:
| Event | Start | End |
|---|---|---|
| Travel to Acme HQ, Canary Wharf | Tue 09:25 | Tue 10:00 |
| Client review — Acme | Tue 10:00 | Tue 11:00 |
The 35-minute transit journey is now a visible block. The 09:25–10:00 slot shows as busy, so nobody books over the commute.
Trigger it
Run this on a schedule so new offsite meetings get buffered automatically:
- In the Apps Script editor, open Triggers (the clock icon).
- Click Add trigger.
- Choose the
addTravelBuffersfunction, a Time-driven source, and a Day timer running early each morning. - Save and approve the authorisation prompt.
A daily run catches anything booked the day before, well ahead of time.
Watch out for
- The script only measures the trip to the meeting. A return-journey buffer would need a second event created after the meeting ends.
- It assumes you always start from the studio. Back-to-back offsites mean the
real origin is the previous location, not
HOME_LOCATION— this script does not chain journeys. - Transit times shift with timetables and disruption. The buffer reflects the estimate at the moment of the run, not live conditions on the day.
- Deleting a meeting does not delete its travel event. The buffer is a separate event and will linger on the calendar.
- The Maps service has a daily directions quota. A week of offsite-heavy days uses one lookup per event — fine normally, but worth knowing on a busy calendar.
getTagandsetTagstore data on the event itself. If an event is recreated or copied, it loses thetravel-bufferedtag and may be buffered again.
Related
Schedule personal habits and routines
Block recurring habits on Awadesh's calendar — gym, walks, deep-work mornings.
Updated Nov 5, 2025
Sync birthdays and anniversaries to Calendar
Populate recurring personal dates from a Sheet — the Northwind team rituals calendar.
Updated Nov 1, 2025
Generate recurring events with custom exceptions
Handle complex recurrence rules in code — every Tuesday except UK bank holidays.
Updated Oct 28, 2025
Auto-reschedule low-priority conflicts
Move flexible Northwind events around fixed ones — focus blocks bend, client calls don't.
Updated Oct 16, 2025
Build a contract-renewal calendar
Track Northwind's recurring-revenue renewal dates as calendar events for proactive sales.
Updated Oct 8, 2025