6

I am well able to download my GPX file of an activity when logged in to Strava and calling this link: https://www.strava.com/activities/5656012590/export_original I get the original gpx. It looks as I need it.

Is there a v3 api way? I would like to access it with the swagger generated code, a la

new ActivitiesApi(getApiClientWithToken(token)).getLoggedInAthleteActivities(System.currentTimeSeconds().toInteger(), 0, 1, 30)

(Groovy code, this works for getting activities)

The only thing I found is https://www.strava.com/api/v3/routes/{id}/export_gpx. But from what I see in the Api response of activities, there is no route attached to it. In activities I can see an 'externalId' which is set to something like '123456123.gpx' and I can see the polylines from the map. But converting polylines sounds like too much effort now and I guess it misses some points. Accessing the externalID, I have no idea.

In the end I don't really care how to get the GPX. If it is a cURL call with passing the token via post and then downloading it, would be fine, as well as getting it with the Java API from swagger. I would prefer the latter option though.

Matthias
  • 1,200
  • 2
  • 13
  • 33
  • well. In the end there seems to be no way. What I did is getting the activity stream and creating my own GPX out of it. It might have a lower resolution than the original file, but for my use case this is ok. – Matthias Jul 27 '21 at 12:57

2 Answers2

5

Just adding this here in case it is useful. The Strava API also has the ability to download data streams (see here API Documentation). I believe this gives slightly more info such as private activities and GPX points within privacy zones etc. assuming the API scope is set to read_all.

I was using the API with Python but I assume it works basically identically in Java. Also note I am just doing this as a hobby so there is likely a more efficient way to do the following...

Example on creating gpx file available here

The code below should download data streams from the Strava API and then generate a GPX file from these data streams.

import requests as r
import pandas as pd
import json
import gpxpy.gpx
from datetime import datetime, timedelta

#This info is in activity summary downloaded from API
id = 12345678 #activity ID
start_time = '2022-01-01T12:04:10Z' #activity start_time_local

#get access token for API
with open('config/strava_tokens.json') as f:
    strava_tokens = json.load(f)
access_token = strava_tokens['access_token']

# Make API call
url = f"https://www.strava.com/api/v3/activities/{id}/streams"
header = {'Authorization': 'Bearer ' + access_token}
latlong = r.get(url, headers=header, params={'keys':['latlng']}).json()[0]['data']
time_list = r.get(url, headers=header, params={'keys':['time']}).json()[1]['data']
altitude = r.get(url, headers=header, params={'keys':['altitude']}).json()[1]['data']

# Create dataframe to store data 'neatly'
data = pd.DataFrame([*latlong], columns=['lat','long'])
data['altitude'] = altitude
start = datetime.strptime(start_time, "%Y-%m-%dT%H:%M:%SZ")
data['time'] = [(start+timedelta(seconds=t)) for t in time_list]

gpx = gpxpy.gpx.GPX()
# Create first track in our GPX:
gpx_track = gpxpy.gpx.GPXTrack()
gpx.tracks.append(gpx_track)
# Create first segment in our GPX track:
gpx_segment = gpxpy.gpx.GPXTrackSegment()
gpx_track.segments.append(gpx_segment)
# Create points:
for idx in data.index:
    gpx_segment.points.append(gpxpy.gpx.GPXTrackPoint(
                data.loc[idx, 'lat'],
                data.loc[idx, 'long'],
                elevation=data.loc[idx, 'altitude'],
                time=data.loc[idx, 'time']
    ))
# Write data to gpx file
with open('output.gpx', 'w') as f:
    f.write(gpx.to_xml())

I've just added a python code to GitHub that should hopefully download all a users GPX files from Strava.

Dan
  • 103
  • 1
  • 8
2

Closest I could get is using the streams API as described in other posts.

        StreamSet streamSet = streamsApi.getActivityStreams(activityId as long, ['latlng', 'altitude', 'time'], true)

        def altitudes = streamSet.getAltitude().getData()
        def latLong = streamSet.getLatlng().getData()
        def times = streamSet.getTime().getData()

        ArrayList<StreamData> data = []
        for (int i = 0; i < times.size(); i++) {
            StreamData streamData = new StreamData()
            streamData.id = activityId as long
            streamData.time = times[i]
            streamData.startTime = startTime
            streamData.altitude = altitudes[i]
            streamData.latitude = latLong[i][0]
            streamData.longitude = latLong[i][1]
            data << streamData
        }

and then building my own GPX file from it:

    def stringWriter = new StringWriter()
    def gpxBuilder = new MarkupBuilder(stringWriter)

    gpxBuilder.mkp.xmlDeclaration(version: "1.0", encoding: "utf-8")
    gpxBuilder.gpx() {
        metadata() {
            time(startTime)
        }
        trk() {
            name(NEW_ACTIVITY_NAME)
            type(convertedType)
            trkseg() {
                for (def item : streamData) {
                    trkpt(lat: item.latitude, lon: item.longitude) {
                        ele(item.altitude)
                        time(UtcTimeString)
                    }
                }
            }
        }
    }

    stringWriter.toString()

Uploading this to Strava works well.

Matthias
  • 1,200
  • 2
  • 13
  • 33