Build a Workout Accountability SMS Buddy with the Strava API, Twilio Functions, and the Twilio CLI
Tags: twilio, strava, javascript
Published: 2020-04-28 22:41:42

---
title: Build a Workout Accountability SMS Buddy with the Strava API, Twilio Functions, and the Twilio CLI
published: true
description: Get a deep dive into using the Strava API and hold yourself accountable for exercising with a Twilio app using Twilio SMS, Functions, and the Serverless Toolkit.
tags: twilio, strava, javascript, js
---
![header](https://twilio-cms-prod.s3.amazonaws.com/images/strava.width-1616.png)

This blog post was written for [Twilio](https://www.twilio.com/) and [originally published on the Twilio blog](https://www.twilio.com/blog/quarantine-workout-accountability-sms-buddy).

With gyms closed during quarantine, many people are trying to run or bike more outdoors (at a safe social distance from others, of course!) [Strava](http://strava.com/) is a popular social fitness app that helps users track and share outdoor workouts. Read on to learn how to build a quarantine workout accountability SMS system with the [Strava API](https://developers.strava.com/), [Twilio Functions](https://www.twilio.com/console/functions/manage), and the [Twilio Serverless Toolkit](https://www.twilio.com/docs/labs/serverless-toolkit).

![sample sms](https://twilio-cms-prod.s3.amazonaws.com/images/Screen_Shot_2020-04-28_at_1.45.18_PM.width-1000.png)

### Prerequisites
1. A Strava account - [sign up here](https://www.strava.com/register/free) if you don't have one already
2. A Twilio account - [sign up for a free one here and receive an extra $10 if you upgrade through this link](http://www.twilio.com/referral/iHsJ5D)
3. A Twilio phone number with SMS capabilities - [configure one here](https://www.twilio.com/console/phone-numbers/search)
4. [Postman](https://www.postman.com/downloads/) (you could alternatively make cURL requests from the command line)

### Setup the Strava API
![Run Forrest Run gif](https://twilio-cms-prod.s3.amazonaws.com/original_images/Pbn_xo8AvkRYykUx3wTBaaYIt4c_liUZ_1PR24K5G6aj8hNCdkV1OHlFrW5a30VsxMbqNhXZ16HFhj)

In order to use the [Strava API](https://developers.strava.com/), you need to create an app. If you’re reading this, you likely already have a Strava account but if not go ahead and create one now from the <em>Prerequisites</em> link above. Sign in to your Strava account and navigate to [your API settings page](https://www.strava.com/settings/api). You can alternatively find that by selecting `My API Application` in the dropdown menu on the left of your [regular account settings](https://www.strava.com/settings/profile).

![Strava profile dropdown](https://twilio-cms-prod.s3.amazonaws.com/images/OHHfe49OsMLFK2l6aTtoTt4dZbm--4IOIYgybH2b9vhSr.width-1000.png)

You should now see the “My API Application” page. Fill it out accordingly:

![my application page](https://twilio-cms-prod.s3.amazonaws.com/images/A-jQX7Ev5Gflbk67vAnxktOW9j3FMCHK2MZyJYTzPfPQj.width-1000.png)

1. <strong>Application name</strong> (I called mine <em>Quarantine Accountability</em>)
2. <strong>Category</strong> (<em>social motivation</em>, perhaps?)
3. <strong>Club</strong> (I left this blank as I'm not in a Strava club and it's not required)
4. <strong>Website</strong> (I used my personal website, this can be anything)
5. <strong>Application description</strong> (<em>"maybe this will make me run more?"</em>)
6. <strong>Authorization Callback Domain</strong> (<em>localhost</em>)

Agree to Strava's API agreement and click <em>Create</em>. Yay! You have your first Strava application.

![Usain Bolt gif](https://twilio-cms-prod.s3.amazonaws.com/original_images/m6qVNCIFDonSUD1j2xr7HRqplIMZ7OV2KhGWuy5mpvOGcwE14hTliMsgzFiuVJurVmGKHdsEaYshuX)

### Make your first Strava API Request
The Strava API docs go over the endpoints you can use and the arguments they take. This post will start off hitting the endpoint to receive your personal statistics which requires two pieces of information for query string parameters:
1. Your numeric athlete ID is found by navigating to your Strava profile (click <em>My Profile</em>) in the top right corner and look at the URL after <em>/athletes</em>.
![athlete profile](https://twilio-cms-prod.s3.amazonaws.com/images/fOvWRUviUv5X5tzmPrJ10uEOWXDInv_w5R5LSzK1VZe8L.width-1000.png)
2. Your Access Token, found in your [API application settings](https://www.strava.com/settings/api).
![access token in console](https://twilio-cms-prod.s3.amazonaws.com/images/ro3_Cgwa95SEPRUhH3eFH6HVh80HscSQhqjmwIAtEoweS.width-1000.png)

Open Postman and paste https://www.strava.com/api/v3/athletes/{your-athlete-ID}/stats into the URL bar, replacing {your-athlete-ID} with your ID from above (from your personal Strava page, not your API settings page.)

![postman url bar](https://twilio-cms-prod.s3.amazonaws.com/images/3m_bc7RkN8KM-TZXmQK4yTsTMqfX2Ls6OfJDg9u5r9Iu2.width-1000.png)

Underneath the URL bar, select <em>Params</em>.  Add a <em>Key</em> called <em>access_token</em> and its corresponding <em>Value</em> of your access Token from the last step.

![access token in Postman](https://twilio-cms-prod.s3.amazonaws.com/images/o44H4Idgr-8xQQkGBCSQPLAewaBGlKp_o-tEI0fS69A5qt.width-500.png)

Click the blue `Send` button to make a GET request and you should see something like this in Postman:

![Postman response](https://twilio-cms-prod.s3.amazonaws.com/images/Screen_Shot_2020-04-28_at_1.18.49_PM.width-1000.png)

Nice! You just accessed your statistics in a nice JSON format. Feel free to play around with [different Strava endpoints](https://developers.strava.com/docs/reference/) and see what other information you can access.

![bike gif](https://twilio-cms-prod.s3.amazonaws.com/original_images/Az8NFmfqy92XQo6o7J3sA1PKvQV5OYE3H80UgYI_oM3xD3WrMcwMerS1M0gaiYKnikXx0x1s90R_qw)

### Strava Activity Webhook Authentication
Strava changed its API authorization process in 2018. The Access Token from above has `scope:read` which is insufficient to make a request to each endpoint. For example, to access any Activity webhook the scope must instead be `activity:read`. Let's make an Access Token that can hit an Activity webhook.

1. Grab your client ID from your Strava app settings. In a web browser tab, type into the URL bar `https://www.strava.com/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost&response_type=code&scope=activity:read` and click `enter`. You should see a screen like this:
![authenticate page](https://twilio-cms-prod.s3.amazonaws.com/images/KZSrFQjscblxgY6re55l5vc-0zfGai4GD0mkmhmolWsK8.width-1000.png)
2. Click `Authorize`. In the URL bar, copy the `code` as shown below.
![code in URL bar](https://twilio-cms-prod.s3.amazonaws.com/images/M3O2Wk4X49H1eoNQ45vRiYNEtwBM0yPatbrumc4w18skS.width-1000.png)
3. Now back in Postman, add `https://www.strava.com/oauth/token` in the Postman URL bar and add the following parameter keys and their corresponding values: `client_id` and `client_secret` whose values you can find in your Strava app settings, code with the code from step two, and `grant_type` whose value is <em>authorization_code</em>.
![Postman parameters for authentication](https://twilio-cms-prod.s3.amazonaws.com/images/Screen_Shot_2020-04-28_at_1.18.31_PM_kuUnDla.width-1000.png)

Make the POST request and you should receive some JSON like this:
![new access token in Postman](https://twilio-cms-prod.s3.amazonaws.com/images/86wO4puIHwhz1kj0BNy02ucGNbbrW3lRKnAQ46_nt2PhH.width-1000.png)

With this new Access Token we can access the [Strava Activities endpoint](https://developers.strava.com/docs/reference/#api-Activities). To test the information we receive from this endpoint, make another Get request in Postman that looks something like this:
![Get request in Postman for authentication](https://twilio-cms-prod.s3.amazonaws.com/images/Hf2OxSwF6Nx70GSfegQxt-R-ZyJmAwA23nNgsvhG2WOY7.width-1000.png)

This returns details about the most recent Strava activity completed.

![information received from Activities endpoint in Postman](https://twilio-cms-prod.s3.amazonaws.com/images/13UyfsoYEnelKkYUjp2F5-DLZG8DZs5Fc3_RhUBkqSS6Cb.width-500.png)

Now we can move on to making our Twilio app with the CLI and Functions to hold ourselves accountable for exercising.

### Make and Test the Function Locally
Let’s write a function that uses the Strava API to compute the time and distance of our last activity, and wraps that information in TwiML. To debug our Function more easily, we'll use the [Serverless Toolkit](https://www.twilio.com/docs/labs/serverless-toolkit) developed by [my teammate Dominik](https://twitter.com/DKundel/). For more details on installation and project structure, check out [the docs on how to develop and debug Twilio Functions locally](https://www.twilio.com/docs/labs/serverless-toolkit/getting-started).

The best way to work with the Serverless Toolkit is through the Twilio CLI. If you don't have the Twilio CLI installed yet, run the following commands to install it and the Serverless Toolkit:

```
npm install twilio-cli -g
twilio login
twilio plugins:install @twilio-labs/plugin-serverless
```

Afterwards create your new project by running:
```
twilio serverless:init twilio-function strava-demo
cd strava-demo
npm install got
```

`cd` into `strava-demo/functions` and make a new file called `strava.js` containing the following code:
```JavaScript 
const got = require('got');
exports.handler = async function (context, event, callback) {
  let twiml = new Twilio.twiml.MessagingResponse();
  try {
    const response = await got(
  `https://www.strava.com/api/v3/athlete/activities?per_page=1&access_token=${context.STRAVA_ACCESS_TOKEN}`
    );
    const data = JSON.parse(response.body);
    var distance = data[0].distance;
    //convert distance in meters to miles if activity distance is less than 1 mile
    if(!distance < 1609.34) {
        distance = Math.round(data[0].distance * 0.000621371192); //meters to miles
        distance = distance.toString().substring(0,6);
        distance += '-mile';
    }
    else {
        distance += '-meter';
    }
    const date = data[0].start_date;
    const prettyDate = date.substring(5,10); // month and day
    var time = data[0].moving_time;
    time = secondsToHrsMins(time);
    const activityType = data[0].type.toLowerCase();

   twiml.message(
     `{insert-your-name}'s last Strava workout was a ${distance} ${activityType} on ${prettyDate} in ${time} minutes. Encourage them to ${activityType} again soon.`
   );

    callback(null, twiml);
  } catch (error) {
    console.log(error);
    twiml.message("There was an error getting the data from the Strava API. Try again later or ping {your-name} directly to motivate them to get some fresh air today.");
    callback(null, twiml);
  }
};
function secondsToHrsMins(seconds) {
    var date = new Date(null);
    date.setSeconds(seconds); // specify value for SECONDS here
    return date.toISOString().substr(11, 8);  
}
```

Add your `Access Token` from the authentication portion as an environment variable in your Function's `.env` called STRAVA_ACCESS_TOKEN so others can't see it and use it, and check that the `got` module is listed as a dependency (not a devDependency) in your projects <em>package.json</em>, both files of which are in your root directory. Still in your root directory, run followed by `npm start`. You should see some local URLs you can test.

![URLs to test](https://twilio-cms-prod.s3.amazonaws.com/images/lR6HV3C66AWTycHzXD6A5APpaxi6tYi1PbqKGIbb5WSKb.width-1000.png)

Going to `localhost://3000/strava` in the browser should display a page like this:
![XML page in browser](https://twilio-cms-prod.s3.amazonaws.com/images/zHe_oqrEPyTAnzwUq-H0QBoNfxntTpPwoYbcPDWtAqXc2.width-1000.png)

### Configure our Function with a Twilio Phone Number
To open up our app to the web with a public-facing URL, run `twilio serverless:deploy`. You should see this at the bottom of your terminal:
![deploy](https://twilio-cms-prod.s3.amazonaws.com/images/HyGvqaliBd3qKLV817zbJuelyRUwj6Qh60rBHdb8qpbUr.width-1000.png)

Grab the Function URL corresponding to your app (here it has `/strava`) and [configure a Twilio phone number](https://www.twilio.com/console/phone-numbers/incoming) with it as shown below.

![configure twilio number](https://twilio-cms-prod.s3.amazonaws.com/images/3NJyb2-G0A0-ggkXxLglfhZu361anrjIFvKPcHvjL4Cyg.width-1000.png)

Click <em>Save</em> and now text anything to your Twilio phone number for a response like this one:

![sms test](https://twilio-cms-prod.s3.amazonaws.com/images/Screen_Shot_2020-04-28_at_1.37.16_PM.width-1000.png)

Warning: Strava Access Tokens expire after six hours. For more information on refreshing expired Access Tokens, check out [this section of the Strava docs](https://developers.strava.com/docs/authentication/#refreshingexpiredaccesstokens).

### What's Next
![happy run Liz Lemon gif](https://twilio-cms-prod.s3.amazonaws.com/original_images/happyrun.gif)

You can access and play around with different JSON information with [different Strava API endpoints](https://developers.strava.com/docs/reference/). I don't know about you, but I feel like it's time to go for a run so people don't ask me why I haven't done so in a while. Let me know online or in the comments section what you're working on.

- Twitter: [@lizziepika](http://twitter.com/lizziepika)
- GitHub: [elizabethsiegle](http://github.com/elizabethsiegle)
- Email: lsiegle@twilio.com