Skip to content

Instantly share code, notes, and snippets.

@niw
Last active November 7, 2023 16:19
Show Gist options
  • Save niw/858c1ecaef89858893681e46db63db66 to your computer and use it in GitHub Desktop.
Save niw/858c1ecaef89858893681e46db63db66 to your computer and use it in GitHub Desktop.
A simple NikePlus API description to fetch past run metrics
#!/usr/bin/env bash
# fetch_nike_puls_all_activities.bash
# A simple bash script to fetch all activities and metrics from NikePlus.
# See `nike_plus_api.md` for the API details.
readonly bearer_token="$1"
if [[ -z "$bearer_token" ]]; then
echo "Usage: $0 bearer_token"
exit
fi
if ! type jq >/dev/null 2>&1; then
echo "Missing jq, please install it. e.g. brew install jq" >&2
exit 1
fi
nike_plus_api() {
curl -H "Authorization: Bearer ${bearer_token}" "$@"
}
activity_ids=()
activities_page=0
while true; do
activities_file="activities-${activities_page}.json"
if [[ -z "$after_id" ]]; then
url="https://api.nike.com/sport/v3/me/activities/after_time/0"
else
url="https://api.nike.com/sport/v3/me/activities/after_id/${after_id}"
fi
echo "Fetch $url..."
nike_plus_api "$url" > "$activities_file"
activity_ids=("${activity_ids[@]}" $(jq -r ".activities[].id" "$activities_file"))
after_id=$(jq -r ".paging.after_id" "$activities_file")
if [[ "$after_id" == "null" ]]; then
break
else
activities_page=$((activities_page + 1));
fi
done
for activity_id in ${activity_ids[@]}; do
activity_file="activity-${activity_id}.json"
url="https://api.nike.com/sport/v3/me/activity/${activity_id}?metrics=ALL"
echo "Fetch $url..."
nike_plus_api "$url" > "$activity_file"
done

NikePlus API

NikePlus hosted many my past run metrics however, they don't provide a way to export them for the customers and yet their API seems open to their partner which sounds kind of evil.

Anyways, because of that, there is definitely a simple HTTP/JSON API and we can fetch all metrics from their website.

To acquire the access, the API is using OAuth 2.0, thus need to get an access token, which is not easy by using normal OAuth authorization steps because we can't create client ID for their API. However, nike.com and their website itself is using same API and it's really easy to get own access token from the response.

Open https://www.nike.com/us/en_us/p/myactivity and login, then see developer console. Unfortunately, Nike discontinues viewing activities on the web. To get bearer token, run Charles Proxy on iPhone with SSL proxy enabling, then see the access to api.nike.com. There are bunch of requests made to api.nike.com and find the one has Authorization header with Bearer token. It seems like Base64 JSON data includes session tokens with digest.

If we can get this Bearer token, then we can call their API to fetch all metrics.

API Endpoints

There are bunch of API endpoints to access historical metrics however, there are only two API endpoints which we need to fetch past run metrics.

/sport/v3/me/activities/after_time/${time}

Use this endpoint first to start fetching activities, by giving 0 as a time. time is an integer value of UNIX epoc milliseconds.

Request

$ curl -v -H "Authorization: Bearer ${bearer_token}" 'https://api.nike.com/sport/v3/me/activities/after_time/0'

Response

{
  "activities": [
    {
      id: "${activity_uuid}"
    },
    ...
  ],
  "paging": {
    "after_time": ${after_time},
    "after_id": "${after_activity_uuid}"
  }
}

This API response returns limited amount of latest activities from the given time. Thus, we might need to paginate to get older activities. In that case, you might see after_id key in paging.

/sport/v3/me/activities/after_id/${before_activity_uuid}

Use this endpoint to fetch another list activities to reach beginning. If paging has only before_id key, then it is last page.

/sport/v3/me/activity/${activity_uuid}?metrics=ALL

To get GPS locations, heart rates and detailed activity metrics, use this API endpoint with activity_uuid, that we can get by sport/v3/me/activities/ endpoint. Give metrics=ALL to get all details of the activity metrics.

Request

$ curl -v -H "Authorization: Bearer ${bearer_token}" 'https://api.nike.com/sport/v3/me/activity/${activity_uuid}?metrics=ALL'

Response

{
  "id": "${activity_uuid}",
  "type": "run",
  ...
  "summaries": [
    {
      "metric": "distance",
      ...
    },
    ...
  ],
  ...
  "metric_types": [
    "distance",
    "rpe",
    "pace",
    "latitude",
    "heart_rate",
    "calories",
    "nikefuel",
    "speed",
    "longitude"
  ],
  "metrics": [
    {
      "type": "distance",
      "unit": "KM",
      ...
      "values": [
        {
          ...
        },
        ...
      ]
    },
    ...
  ],
  "moments": [
    ...
  ]
}

Here, metrics contains all detailed metrics of distance, latitude and longitude etc.

@LukasM937
Copy link

those the bearer_token passed to the bash skript has to contain "bearer" or just the alphanumerial code afterwards?

Do you know how the token is generated? I want to know the method

Sadly I didn’t
I would guess it’s a sha 256 value from
The ID and some extra salt.
You could try it out with an online Tool to generate the tooken. Until you get your token.
I used Proxyman to receive mine

@youngToMaturity
Copy link

thanks a lot!

@kmcelwee
Copy link

kmcelwee commented Apr 7, 2022

@niw I encountered a small bug in your documentation that tripped me up for a few minutes:

curl -v -H 'Authorization: Bearer ${bearer_token}'

Should use double quotes, otherwise the string won't interpolate and you'll get an Unauthorized user access error. But also thank you! this was perfect.

@niw
Copy link
Author

niw commented Apr 7, 2022

@kmcelwee fixed.

@andrew-behrend
Copy link

Has anyone tried to create a guided run - with intervals - using the nrc API?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment