How To Create Your Own Strava Stats Widget

Strava is one of the world’s most loved social networks for tracking all things fitness. You can track your runs, rides, swims and many other types of sports with the app. The site tracks a lot of information about your workouts and even provides a few widgets to embed on your site – unfortunately these widgets are mainly for displaying your latest activities, and you can’t tweak the style.

In this tutorial, we are going to create our very own widget that will display our Lifetime Stats with the help of the Strava API. This widget will display our All-Time stats for runs, rides, and swims, and you can customise the style to suit the design of your website šŸ‘ŒšŸ».

The finished widget can be view here.

1. Create a Strava App

Strava requires that we create an app to interact with their API. Luckily they make this an easy enough process, so log into Strava and navigate to Settings > API where you will be presented with the ability to create an App.

The main fields we have to fill in are below

  • Application Name – A short name to describe your app.
  • Website – Website associated with the app.
  • Application Description – A brief description about what your app does.
  • Authorization Callback Domain – Domain to be used to authorise user and redirect them back. (We must provide a domain but our app won’t require this functionality).

My application fields

Once we click the create button, we next need to upload a 124px x 124px app icon. You can use my one located here.

Congrats, now you have your very own Strava app created! Next up we have to use the generated values given to use by Strava.

2. Connect to API via access token

Next, we are going to use our app’s access token to connect to our own profile and see what the API returns.

$athlete_id = 'YOUR_PROFILE_ID';
$access_token = 'YOUR_ACCESS_TOKEN';
		
$strava_stats_api = 'https://www.strava.com/api/v3/athletes/' . $athlete_id . '/stats?access_token=' . $access_token;
echo $strava_stats_api;

The above code creates two variables (athlete id & access token), adds them to the athletes REST URLĀ  and then outputs the full URL – which looks something like this:

https://www.strava.com/api/v3/athletes/YOUR_PROFILE_ID/stats?access_token=YOUR_ACCESS_TOKEN

If we copy and paste this URL into our address bar, we get JSON data returned with our main stats.

This is just a quick and dirty way to show you the data that the API returns but we can’t build our widget with just an access token as Strava sets it to expire every 6 hours.

3. Keep Access token updated

The Strava documentation says this about refreshing expired access tokens.

Access tokens expire six hours after they are created, so they must be refreshed in order for an application to maintain access to a userā€™s resources. Every time you get a new access token, we return a new refresh token as well. If you need to make a request, we recommend checking to see if the short-lived access token has expired. If it has expired, request a new short-lived access token with the last received refresh token.

So we need to keep the access token updated and below we are going to use CURL to achieve this.

/** 
* Keep access token updated 
*/
$oath_url =  'https://www.strava.com/oauth/token?';

$oauthFields = array
(
   'client_id' => 'CLIENT_ID',
   'client_secret' => 'CLIENT_SECRET',
   'refresh_token' => 'REFRESH_TOKEN',
   'grant_type' => 'refresh_token'
);

$parameters = http_build_query($oauthFields);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $oath_url.$parameters);
curl_setopt($ch, CURLOPT_POST, count($oauthFields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)');

$urlResponse = curl_exec($ch);
curl_close($ch);
$obj = json_decode($urlResponse, true);

$access_token = $obj['access_token'];
$refresh_token = $obj['refresh_token'];

With this above code, we no longer have to worry about expiring access tokens, huzzahh!

If you would like me to explain this block in-depth, just reply by tweet at the bottom of this article.

4. Caching our JSON results

Now we can pull in our data all we want! Well no we can’t actually šŸ™ The API limits our requests by 100 requests every 15 minutes and 1,000 total requests per day. Not to worry – we just have to cache our results so instead of repeatedly hitting the API, we cache it to a file and make a new request every 5 minutes.

$strava_json; // Declare our Strava data variable
$athlete_id = 'ATHLETE_ID'; // Your profile ID
$strava_stats_api = 'https://www.strava.com/api/v3/athletes/' . $athlete_id . '/stats?access_token=' . $access_token; // The REST URL for our stats
$filename = __DIR__ . 'strava-athlete.json'; // The filename of our cached Strava data

// Our data is cached and less than 5 minutes old, pull data from the cached file
if( file_exists($filename) && ( (time() - 60 * 5 ) < filemtime($filename) ) )
{
   $strava_json = json_decode(file_get_contents($filename), true);
}
// Our data is older than 5 minutes, request a new call to the API
else
{
   $strava_json = file_get_contents($strava_stats_api);
   file_put_contents($filename, $strava_json);
   $strava_json = json_decode($strava_json, true);
}

5. Pulling in our Strava Stats

I am going to create 3 variables that will each hold an array of stats from the rides, runs, and swims arrays in our $strava_json data.

$all_ride_totals = $strava_json['all_ride_totals'];
$all_run_totals = $strava_json['all_run_totals'];
$all_swim_totals = $strava_json['all_swim_totals'];

Retrieving all required data

We are just going to get our counts and distance values but as the distance value is in metres we have to convert to kilometres by dividing by 1,000 and then using PHP’s number_format to format the result with commas.

$all_ride_totals = $strava_json['all_ride_totals'];
$all_run_totals = $strava_json['all_run_totals'];
$all_swim_totals = $strava_json['all_swim_totals'];
		
$all_ride_totals['distance'] = number_format($all_ride_totals['distance'] / 1000, 0) . 'km';
$all_run_totals['distance'] = number_format($all_run_totals['distance'] / 1000, 0) . 'km';
$all_swim_totals['distance'] = number_format($all_swim_totals['distance'] / 1000, 0) . 'km'; ?>

6. Create our HTML/CSS widget box

The final step is to throw our data into a nicely formatted table to show off our Strava stats and we’re done!

Mark-up

<div class="strava-widget">
   <table class="strava-stats">
      <tr>
         <th class="caption" colspan="6">Strava Lifetime Stats</th>
      </tr>
      <tr>
         <td class="heading" colspan="2">Cycling</td>
         <td class="heading" colspan="2">Running</td>
         <td class="heading" colspan="2">Swimming</td>
      </tr>
      <tr>
         <td>Rides</td>
         <td><strong><?php echo $all_ride_totals['count']; ?></strong></td>
         <td>Runs</td> 
         <td><strong><?php echo $all_run_totals['count']; ?></strong></td>
         <td>Swims</td> 
         <td><strong><?php echo $all_swim_totals['count']; ?></strong></td>
      </tr>
      <tr>
         <td>Distance</td>
         <td><strong><?php echo $all_ride_totals['distance']; ?></strong></td>
         <td>Distance</td> 
         <td><strong><?php echo $all_run_totals['distance']; ?></strong></td>
         <td>Distance</td> 
         <td><strong><?php echo $all_swim_totals['distance']; ?></strong></td>
      </tr>
   </table>
</div>

Our CSS

.strava-widget {
   float: left;
   width: 100%;
}
   .strava-stats {
      border-top: 1px solid #ccc;
      border-right: 1px solid #ccc;
   }
      .strava-stats .caption {
         background: #dbdada;
         font-weight: bold;
      }
         .strava-stats th,
         .strava-stats td {
            padding: 15px;
            border-left: 1px solid #ccc;
            border-bottom: 1px solid #ccc;
            width: calc(100% / 6)
         }
         .strava-stats .heading {
            background: #dbdadac7;
            font-weight: bold;
            text-align: center;
         }

This widget gives you the total count of activities for each sport, and total distance. You should explore the API and have fun with it.

You can reply to this post by tweeting to me