The Strava API has a call to retrieve the first 50 efforts for a segment. In theory, the API supports an offset parameter to allow you to download additional efforts after the first 50. However the offset parameter does not work currently in the segment efforts API. I didn’t want to wait until V3 of the API, so…
Additionally, the segment efforts API returns efforts ordered fastest to slowest, so a naive date-based retrieval does not work, and this may also be why the offset parameter is not currently supported.
I now have a workaround which does the job (albeit a little more slowly): use the startDate and endDate parameters, which do work, to initially pull the efforts across “all time” (or, say, from 2010 to now). If you receive 50 efforts back from the call, then split the time window in half, and retrieve each half. Rinse and repeat until you receive less than 50 efforts for a window, at which point you know you have all the efforts for that window. It’s simple enough to merge the arrays that you receive in response.
This works fine, but is a bit more load on the Strava servers. For example, a segment with 425 efforts required 28 calls as opposed to 9 if the offset parameter worked, or just 1 if you could request the full set of efforts (which is still not a huge download, although really busy segments may be a bit more problematic).
I now optimise to retrieve all efforts for segments just once, then just the last few days worth later on. The downside is that new subscribers will not have old efforts uploaded (to resolve this I may periodically do the full sync again). New segments would also bump into this issue until a global sync is done.
My implementation is not perfect (I’m ignoring errors for now), and if there are 50 efforts in less than 1 second then I’ll get none of them 🙂 Nevertheless, this little PHP code snippet is one way it could be done.
{
if($startDate == 0 && $endDate == 0)
{
$startDate = mktime(0,0,0,1,1,2010);
$endDate = time();
}
if($startDate >= $endDate) return null;
$startDateString = date(“Y-m-d\\TH:i:s\\Z”, $startDate);
$endDateString = date(“Y-m-d\\TH:i:s\\Z”, $endDate);
$efforts = $this->callApi(“/v1/segments/$segmentId/efforts?startDate=$startDateString&endDate=$endDateString”);
$numEfforts = sizeof($efforts->efforts);
if($numEfforts == 50)
{
// split the time period in 2
$midDate = round(($startDate + $endDate) / 2, 0);
$firstEfforts = $this->getSegmentEfforts($segmentId, $startDate, $midDate);
$secondEfforts = $this->getSegmentEfforts($segmentId, $midDate, $endDate);
if($firstEfforts == null) return $secondEfforts;
if($secondEfforts == null) return $firstEfforts;
$firstEfforts->efforts = array_merge($firstEfforts->efforts, $secondEfforts->efforts);
return $firstEfforts;
}
return $efforts;
}
Finding some of the very popular segments are limiting the feasibility of this approach (e.g. segments with over 2000 attempts). So I’ve tweaked the algorithm to stop recursing after 5 calls for now.
This binary search approach is great, and was working well for me for a while. But I’m starting to believe that the time portion of the startDate and endDate parameters is not supported. The Strava docs state that these should be formatted as YYYY-MM-DD, without mentioning time. And the results for a call such as http://app.strava.com/api/v1/segments/621928/efforts?startDate=2011-01-29T10:00:00Z&endDate=2011-01-29T11:00:00Z don’t appear to heed the time parameters at all. Thoughts?
jpo, I believe you are right. Not sure why I didn’t notice that before 🙂
Of course, the concern is what if there’s more than 50 efforts in a day? With Low-Key Hillclimbs this is not unusual.
I’m really looking forward to v3 coming on-line. For my present application, I need only to read and write single events, however, for which I hope the present infrastructure is sufficient.
Hanging out for V3 also… Or even a fix to V2 so you can get more than 50 efforts from a segment in the ‘correct’ way…
I’d been struggling with the API and segments with the offset parameter. After I realized it didn’t work Google directed me to your site. I was just about to implement your method when I noted that other queries ie efforts by athlete use a “?”. Anyway the offset parameter appears to work if you use “?offset=x” rather than “&offset=x”.
Hope this helps.
What I’m still struggling with is getting all segment efforts using v2 of the API and getting the leaderboard.
Ian
Hello all.
I’m developing an iPhone app using the Strava API and I can’t make the segment leader board work with offset parameter. Curious to know if someone could tell me if this seems right to you:
http://www.strava.com/api/v1/segments/229781/efforts?best=true&offset=50
I’ve tried also using the question mark, with no success:
http://www.strava.com/api/v1/segments/229781/efforts?best=true?offset=50
Thanks !
Martin
I can’t make the segment leader board work for my app, I’m developing in objective c and the url I’m trying to query is:
http://www.strava.com/api/v1/segments/229781/efforts?best=true&offset=50
Does it seems right to you ?
Any help is appreciated.
MR
Martin, yes, the bug still exists in v2 of the API. You can’t query more than 50 segment efforts. And I have not yet seen any resolution to this.
Well, I now learn that the bug has been fixed, partially at least. You can at least retrieve more than 50 efforts for a given date, apparently: Strava API for efforts per segment: Limitations and workarounds, comment by jpo