Prerequisites
Node.js installed on your machine
A Strava Developer account
A Notion account
Step 1 - Get Your API Keys
Strava API Key
Log in to your Strava account.
Fill in the required details and click Create .
Copy the Client ID and Client Secret .
Notion API Key
Log in to your Notion account.
Click on New Integration .
Fill in the required details and click Submit .
Copy the generated Internal Integration Token .
Step 2 - Set Up Your Notion Database
Create a new database in Notion with the following properties:
Name (Title)
Distance (Number)
Pace (Text)
Duration (Text)
Elevation Gain (Number)
Type (Text)
Date (Date)
Calories (Number)
Share the database with your integration:
Click on the three dots in the top-right corner of the page.
Under Connections , click on Connect to and search for your integration and invite it.
Step 3 - Project Structure
This step is not necessary but we suggest projects to be structured like so:
project-root/
├── src/
│ ├── config/
│ │ └── spotify.js
│ │ └── notion.js
│ ├── integrations/
│ │ ├── spotifyIntegration.js
│ │ └── notionIntegration.js
│ ├── main.js
│ ├── server.js
Step 4 - Create .env file
Create a .env file in your project directory with the following with the following information:
NOTION_TOKEN='your_notion_integration_token'
NOTION_DATABASE_ID='your_notion_database_id'
STRAVA_CLIENT_ID='your_strava_client_id'
STRAVA_CLIENT_SECRET='your_strava_client_secret'
STRAVA_ACCESS_TOKEN='your_strava_access_token'
STRAVA_REFRESH_TOKEN='your_strava_refresh_token'
Please note that you will have to update your .env file with your STRAVA_ACCESS_TOKEN and STRAVA_REFRESH_TOKEN after completing Strava’s OAuth flow.
Step 5 - Packages
Install the required Node.js packages using the following command:
npm install @notionhq/client dotenv express https
Additionally, create a package.json file and add the following:
{
"name" : "strava_integration" ,
"version" : "1.0.0" ,
"main" : "src/main.js" ,
"scripts" : {
"start" : "node src/main.js"
},
"dependencies" : {
"@notionhq/client" : "^1.0.4" ,
"dotenv" : "^8.6.0" ,
"express" : "^4.19.2" ,
"https" : "^1.0.0"
}
}
Step 6 - OAuth Flow
Create server.js to handle the OAuth flow:
const express = require ( 'express' );
const https = require ( 'https' );
const querystring = require ( 'querystring' );
require ( './utils/dotenv' );
const app = express ();
const PORT = 3000 ;
app . get ( '/' , ( req , res ) => {
res . send ( '<h1>Strava OAuth Integration</h1><p><a href="/auth">Click here to authorize with Strava</a></p>' );
});
app . get ( '/auth' , ( req , res ) => {
const authUrl = `https://www.strava.com/oauth/authorize?client_id= ${ process . env . STRAVA_CLIENT_ID } &response_type=code&redirect_uri=http://localhost: ${ PORT } /exchange_token&approval_prompt=force&scope=activity:read_all` ;
res . redirect ( authUrl );
});
app . get ( '/exchange_token' , ( req , res ) => {
const { code } = req . query ;
const postData = querystring . stringify ({
client_id: process . env . STRAVA_CLIENT_ID ,
client_secret: process . env . STRAVA_CLIENT_SECRET ,
code: code ,
grant_type: 'authorization_code'
});
const options = {
hostname: 'www.strava.com' ,
path: '/oauth/token' ,
method: 'POST' ,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded'
}
};
const request = https . request ( options , ( response ) => {
let data = '' ;
response . on ( 'data' , ( chunk ) => {
data += chunk ;
});
response . on ( 'end' , () => {
const parsedData = JSON . parse ( data );
if ( parsedData . errors ) {
res . status ( 400 ). send ( `Error: ${ parsedData . message } ` );
} else {
res . send ( `Access Token: ${ parsedData . access_token } <br>Refresh Token: ${ parsedData . refresh_token } ` );
}
});
});
request . on ( 'error' , ( e ) => {
res . status ( 500 ). send ( `Error: ${ e . message } ` );
});
request . write ( postData );
request . end ();
});
app . listen ( PORT , () => {
console . log ( `Server is running on http://localhost: ${ PORT } ` );
});
See all 64 lines
Step 7 - Set Up Strava API Client
Create strava.js to set up the Strava API client:
const https = require ( 'https' );
const querystring = require ( 'querystring' );
// Function to get Strava access token
async function getStravaAccessToken () {
const postData = querystring . stringify ({
client_id: process . env . STRAVA_CLIENT_ID ,
client_secret: process . env . STRAVA_CLIENT_SECRET ,
refresh_token: process . env . STRAVA_REFRESH_TOKEN ,
grant_type: 'refresh_token'
});
const options = {
hostname: 'www.strava.com' ,
path: '/oauth/token' ,
method: 'POST' ,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded'
}
};
return new Promise (( resolve , reject ) => {
const req = https . request ( options , ( res ) => {
let data = '' ;
res . on ( 'data' , ( chunk ) => {
data += chunk ;
});
res . on ( 'end' , () => {
const parsedData = JSON . parse ( data );
if ( parsedData . errors ) {
reject ( new Error ( `Error fetching access token: ${ parsedData . message } ` ));
} else {
resolve ( parsedData . access_token );
}
});
});
req . on ( 'error' , ( e ) => {
reject ( e );
});
req . write ( postData );
req . end ();
});
}
module . exports = { getStravaAccessToken };
See all 49 lines
Step 8 - Set Up Notion API Client
Create a notion.js file to set up the Notion API client using the @notionhq/client library. Use your Notion integration token and database ID.
// notion.js
const { Client } = require ( '@notionhq/client' );
const dotenv = require ( 'dotenv' );
dotenv . config ();
const notion = new Client ({ auth: process . env . NOTION_TOKEN });
const databaseId = process . env . NOTION_DATABASE_ID ;
module . exports = { notion , databaseId };
Step 9 - Fetch Activity Data From Strava
Create a stravaIntegration.js file to fetch activity data from your Strava account:
const https = require ( 'https' );
const { getStravaAccessToken } = require ( '../config/strava' );
// Helper function to make GET requests
async function fetchJson ( url , headers ) {
return new Promise (( resolve , reject ) => {
const options = {
headers: headers
};
https . get ( url , options , ( res ) => {
let data = '' ;
res . on ( 'data' , ( chunk ) => {
data += chunk ;
});
res . on ( 'end' , () => {
resolve ( JSON . parse ( data ));
});
}). on ( 'error' , ( e ) => {
reject ( e );
});
});
}
// Convert pace from min/km to min/mile
function convertPaceToMinPerMile ( paceInMinPerKm ) {
const minPerMile = paceInMinPerKm * 1.60934 ;
const minutes = Math . floor ( minPerMile );
const seconds = Math . round (( minPerMile - minutes ) * 60 );
return ` ${ minutes } : ${ seconds < 10 ? '0' : '' }${ seconds } min/mile` ;
}
// Convert distance from meters to miles
function convertMetersToMiles ( meters ) {
return meters * 0.000621371 ;
}
// Fetch activities from Strava
async function getStravaActivities () {
const accessToken = await getStravaAccessToken ();
const headers = {
'Authorization' : `Bearer ${ accessToken } `
};
const activitiesResponse = await fetchJson ( 'https://www.strava.com/api/v3/athlete/activities' , headers );
// Log the response to understand its structure
console . log ( 'Activities Response:' , activitiesResponse );
if ( ! Array . isArray ( activitiesResponse )) {
throw new Error ( 'Invalid response from Strava API' );
}
return activitiesResponse . map ( activity => {
const paceInMinPerKm = ( activity . moving_time / 60 ) / ( activity . distance / 1000 );
const paceInMinPerMile = convertPaceToMinPerMile ( paceInMinPerKm );
const distanceInMiles = convertMetersToMiles ( activity . distance );
return {
name: activity . name ,
distance: distanceInMiles ,
pace: paceInMinPerMile ,
duration: new Date ( activity . moving_time * 1000 ). toISOString (). substr ( 11 , 8 ), // Duration in HH:MM:SS
elevation_gain: activity . total_elevation_gain ,
type: activity . type ,
date: activity . start_date ,
calories: activity . calories
};
});
}
module . exports = { getStravaActivities };
See all 74 lines
Step 10 - Populate Notion Database with Strava Activity Data
Create a notionIntegration.js file to handle populating the Notion database with all Strava activities.
const { Client } = require ( '@notionhq/client' );
// Initialize the Notion client
const notion = new Client ({ auth: process . env . NOTION_TOKEN });
// Add data to the Notion database
async function addToNotionDatabase ( databaseId , activity ) {
try {
await notion . pages . create ({
parent: { database_id: databaseId },
properties: {
'Name' : {
title: [
{
text: {
content: activity . name
}
}
]
},
'Distance' : {
number: activity . distance
},
'Pace' : {
rich_text: [
{
text: {
content: activity . pace
}
}
]
},
'Duration' : {
rich_text: [
{
text: {
content: activity . duration
}
}
]
},
'Elevation Gain' : {
number: activity . elevation_gain
},
'Type' : {
rich_text: [
{
text: {
content: activity . type
}
}
]
},
'Date' : {
date: {
start: activity . date
}
},
'Calories' : {
number: activity . calories || 0 // Default to 0 if undefined
}
}
});
} catch ( error ) {
console . error ( 'Error adding to Notion database:' , error );
}
}
module . exports = { addToNotionDatabase };
See all 69 lines
Step 11 - Main Script
Create a main.js file that uses the modules created above to execute the integration logic.
require ( 'dotenv' ). config ();
const { getStravaActivities } = require ( './integrations/stravaIntegration' );
const { addToNotionDatabase } = require ( './integrations/notionIntegration' );
const NOTION_DATABASE_ID = process . env . NOTION_DATABASE_ID ;
// Main function to fill the Notion database with Strava activities
async function fillNotionDatabase () {
try {
const activities = await getStravaActivities ();
for ( const activity of activities ) {
await addToNotionDatabase ( NOTION_DATABASE_ID , activity );
console . log (\ `Added to Notion: Name: ${ activity . name } , Distance: ${ activity . distance } , Pace: ${ activity . pace } \` );
}
} catch (error) {
console.error('Error filling Notion database:', error);
}
}
fillNotionDatabase();
See all 22 lines
Step 12 - Run the OAuth Flow
Open your browser and navigate to http://localhost:3000:
You should see a page with a link to authorize with Strava.
Click the link to authorize with Strava:
This will redirect you to Strava’s authorization page.
Authorize the application:
Strava will redirect you to a page with an authorization code.
The server will exchange the authorization code for an access token and refresh token:
The tokens will be displayed on the page.
Copy the refresh token and update your .env file with it.
Step 13 - Run the Integration
Execute the integration script by running the following command:
Customize the code according to your Notion database structure and the properties you want to include for each Strava activity.