← Back to list

From ride to row — Automating bike commute registration with n8n, Strava and Google sheets

I use n8n to automatically turn Strava ride events into spreadsheet entries that HR will accept with no manual typing required. The…

Yoeri op't Roodt · 2025-08-20 10:51 · 0 claps · 5.7 min read
#n8n-workflow-automation #bike-commuting #strava-app #google-sheets #software-development
Open on Medium ↗
Wiki topics: 🏃 · Running & Endurance

From ride to row — Automating bike commute registration with n8n, Strava and Google sheets

I use n8n to automatically turn Strava ride events into spreadsheet entries that HR will accept with no manual typing required. The workflow listens for Strava activity events, checks whether the start and end are near known locations (home/office), prepares the fields to match my company’s Excel template, ensures the right Google Sheet exists for that day, and writes the commute data into the correct cells.

What you’ll need

Before diving in, here’s the setup I used:

  • A Strava account.
  • An n8n instance (I self-host this with a Cloudflare tunnel to make it publicly accessible).
  • A Google account with access to Sheets and Drive.
  • A copy of my company’s Excel template for bike commute registration.

Introduction

What this workflow does

This workflow listens for Strava activities, validates whether they are commutes, and writes them into the correct HR Excel template stored in Google Sheets.

  1. Listen for Strava activities.
  2. Run a geofence check via a custom script.
  3. Prepare data in the format HR expects.
  4. Ensure the target Google Sheet exists.
  5. Fill in the year/month metadata.
  6. Write commute data into the right row.

Why n8n

I chose n8n because it’s self-hostable and flexible. It comes with native nodes for Strava and Google, so I only had to add minimal glue code. Error handling and retries are built in, which makes it reliable for something I want to “set and forget.”

Architecture at a glance

  • Strava notifies n8n via the activity.created event.
  • n8n fetches the activity and runs a geofence check to validate if it’s a commute.
  • The workflow finds or creates the correct Google Sheet for that month.
  • Data is written into the proper row and columns.

How the workflow runs

The n8n workflow

The n8n workflow

1. Strava activity trigger

The workflow begins with the Strava node in n8n. I configured it to connect to my Strava account, listen for new activities, and trigger whenever a ride is created. This way, as soon as a ride syncs from my bike computer to Strava, the workflow kicks off automatically.

2. Custom script: geofence validation

Once the activity data arrives, a Code node checks if the ride qualifies as a commute. The script compares the start and end points with predefined coordinates for “home” and “office.” If the ride starts near one and ends near the other, it’s marked as a commute.

I implemented the script in JavaScript (though Python would also work). The main logic uses the Haversine formula to calculate distances and determine whether the points are within range. If both points are near different reference locations, the ride passes the commute check.

If the check fails, the workflow stops here.

const referenceLocations = {
  home: [xx.xxx, xx.xxx], // I'm not sharing my home coordinates
  office: [xx.xxx, xx.xxx], // And this one will be a secret as well
};

// Convert degrees to radians
function toRad(value) {
  return value * Math.PI / 180;
}

// Haversine formula to calculate distance between two points on a sphere.
function calculateDistance(lat1, lon1, lat2, lon2) {
  const R = 6371;
  const dLat = toRad(lat2 - lat1);
  const dLon = toRad(lon2 - lon1);

  const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

  return R * c;
}

// Find which reference locations a point is within tolerance.
function findNearbyLocations(lat, lon, tolerance = 0.5) {
  const nearby = [];
  for (const [locationName, [refLat, refLon]] of Object.entries(referenceLocations)) {
    const distance = calculateDistance(lat, lon, refLat, refLon);
    if (distance <= tolerance) {
      nearby.push(locationName);
    }
  }

  return nearby;
}

// Main logic
const startpoint = $input.first().json.object_data.start_latlng;
const endpoint = $input.first().json.object_data.end_latlng;

let result = false;

if (startpoint && endpoint) {
  let [startLat, startLon] = startpoint;
  let [endLat, endLon] = endpoint;
  if (startLat !== undefined && startLon !== undefined && endLat !== undefined && endLon !== undefined) {
    const startNearby = findNearbyLocations(startLat, startLon);
    const endNearby = findNearbyLocations(endLat, endLon);

    // Check if both points are near different predefined reference locations.
    if (startNearby.length > 0 && endNearby.length > 0) {
      const startLocations = new Set(startNearby);
      const endLocations = new Set(endNearby);

      const differentLocations = [ ... endLocations].some(loc => !startLocations.has(loc)) || [ ... startLocations].some(loc => !endLocations.has(loc));

      result = differentLocations;
    }
  }
}

return [{
  json: {
    isConsideredCommuting: result,
    startpointNearby: startpoint ? findNearbyLocations( ... startpoint) : [],
    endpointNearby: endpoint ? findNearbyLocations( ... endpoint) : [],
  }
}];

3. Preparing the data

Strava’s raw output doesn’t look anything like what HR wants. Using a Set node, I reshaped the data into the exact format of the company’s Excel template. That meant converting meters to kilometers, formatting the date, and hardcoding the start and end addresses so the spreadsheet matched HR’s expectations.

[
  {
    "distance": 15,
    "location_1": "home address",
    "location_2": "office address",
    "date": "07/08/2025",
    "month": "August",
    "year": "2025",
    "day_of_month": "7"
  }
]

4. Ensuring the Google Sheet exists

Because this should run without manual setup, the workflow checks whether the Google Sheet for the current month already exists. If not, it automatically copies a blank template file and renames it with the correct month and year. This ensures every commute gets logged in the right place, even at the start of a new month.

5. Set the year and month

The workflow then updates the sheet with the correct year and month values. In my company’s template, these are stored in merged cells at the top, so this step has to run before writing the commute data.

[
  {
    "row_number": 6,
    "Year": "2025",
    "Month": "August"
  }
]

6. Write the commute data

Finally, the workflow writes the actual commute details into the row corresponding to the day of the month. This includes the distance, start and end addresses, and any other required fields. At this point, the ride is fully registered in the HR-approved format.

[
  {
    "Day of month in #": "7",
    "#Km's to workplace": 15,
    "Address A": "home address",
    "Address B": "work address"
  }
]

The result

The first time the workflow ran was on 7 August 2025. Strava detected a ride from home to office and back. n8n validated the start and end points against my geofence, confirmed it as a commute, created the August 2025 sheet automatically, and filled in the metadata and commute row.

Before automation (empty sheet)

Before automation (empty sheet)

After automation

After automation

Lessons learned along the way

  • The commute property in Strava is unreliable. It’s always set to false by default and updating it doesn’t trigger a webhook. The geofence script turned out to be more reliable and works even if I forget to flag the ride.
  • Because n8n’s Strava node requires a public endpoint, I configured a Cloudflare tunnel to one of my domains.
  • My company’s Excel template forces the workflow to update the file twice: once for the year/month metadata, and once for the commute row. Not elegant, but effective.

Future improvements

For now, I’m validating the workflow by biking to work more often and manually spot-checking the results. Once it runs flawlessly, I plan to:

  • Add notifications: Send myself an email or WhatsApp message whenever a commute is logged, including the date, distance, and whether the sheet was newly created or just updated. This gives me immediate confirmation that the ride was tracked correctly.
  • Automate submission: Add an automatic upload to Microsoft Forms so HR receives the data without me lifting a finger.

Closing thoughts

What started as a small annoyance, manually filling out Excel sheets for every bike commute, turned into a fun automation project. By combining Strava, n8n, and Google Sheets, I now have a workflow that reliably tracks my commutes, fills in HR’s template, and saves me from repetitive data entry.

The best part is that the setup is flexible. I can extend it with notifications, more validation rules, or even direct submission to HR systems. It’s a good reminder that automation doesn’t always have to be big and complex. Even small improvements can remove friction and make daily routines smoother.

In short, every time I bike to work, I’m not just exercising. I’m also letting my automation quietly take care of the paperwork in the background.


메타데이터
post_id
ff092cf05409
slug
from-ride-to-row-automating-bike-commute-registration-with-n8n-strava-and-google-sheets-ff092cf05409
url
https://medium.com/@yoerioptr/from-ride-to-row-automating-bike-commute-registration-with-n8n-strava-and-google-sheets-ff092cf05409
canonical_url
https://medium.com/@yoerioptr/from-ride-to-row-automating-bike-commute-registration-with-n8n-strava-and-google-sheets-ff092cf05409
author_url
https://medium.com/@yoerioptr
status
ok
fetched_at
2026-08-10 12:46:46