Log Strava Activity in Notion
This developer documentation provides a step-by-step guide to create an integration between the Notion API and the Strava API using JavaScript. The integration fetches data from a Strava athlete's activities and populates a Notion database with their activity data.
This integration requires following Strava's OAuth flow. Please refer to Strava's OAuth documentation for more information.
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.
- Go toΒ Strava API.
- Click onΒ Create An App.
- Fill in the required details and clickΒ Create.
- Copy theΒ Client IDΒ andΒ Client Secret.
Notion API Key
- Log in to your Notion account.
- Go toΒ Notion Integrations.
- 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
βββ .env
βββ package.json
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 yourSTRAVA_ACCESS_TOKEN
andSTRAVA_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}`);
});
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 };
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 };
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 };
Step 11: Main Script
Createa 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();
Step 12: Run the OAuth Flow
- Start the OAuth Server:
node src/server.js
- 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:
npm start
Customize the code according to your Notion database structure and the properties you want to include for each Strava activity.