API - RunSaturday for Developers

RunSaturday allows its users to share their data.


If you're a developer and would like to build on data from runsaturday, then here are some of our APIs.

If there's something you want to do - but the current API isn't rich enough for you - then please come over to Talk and ask

Data Formats

For output, runSaturday supports two main formats:

  • ATOM (an XML format - a bit like RSS)
  • JSON

For data upload, runSaturday supports SOAP XML web services

Activity Lists

To get hold of an athlete's recent runs (where that athlete is called targetUserName), you will be able to use a path like:

http://www.runsaturday.com/RSS/AnalysisRSS.aspx?TargetUser=<targetUserName>&<optionalParams>

The optionalParams include:

  • UserName - a user name to use for the RSS get (if none is provided then anonymous access will be assumed)
  • Password - the password associated with UserName
  • StartDate - the date to start the search - if none is provided, then 31 days ago is assumed
  • EndDate - the end date for the search - if none is provided, then today (GMT/BST time) is assumed.
  • ShowRuns - should runs be included - assumed true by default - similarly ShowAqua, ShowSwims, ShowBikes, ShowCross, ShowWalks, ShowSkates
  • xml - set this to 1 if you want data rather than text friendly xml

As an example:

http://www.runsaturday.com/RSS/AnalysisRSS.aspx?TargetUser=Hollywoof&StartDate=13%20Feb%202009&EndDate=13%20Mar%202009&xml=1

There are further options - including Distance, Pace and Day of the week filtering - similar to that shown on the Analysis page.

The response from this query contains data entries similar to:

<RSActivity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.runsaturday.com/runsaturday/rss/activity/v1">
<ActivityId>44003</ActivityId>
<ActivityXmlId />
<CourseNumLaps>0</CourseNumLaps>
<CourseId>0</CourseId>
<UserId>3</UserId>
<AverageHR>0</AverageHR>
<AveragePace>1900-01-01T00:18:10</AveragePace>
<AveragePaceExclStops>1900-01-01T00:18:10.909</AveragePaceExclStops>
<PaceGroup>1900-01-01T00:18:00</PaceGroup>
<AverageSpeed>3.3</AverageSpeed>
<AverageSpeedExclStops>3.3</AverageSpeedExclStops>
<MaximumSpeed>0</MaximumSpeed>
<UnitsText>km</UnitsText>
<UnitsTextLong>km</UnitsTextLong>
<Cadence>0</Cadence>
<CadenceExclStops>0</CadenceExclStops>
<Calories>0</Calories>
<Distance>2.2</Distance>
<DistanceInM>2200</DistanceInM>
<HasDetail>false</HasDetail>
<HasMapDetail>false</HasMapDetail>
<HasHeartMapDetail>false</HasHeartMapDetail>
<DistanceGroup>2</DistanceGroup>
<LocationKnown>false</LocationKnown>
<LocationLat>0</LocationLat>
<LocationLong>0</LocationLong>
<EndLocationLat>0</EndLocationLat>
<EndLocationLong>0</EndLocationLong>
<LocationText /> <MapUrlParamString />
<MaxHR>0</MaxHR>
<MinimumPace>1900-01-01T00:00:00</MinimumPace>
<Notes>&lt;p&gt;&amp;#160;Up and down - maybe 20 strokes per length?&lt;/p&gt;</Notes>
<StartTime>2009-03-13T13:00:00</StartTime>
<SubType>Pool</SubType>
<Type>83</Type>
<TypeShortString>Swim</TypeShortString>
<Title>Lunchtime swim</Title>
<TotalTime>1900-01-01T00:40:00</TotalTime>
<UserDisplayName>Hollywoof</UserDisplayName>
<UserCountryName />
<ProcessedType>Swim</ProcessedType>
<WeatherCondition>Unknown</WeatherCondition>
<WeatherConditionText>-</WeatherConditionText>
<WindDirectionDegrees xsi:nil="true" />
<WindSpeedKmh xsi:nil="true" />
<TemperatureCelcius xsi:nil="true" />
<HumidityPercent xsi:nil="true" />
<AveragePower>0</AveragePower>
<AveragePowerExclStops>0</AveragePowerExclStops>
<MaximumPower>0</MaximumPower>
<AltitudeGainM>0</AltitudeGainM>
<AltitudeLossM>0</AltitudeLossM>
<UserDefinedLocationText>Lensbury</UserDefinedLocationText>
<OriginatingId>RunSaturdayUI:5cd619c35b9a4bc993aba0e78023b4c3</OriginatingId>
<Intensity>0</Intensity>
<STIAverage>0</STIAverage>
<STIScore>0</STIScore>
<IsMapInPrivateLocation>false</IsMapInPrivateLocation>
<TemperatureFahrenheit xsi:nil="true" />
<TemperaturePrefs>Fahrenheit</TemperaturePrefs>
<TemperatureLocalUnits xsi:nil="true" />
</RSActivity>

Most of these fields should be fairly self explanatory... for the rest I'll update this page soon!

If you would rather have JSON instead of XML then use a string like

http://www.runsaturday.com/RSS/AnalysisJSON.aspx?TargetUser=<targetUserName>&<optionalParams>

where the parameters are exactly as above

  • except that the parameter is not used.
  • and that there is an additional parameter callback=<javascript_function_name> which allows the JSON to be used across multiple domains

Yahoo! Pipes

Thanks especially to Haayman there are several Yahoo! Pipes examples available which manipulate the RSS/ATOM from runSaturday.

These pipes demonstrate how to pull out and manipulate the data you are most interested in - or they can be used off the shelf with REST parameters for your developments. For example

Yahoo! Pipes are also useful if you want to add "Badges" to external sites - e.g. sidebars to blogs (see the sidebar on hollybar.blogspot.com)

Activity Details

To get hold of an individual activity, runsaturday exposes a level of analysis called ChartPoints - these provide detailed point-by-point tracking for an activity.

To get hold of a specific activity (where the id is number ActivityId - as listed in a LIST above), you will be able to use a path like:

http://www.runsaturday.com/RSS/ActivityRSS.aspx?ActivityId=<activityId>&<optionalParams>

The optionalParams currently only include:

  • UserName - a user name to use for the RSS get (if none is provided then anonymous access will be assumed)
  • Password - the password associated with UserName

You only need to include these optionalParams if the activity requested belongs to an athlete who wishes to keep his or her details private.

For example:
http://www.runsaturday.com/RSS/ActivityRSS.aspx?ActivityId=42882

The response from this query contains:

  • A single RSActivityChartPointGroup
  • containing a set of Laps
  • Each of which is a LapChartPointGroup
  • Which contains a list of Tracks
  • Each TrackChartPointGroup has a list of ChartPoints
  • Each ChartPoint has properties about time/distance/speed...

So basically an Activity has zero or more Laps - each Lap has zero or more Tracks - each Track has zero or more ChartPoints

An example ChartPoint is:

<ChartPoint>
<Speed>8.1974650929788986</Speed>
<PointTime>2009-03-10T19:36:34Z</PointTime>
<Position>
<Longitude>-0.3440729</Longitude>
<Latitude>51.4326103</Latitude>
</Position>
<MinutesSinceStart>0.11666666666666667</MinutesSinceStart>
<MinutesSinceStartExcludingGaps>0.11666666666666667</MinutesSinceStartExcludingGaps>
<Altitude>3.5019531</Altitude>
<Cadence xsi:nil="true" />
<HeartRate xsi:nil="true" />
<DistanceSeenToDate>16.4910584216315</DistanceSeenToDate>
<DistanceSeenToDateLocalUnits>0.0164910584216315</DistanceSeenToDateLocalUnits>
</ChartPoint>

API Limits

runSaturday has no strict API limits enforced currently...

However, we ask developers to please not call more than once per second and to cache user data wherever possible - so as not to stress our servers.

If you are building an application that you are concerned is going to stress our service, then please get in touch!

Example Activity Displays - Javascript with JQuery and JSON for maps and charts

Charts

Here's an example of how you can use javascript and runsaturday's data interfaces to extend the runsat charting analysis:

http://slodge.com/runsatplot/default.html?activity=246486

where "activity=246486" can be replaced with your own favourite charting number.

This example is less than 200 lines long - and really I hope should be Ok for most people to follow and change.

For charting and HTML manipulation it uses:
- jquery - http://jquery.com/
- jflot - http://code.google.com/p/flot/

As an explanation of how it works, here are all the javascript functions it contains:

getUrlVars
From http://jquery-howto.blogspot.com/2009/09/get-url-parameters-values-with-jquery.html
This is only used to parse the activity number from the url.

makeAjaxRequest
This makes a request to runsaturday for the activity data and specifies prepareAndPlotData as the callback function.

plotData(plotName, toPlot, color)
This plots an individual chart using:
- plotName as the title
- toPlot as the data - this is organised as an array of arrays - each inner element is an x.y pair, e.g. toPlot might look like [ [0,5], [1,6], [2,5], [3,6], .... ]

addSeparator
Just adds a space to the display - nothing exciting

outputDebugInfo
Adds the list at the bottom of the display - each of these listed items is a bit of info about the Activity

prepareAndPlotData(data)
This is the method called back by runsaturday.
This method, parses the incoming data into a format friendly enough for plotData, then calls plotData.
The incoming data is organised as a single object:

  •  with a property Activity (see outputDebugInfo for its contents)
  •  with a property Laps - this property is an Array of Lap objects, each Lap object has an array of Tracks inside it, each Track has an array of ChartPoints inside it - each ChartPoint has fields inside it including:
    •  Altitude
    •  Cadence
    •  HeartRate
    •  PaceInMinutes
    •  Position
    •  Power
    •  Speed
    •  DistanceSeenToDateLocalUnits
    •  MinutesSinceStartExcludingGaps


That's it :)

If you want to play, all the source (including jflot and jquery) is available at: http://slodge.com/runsatplot/Charty.zip

If anyone wants to build something, then please do

Maps

If anyone wants to extend your analysis by drawing your own maps, then this is also very possible  

The best way to do this is to use the JSON api - which is introduced in my last post about how to draw your own charts.

As an example of how to draw your own maps - for UK users only I picked an Ordinance Survey example. Sorry - but the OS doesn't map the rest of the world

This may be a little advanced - because it involves conversions from "normal" coordinates to very special ones (Her Majesty has special needs!)

But I hope you get the idea of what is possible and how little code you really need to write:

Here's the sample:
http://www.runsaturday.com/rss/os/os.html?activity=245367

As before, just replace the activity=245367 with the number of the activity you want to see.

e.g.

  • Bala tri - http://www.runsaturday.com/rss/os/os.html?activity=95269
  • Essex action - http://www.runsaturday.com/rss/os/os.html?activity=97427
  • Isle Of Man walking - http://www.runsaturday.com/rss/os/os.html?activity=246367
Web RSS and JSON Examples

The Yahoo! Pipes (above) show the ATOM feeds in use

These demo pages show the JSON feeds consumed from jQuery:

  • http://www.slodge.com/runsatlink
  • http://www.slodge.com/runsattree
  • http://www.slodge.com/runsattime
Uploading Data - PHP
Andread posted this article - http://www.runsaturday.com/Talk/g/posts/t/1076 about uploading from livetrack24.com to runsaturday using PHP.
Consuming RSS - PHP
dra posted this article about how to consume the XML format of the RSS and display it in a blog - http://www.runsaturday.com/Talk/g/posts/t/1162

Uploading From VBA
 
Basically this uploads using the webservice http://www.runsaturday.com/runsaturday/ManualSync.asmx?op=AddSimpleActivity and it needs a reference to the Microsoft XML library to work
 
Sub UploadFromVBA()
    Dim myUserName As String
    myUserName = "PUT YOUR RUNSATURDAY USER NAME HERE"
    Dim myPassword As String
    myPassword = "PUT YOUR PASSWORD HERE"
   
    Dim sportType As String
    sportType = "Run" ' One of "Run", "Swim", "Bike", "Walk", "Water", "Winter", "Skate", "Cross"
   
    Dim sportSubType As String
    sportSubType = "General" ' put your single word tag here
 
    Dim theTitle As String
    theTitle = "My example run" ' title goes here
 
    Dim longNotes As String
    longNotes = "Long description" ' note that you really should XML encode this string!
   
    Dim whenStarted As String
    whenStarted = "2010-02-15T11:21:13.000Z" ' start time here
   
    Dim durationInSeconds As Double
    durationInSeconds = 3412 ' time taken in seconds here
   
    Dim distanceInMetres As Double
    distanceInMetres = 10000 ' distance in metres here
   
    Dim calories As Long
    calories = 520 ' calories here
 
    Dim intensity As Integer
    intensity = 8 ' 0 is unknown, 1->10 is easy->hard
 
    Dim strXML As String
    strXML = "<?xml version=""1.0"" encoding=""utf-8""?>"
    strXML = strXML & "<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">"
    strXML = strXML & "<soap:Header>"
    strXML = strXML & "<UploadTrackCredentials xmlns=""http://www.runsaturday.com/"">"
    strXML = strXML & "<UserName>" & myUserName & "</UserName>"
    strXML = strXML & "<SecretKey>" & myPassword & "</SecretKey>"
    strXML = strXML & "</UploadTrackCredentials>"
    strXML = strXML & "</soap:Header>"
    strXML = strXML & "<soap:Body>"
    strXML = strXML & "<AddSimpleActivity xmlns=""http://www.runsaturday.com/"" >"
    strXML = strXML & "<type>" & sportType & "</type>"
    strXML = strXML & "<subType>" & sportSubType & "</subType>"
    strXML = strXML & "<title>" & theTitle & "</title>"
    strXML = strXML & "<startedAt>" & whenStarted & "</startedAt>"
    strXML = strXML & "<distanceInMetres>" & distanceInMetres & "</distanceInMetres>"
    strXML = strXML & "<durationInSeconds>" & durationInSeconds & "</durationInSeconds>"
    strXML = strXML & "<notes>" & longNotes & "</notes>"
    strXML = strXML & "<calories>" & calories & "</calories>"
    strXML = strXML & "<intensity>" & intensity & "</intensity>"
    strXML = strXML & "</AddSimpleActivity>"
    strXML = strXML & "</soap:Body>"
    strXML = strXML & "</soap:Envelope>"
   
    Dim objHTTP As New MSXML2.XMLHTTP
    objHTTP.Open "post", "http://www.runsaturday.com/runsaturday/ManualSync.asmx"
   
    objHTTP.setRequestHeader "Content-Type", "text/xml; charset=utf-8"
    objHTTP.setRequestHeader "SOAPAction", "http://www.runsaturday.com/AddSimpleActivity"
    objHTTP.send strXML
       
    Dim result As String
    result = objHTTP.responseText
   
    Dim AddSimpleActivityResult As Integer
    AddSimpleActivityResult = InStr(result, "<AddSimpleActivityResult>")
    Dim EndAddSimpleActivityResult As Integer
    EndAddSimpleActivityResult = InStr(result, "</AddSimpleActivityResult>")
   
    If AddSimpleActivityResult = 0 Then
        MsgBox "Failed"
        MsgBox result
        Exit Sub
    End If
    If EndAddSimpleActivityResult = 0 Then
        MsgBox "Failed Weirdly"
        MsgBox result
        Exit Sub
    End If
   
    Dim lenOfTag As Integer
    lenOfTag = Len("<AddSimpleActivityResult>")
   
    Dim activityId As Long
    activityId = CLng(Mid(result, AddSimpleActivityResult + lenOfTag, EndAddSimpleActivityResult - (AddSimpleActivityResult + lenOfTag)))
   
    MsgBox "Activity added at http://www.runsaturday.com/act/" & activityId
End Sub