Setting up Strava Webhooks

Strava has an incredible data set and I wanted to demonstrate how easy it is to get set up with real time data with their Webhooks API.

First, we need to create an application.

Some dummy data is sufficient

After you fill that out, it’ll ask you to upload an image (anything will work). Once you get through that, you should have the information you need to get going:

Note the Client ID and Client Secret

If you check their wonderful webhooks documentation, it describes how to create a subscription via a simple curlcommand.

curl -X POST \
-F client_id=CLIENT_ID \
-F client_secret=CLIENT_SECRET \
-F 'callback_url=CALLBACK_URL' \
-F 'verify_token=STRAVA'

We know what the CLIENT_ID and CLIENT_SECRET are since we created them already. The verify_token is simply a way of authenticating that the initial handshake of the subscription actually came from Strava. Read the documentation on more about that. But what about the CALLBACK_URL. This is essentially where Strava will POST events to when new ones are created. It would likely be something like

But what if we’re developing locally. Your server is going to be hosted on localhost inaccessible to the outside world.

Enter ngrok.

Ngrok is a really neat tool that allows you to expose a localhost port to a publicly accessibly URL. This is super useful if you need to demo something for a product manager real quick.

Sign up for an account and visit the dashboard to get your authtoken.


I personally like to install ngrok with Homebrew Cask.

brew cask install ngrok
ngrok authtoken YOUR_TOKEN

Finally, we are ready to start coding!

Set up a simple Sinatra app:

In the app.rb file, we are setting up a simple GET endpoint that echoes back the challenge token Strava provides in the initial subscription.

You can start this with bundle exec rackup, which should be running on port 9292 by default. Once you do that, in a new tab, start up ngrok with ngrok http 9292. You should see something like this:

ngrok http 9292

The forwarding URL is the important bit. If you were to try to access the URL, you’ll get the “Sinatra doesn’t know this ditty.” meaning that it’s successfully forwarding localhost and hitting Sinatra.

Since our endpoint is at GET /event, our callback URL is

Important: when you’re on the free plan with ngrok, the forwarding URL changes each time you start up ngrok!

We can finally set up our subscription with Strava!

curl -X POST \
-F client_id=CLIENT_ID \
-F client_secret=CLIENT_SECRET \
-F 'callback_url=' \
-F 'verify_token=STRAVA'

If everything went well, you should get back a message like this:


Now just one more piece to put it all together. We need to add a POST endpoint to receive events.

Here we have our POST /event endpoint set up which immediately responds back with a 200 OK, prints out the event, and then logs the event to a file.

To test this, create a manual entry and you should get something printed to the console.

{“aspect_type”=>”create”, “event_time”=>1517901354, “object_id”=>1393871891, “object_type”=>”activity”, “owner_id”=>27995927, “subscription_id”=>121065, “updates”=>{}} — — [06/Feb/2018:00:15:55 -0700] “POST /event HTTP/1.1” 200–0.0029

The object_id references the activity. Hence, you can use the rest of the Strava API to get more interesting data.

We are also logging directly to a file. When you start playing with real time data, you’ll likely want to save the information to S3 and do ETL processing on it later (well beyond the scope of this article).

Hopefully this has helped you get started with real time data and Strava. The code for all of this is available on GitHub.

Feel free to follow me on Strava and deliver those sweet, succulent kudos.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.