Published: April 6, 2020
Build a Netlify-hosted, GitHub auto-deploying, Gatsby-based Website to Display Your Strava Data
I think I have enough keywords in the title to get a few clicks about Gatsby, Netlify, GitHub, and Strava!
Update: I've no idea why, but looks like the code snippets got messed up at some stage, so probably best to just use the text in this article, but go directly to GitHub for the code.
As the title of this post suggests, there are 3 parts to this article
What we are going to do is create a small website that pulls in a list of all your Strava activities. It then creates a page to list them all, and an individual page for each activity so you can see more details about that activity. For no good reason, we'll also pull in a list of all groups that you are a member of. If you'd just like to see the code that does this, you can get the code from GitHub and you can see the finished site here (it's ugly, but I only care about the data for the point of this article).
1. Strava and Gatsby
I'm going to presume that you know what Gatsby is and how to install it, get a basic site running, and look-up GraphQL queries. If not, Gatsby has some great documentation just waiting for you.
Once you have your site installed and running, you will need to get some data from Strava. To do so, you need the Gatsby Source Strava plugin, which you can get by running npm install gatsby-source-strava --save
. You can also find the code for the Gatsby Strava Plugin on GitHub, created by Cédric Delpoux, and with lots of documentation/example code - thanks Cédric.
To get your data from Strava you must click on your profile, then on your settings, and then register for a new application. This will give you some authorisation tokens, which you will need for the next step.
gatsby-source-strava
has a command line tool to build your authorisation where you can simply run gatsby-source-strava-token
from the root of your project, but I couldn't get it to work, so I just called that file directly from the root of my project: node_modules/gatsby-source-strava/scripts/generate-token.js
. This asks you for your access token and guides you through the process.
To fetch the data from Strava, you now need to go to your gatsby-node.js
file and we'll use the createPages
API from Gatsby to create a page for each of our Strava activities. Putting the following in your gatsby-node.js
file will do just that:
const path = require(`path`)
module.exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
return new Promise((resolve, reject) => {
resolve(
graphql(
`
{
activities: allStravaActivity {
edges {
node {
activity {
id
}
}
}
}
}
`
).then(({ data: { activities } }) => {
activities.edges.forEach(({ node: { activity } }) => {
createPage({
path: `/activities/${activity.id}`,
component: path.resolve('./src/templates/activity/index.js'),
context: { id: parseInt(activity.id) },
})
})
})
)
})
}
We now have our data, but we don't have a template to display it. See the line above where we said component: path.resolve("./src/templates/activity/index.js")
? Well, that's where Gatsby is going to look for the template to render our activity. So, go to your src
and create a folder in there called templates
(this is where you can store all your templates). In this create a template for your activities, called activity.js
(in my case, I called mine index.js
and placed it in a directory called activities
) - just make sure the path to it is the same path as we set in our gatsby-node.js
a moment ago. Then put the following code in this template (you can amend it to add more information from your activities).
import React, { Fragment } from "react"
import { Link, graphql } from "gatsby"
import Layout from "../../components/layout"
import SEO from "../../components/seo"
const ActivityTemplate = ({ data: { stravaActivity: { activity }, }, }) => ()
Activity Name: {activity.name}
- Activity Type: {activity.type}
- Average Speed: {activity.average_speed}
- Achievement Count: {activity.achievement_count}
- Average Heartrate: {activity.average_heartrate}
- Distance: {activity.distance}
- Elapsed Time: {activity.elapsed_time}
Home |
Activities |
Clubs | Connect with me on Strava. )
export default ActivityTemplate
export const ActivityPageQuery = graphql`
query($id: Float) {
stravaActivity(activity: { id: { eq: $id } }) {
activity {
average_speed
name
achievement_count
average_heartrate
distance
elapsed_time
type
}
}
}
`
When you now run gatsby build
from your terminal, you should be able to go to localhost:8000/activities/XYZ
(where XYZ is the id of your activity)
To build a page to list all of your activities, and link each to it's respective page, in src/pages
create a file called activities.js
and place the following code in it
import React, { Fragment } from "react" import { Link, graphql } from "gatsby" import Layout from "../components/layout"
import SEO from "../components/seo"
const ActivitiesPage = ({ data }) => ()
My {data.allStravaActivity.edges.length} Activities
Click an activity title for more information about that activity
- {data.allStravaActivity.edges.map(edge => (
-
- Completed: {edge.node.activity.when_date} at {edge.node.activity.when_time}
- Moving time: {edge.node.activity.moving_time} seconds
- Distance of {edge.node.activity.distance} metres
- ))}
Home |
Activities |
Clubs | Connect with me on Strava. )
export default ActivitiesPage
export const ActivitiesPageQuery = graphql`
{
allStravaActivity(sort: { order: DESC, fields: activity___start_date }) {
edges {
node {
activity {
name
id
when_date: start_date(formatString: "MMMM DD, YYYY")
when_time: start_date(formatString: "H:m")
type
moving_time
distance
}
}
}
}
}
`
And to get a list of your clubs and link them directly to their Strava page (rather than an internal page on your site), create a file called clubs.js
in src/pages
with the following code.
import React, { Fragment } from "react" import { Link, graphql } from "gatsby" import Layout from "../components/layout"
import SEO from "../components/seo"
const ClubsPage = ({ data }) => ()
My {data.stravaAthlete.athlete.clubs.length} Clubs
Click on a club name to go to that club's Strava page.
- {data.stravaAthlete.athlete.clubs.map(club => (
- {club.name} {!club.private ? true : '- Private Group'}
- ))}
Home |
Activities |
Clubs | Connect with me on Strava. )
export default ClubsPage export const ClubsPageQuery = graphql` { stravaAthlete { athlete { clubs { name url private } } } } `
All of this will create a .strava
directory in your root directory beside your .cache
directory. Make sure you add it to your .gitignore
file, as it will be created by Netlify when we deploy the site, and also because it contains your access token information and you don't want that publicly available.
That'll do for the Gatsby part!
2. Netlify
Everytime I try out Netlify (and it's only been a few times), I'm constantly amazed at how great it is. I remember Phil Hawksworth giving a great presentation at Frontend United 2019 saying basically Netlify aims to get everything that is difficult about hosting and make it easy. I think they have nailed that principle.
When it comes to hosting an Gatsby site on Netlify, you just need to create a new site in Netlify, choose to deploy from a GitHub repository, and select the repository. From there, you can choose what directory to deploy from. In this case choose public
.
Next, you need to create an environment variable to put the sensitive information from your access token in (that we gitignored a moment ago). To do so:
- Go to your Netlify site
- Click on the "Settings" tab
- Click on "Build & Deploy"
- Click on "Environment"
- Add a new variable called
GATSBY_SOURCE_STRAVA_TOKEN
- Paste everything that is in your
./.strava/token.json
file into the "Value" field - You're done
You can now deploy your site by clicking on the "Deploys" tab and then clicking "Trigger deploy". This will run the npm build
command from your package.json
file and deploy the site from your public
directory.
3. GitHub
Now that we have everything working, let's set up a GitHub action to autodeploy the site every 3 hours. Note, this is not the recommended way to do things with Strava - the recommended way is to set up a webhook so everytime a new activity is added, the site gets re-built, rather than building just for the sake of it every 3 hours. For my purposes, I wanted to see how GitHub actions worked, so did it this way. This will also break after 2 days as your access token will be out of date, but I'm not going to go into auto-regenerating new tokens, since this was just a playground project for me. Here's what you need to do:
- In Netlify - yes, Netlify, not GitHub - click on "Settings" then "Build & Deploy" and scroll down to "Build hooks".
- Add a new build hook. I called mine "Redeploy site". This will give you a URL, and anytime that URL is hit, the site will redeploy.
- In your repo, create a folder called
workflows
at the root leve. This is where we will store all our workflow actions for GitHub; in our case, we'll have only one. - Inside this, add a file called
main.yml
, where we will add our action. - Add the following code to the
main.yml
file which will call a cron function to hit your redeploy endpoint every 3 hours, replacing ADD_BUILD_HOOK_URL_HERE with the URL of your build hook.name: Trigger Netlify Build on: schedule: - cron: '* */3 * * *' # every 3 hours jobs: build: name: Redeploy Site runs-on: ubuntu-latest steps: - name: Curl request run: curl -X POST -d {} ADD_BUILD_HOOK_URL_HERE
That's It!
A Gatsby site, that pulls in data from Strava, is hosted on Netlify, and uses GitHub actions to auto-deploy every 3 hours. Here is the finished site, and here is the complete codebase.