Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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.

@tomch3ng

This comment has been minimized.

Copy link

@tomch3ng tomch3ng commented Sep 18, 2018

@niw I've identified a new way to get the Bearer token through the browser (at least until Nike changes it again): Open https://www.nike.com/us/en_us/e/nike-plus-membership and login. Open the developer console and look for a request made to https://unite.nike.com/getUser. There should be an Authorization request header with Bearer token.

@Laszlo-Lazuer

This comment has been minimized.

Copy link

@Laszlo-Lazuer Laszlo-Lazuer commented Jul 30, 2019

Thanks!

@yasoob

This comment has been minimized.

Copy link

@yasoob yasoob commented Dec 16, 2019

Wrote an article detailing how to use this and how to get authorization token :) https://yasoob.me/posts/nike-run-club-data-visualization/

@niw

This comment has been minimized.

Copy link
Owner Author

@niw niw commented Dec 16, 2019

@yasoob Nice summary!

@jvmaia

This comment has been minimized.

Copy link

@jvmaia jvmaia commented Feb 9, 2020

@yasoob good job, ty!

@nareshsinghal

This comment has been minimized.

Copy link

@nareshsinghal nareshsinghal commented May 15, 2020

Is there a way to get the Nike Training Club activities (workouts) as well? I followed the steps but was only able to download the Nike Run activities.

@Maverick133t

This comment has been minimized.

Copy link

@Maverick133t Maverick133t commented May 24, 2020

Hi all,

@yasoob - thanks for the post, got me close but not all the way.

Wondering if any one has gotten a "bad substitution error" when running the bash script in the terminal?

I have jq installed.

Thanks,

M

*Update - spelling of Me as opposed to my

@butnaruandrei

This comment has been minimized.

Copy link

@butnaruandrei butnaruandrei commented Jun 12, 2020

@niw I've identified a new way to get the Bearer token through the browser (at least until Nike changes it again): Open https://www.nike.com/us/en_us/e/nike-plus-membership and login. Open the developer console and look for a request made to https://unite.nike.com/getUser. There should be an Authorization request header with Bearer token.

This still works, thanks!

@yasoob

This comment has been minimized.

Copy link

@yasoob yasoob commented Jul 5, 2020

Hi everyone! For those of you who are looking at this right now, I just wrote a script to extract data from Nike Run Club and convert it into GPX format. I used it to import my NRC data to Strava. You are more than welcome to take a look and offer suggestions. It is still rough but works for my use-cases.

You can find the project here: https://github.com/yasoob/nrc-exporter

@TomasHubelbauer

This comment has been minimized.

Copy link

@TomasHubelbauer TomasHubelbauer commented Aug 15, 2020

@yasoob I tried to obtain the bearer token by running Charles and enabling SSL proxying for api.nike,com, but Charles only shows CONNECT requests for that domain and there is a spinner shown which spins indefinitely after the list of my runs in the NRC app. I think that is because the runs it is able to show are fetched from local cache and there is a request to fetch more in case the cache doesn't have them all which never finishes because Charles interferes with the application which probably started using certificate pinning which might be why I am not able to see the bearer token in Charles.

Do you think this is possible or are you still able to obtain the bearer token just fine?

Edit: Shit, I only now read the comment by @butnaruandrei which mentions how to get the token on web. But I think the endpoint name was changed to https://api.nike.com/identity/user/v1/{guid}/read. This request seems to have the Authorization header.

@zodman

This comment has been minimized.

Copy link

@zodman zodman commented Oct 19, 2020

it still working today :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.