Tracks the real drive time between two places by polling the Google Routes API over a week, then tells you the best time to leave — with far tighter resolution than the wide ranges Google Maps shows.
No dependencies beyond Python 3.9+.
pip install commute-optimizer
That gives you the commute command used below. Running from a source
checkout works too — substitute python -m commute for commute.
All data files (config.json, .env, commute.db, the reports, logs) live
in the directory you run commute from, so each tracking project can have its
own folder.
commute report writes a self-contained report.html: one section
per direction, a chart of median commute vs. departure time (one line per
weekday), and tables ranking the best departure slot inside each rush window —
including how many minutes it saves over the worst slot.
(Generated from synthetic demo data — regenerate with
python docs/_gen_example.py.)
Preflight check before a long run:
> commute check
[ok] config: '1600 Amphitheatre Parkway, Mountain View, CA' -> '1 Market St, San Francisco, CA'
[ok] API key found (AIzaSy...XXXX)
[ok] database writable at C:\...\commute-optimizer\commute.db (0 existing samples)
[ok] live route -> 43.6 min now (free-flow 46.3 min, 58.5 km)
[ok] live route <- 43.1 min now (free-flow 46.5 min, 58.9 km)
[ok] estimated API usage: ~938/day, ~6566/week (free tier ~10,000/month)
All checks passed - ready for a long run.
Polling with the auto-stop timer:
> commute poll -d 7d
Polling '1600 Amphitheatre Parkway, Mountain View, CA' <-> '1 Market St, San Francisco, CA'
Rush interval 1 min, off-peak 10 min. Ctrl+C to stop.
Will stop automatically at 2026-07-12 22:59 and generate the report.
[Sun 22:59:28] -> 43.6 min (free-flow 46.3 min)
[Sun 22:59:28] <- 43.1 min (free-flow 46.5 min)
...
And when the report runs, it also prints the summary:
1600 Amphitheatre Parkway, Mountain View, CA -> 1 Market St, San Francisco, CA
window 07:00-10:00:
Monday leave 09:45-10:00 (~28.7 min; worst 51.3 min, saves 22.6)
Tuesday leave 09:45-10:00 (~29.4 min; worst 51.5 min, saves 22.1)
...
-
Get a Google Maps Platform API key with the Routes API enabled (Google Cloud console → APIs & Services → enable "Routes API" → create an API key).
-
In the folder where you want the data to live, write the example config and edit your addresses:
commute init -
Put your API key in a
.envfile in the same folder:GOOGLE_MAPS_API_KEY=your-key-here
Before a long run, verify everything works (config, API key, database, one live API call per direction, and a quota estimate for your poll schedule):
commute checkStart polling. With -d it stops automatically after the given duration and
generates the report; without it, it runs until Ctrl+C:
commute poll -d 7d # a full week, then auto-report
commute poll # open-endedDurations accept d/h/m and combinations: 7d, 24h, 90m, 1d12h.
Add --no-report to skip the automatic report at the end.
Generate the report any time mid-run (opens report.html in your browser;
--no-open to skip that):
commute reportOr watch the run continuously: this regenerates report.html and a
day-by-day report (report-daily.html — one curve per calendar date plus a
coverage table, so you can see the data filling in before the week is done).
Run it in a second terminal alongside poll; refresh the browser to see
updates:
commute watch # updates every 15 minutes
commute watch -i 5m # or your own intervalTo preview the report without waiting a week, seed a synthetic week of two-direction data (refuses to run if the DB already has samples). In an empty folder:
commute init
commute demo
commute reportInstead of running poll in a terminal, register it with the OS so it stays
alive for the whole run (run this from your data folder — that's where the
scheduled poller will work):
commute schedule install -d 7d # poll for a week, survive anything
commute schedule status # is the task/poller alive?
commute schedule remove # stop and unregisterThis relaunches the poller every 5 minutes (a lock file makes that a no-op while one is already running) and resumes after a reboot once you log in. The stop time is stored as an absolute timestamp, so it survives reboots too; when it's reached, the report is generated as usual.
Per platform:
- Windows — a Task Scheduler task; it can also wake the machine from
sleep to poll. Output goes to
poll.log(no console window). - Linux — a systemd user service + timer (
commute-poll). Logs go tojournalctl --user -u commute-poll. Runs from login onward; for before-login polling runloginctl enable-linger $USER. Linux can't wake itself from sleep for this; a missed tick fires right after wake. - macOS — a launchd LaunchAgent (
com.commute-optimizer.poll) logging topoll.log. macOS won't wake for it either — to poll with the lid closed, plug in and runcaffeinate -s.
Don't run schedule install while a manually-started poll from an older
version is still running — stop that one first, or you'll get duplicate
samples.
If you skip all this and the machine sleeps mid-run, collected data is still
safe in commute.db — the report's Coverage section will show exactly which
stretches were missed.
{
"origin": "home address",
"destination": "work address",
"travel_mode": "DRIVE",
"track_both_directions": true,
"poll": {
"active_window": ["00:00", "23:59"],
"rush_windows": [["07:00", "10:00"], ["16:00", "19:00"]],
"rush_interval_min": 1,
"offpeak_interval_min": 10
}
}track_both_directions— when true (the default), every tick samples both origin→destination and the reverse, so one run covers your morning and evening commutes.active_window— only poll inside this local-time range (set e.g.["06:00", "20:00"]to skip the night entirely).rush_windows— during these windows the poller samples everyrush_interval_minminutes; otherwise everyoffpeak_interval_minminutes. The report ranks departure times within these windows (otherwise 3 a.m. always wins).
The Routes API (traffic-aware) has ~10,000 free calls/month. The default
adaptive schedule makes roughly 470 calls/day per direction — ~6,600/week with
both directions on, still inside the free tier but without room for a second
full week in the same month. Set track_both_directions to false or trim
active_window to halve it. Run commute check to see the estimate
for your exact schedule.
Samples land in commute.db (SQLite). Transient API failures (network blips,
rate limits, 5xx) are retried with backoff (5s/15s/45s) before being recorded
as an error row; permanent failures like a bad key fail fast without retries.
The report ends each direction with a Coverage section flagging any
stretch where sampling stopped (sleep, reboot, repeated errors) despite the
schedule expecting data — so you know which medians to trust.
- Multi-week data blends together. The report groups by weekday, so two
Mondays from different weeks merge into one median curve. Intended use is a
single week per
commute.db; delete or rename the DB between runs. - Wake-from-sleep is Windows-only. On Linux/macOS the scheduled poller resumes right after wake but can't wake the machine itself.
- No automated tests. The pieces are small and hand-verified, but there's no test suite yet.
