Export Mi Fit and Zepp workout data

3 minute read

Introduction

The two most popular companion applications for the Mi Smart Band 5 are Mi Fit and Zepp. Both applications support the tracking of different kinds of workouts, however they do not allow the user to export the collected data for further analysis. Due to the General Data Protection Regulation (GDPR) users may download their personal data from both applications, but the resulting archive does not contain workout specific data. The Zepp application also allows the user to export workouts one-by-one in .gpx format, but it does not contain all the available data and it is infeasible to export thousands of workouts manually.

Screenshot of the Mi Fit application Screenshot of the Zepp application

API

Both applications synchronize the workouts to the cloud, which should make it easy to investigate the HTTP requests and responses. My favorite web debugging proxy tool is Telerik’s Fiddler which is able to decrypt HTTPS traffic originating from mobile devices. There is also a good tutorial available which explains how to set up your devices.

Workout history

By analyzing the traffic of the application, it turned out the following endpoint returns the metadata of all workouts:

https://api-mifit-de2.huami.com/v1/sport/run/history.json

It requires the following header:

Key Example value Note
apptoken DQVBQE…WHtrY A user-specific token acquired during login

And the following GET parameters:

Key Example value Note
r 3bb4ea60-86e3-4b26-924a-edbe42895974 A random UUID
t 160… Current timestamp in milliseconds
userid 700… ID of the user
appid 288… ID of the application
callid 1604562850366 Current timestamp in milliseconds
channel “play” Source of the application - Google Play
country “US” Country of the user
cv “100283_5.4.1-play” Version of the application
device “android_29” OS version
device_type “android_phone” Type of the device
from “2020-01-01” Start date of the requested interval
to “2020-12-31” End date of the requested interval
lang “en_US” Language of the application
source “run.mifit.huami.com” Source of the returned data
timezone “Europe/Budapest” Timezone of the user
type “0” Type of the workout - 0: everything
v “2.0 HTTP/1.1” Some version

The response is a list of metadata corresponding to the workouts that were recorded in the requested interval. The format of a workout metadata is as follows (the values were redacted):

{
  "code": 1,
  "message": "success",
  "data": {
    "summary": [
      {
        "trackid": "1234567890",
        "source": "run.mifit.huami.com",
        "dis": "0.0",
        "calorie": "0.0",
        "end_time": "0",
        "run_time": "0",
        "avg_pace": "0.0",
        "avg_frequency": "0.0",
        "avg_heart_rate": "0.0",
        "type": 0,
        "location": "",
        "city": "",
        "forefoot_ratio": "",
        "bind_device": "",
        "max_pace": 0,
        "min_pace": 0,
        "version": 0,
        "altitude_ascend": 0,
        "altitude_descend": 0,
        "total_step": 0,
        "avg_stride_length": 0,
        "max_frequency": 0,
        "max_altitude": 0,
        "min_altitude": 0,
        "lap_distance": 0,
        "sync_to": "",
        "distance_ascend": 0,
        "max_cadence": 0,
        "avg_cadence": 0,
        "landing_time": 0,
        "flight_ratio": 0,
        "climb_dis_descend": 0,
        "climb_dis_ascend_time": 0,
        "climb_dis_descend_time": 0,
        "child_list": "",
        "parent_trackid": 0,
        "max_heart_rate": 0,
        "min_heart_rate": 0,
        "swolf": 0,
        "total_strokes": 0,
        "total_trips": 0,
        "avg_stroke_speed": 0,
        "max_stroke_speed": 0,
        "avg_distance_per_stroke": 0,
        "swim_pool_length": 0,
        "te": 0,
        "swim_style": 0,
        "unit": 0,
        "add_info": "",
        "sport_mode": 0,
        "downhill_num": 0,
        "downhill_max_altitude_desend": 0
      }
    ]
  }
}

Workout detail

For each workout metadata the corresponding detail can be queried by using the following endpoint:

https://api-mifit-de2.huami.com/v1/sport/run/detail.json

It also requires the apptoken header and the above-mentioned GET parameters with an additional identifier:

Key Example value Note
trackid 1234567890 The trackid parameter from the metadata

The response contains the detail of the requested workout, including the location information. The format of a detailed workout is as follows (the values were redacted):

{
  "code": 1,
  "message": "success",
  "data": {
    "trackid": 1234567890,
    "source": "run.mifit.huami.com",
    "longitude_latitude": "0,0;...",
    "altitude": "0;...",
    "accuracy": "0;...",
    "time": "0;...",
    "gait": "0,0,0,0;...",
    "pace": "0.0;...",
    "pause": "",
    "spo2": "",
    "flag": "0;...",
    "kilo_pace": "",
    "mile_pace": "",
    "heart_rate": "0,0;...",
    "version": 0,
    "provider": "",
    "speed": "0,0.0;...",
    "bearing": "",
    "distance": "0,0;...",
    "lap": "",
    "air_pressure_altitude": "",
    "course": "",
    "correct_altitude": "",
    "stroke_speed": "",
    "cadence": "",
    "daily_performance_info": "",
    "rope_skipping_frequency": "",
    "weather_info": "",
    "coaching_segment": ""
  }
}

Scraping

I implemented both endpoints in Python using the requests package. The scraping algorithm is very simple:

history = get_history()

for metadata in history['data']['summary']:
    detail = get_detail(metadata['trackid'], metadata['source'])

    # Write metadata to .json file
    # Write detail to .json file

The resulting .json files can be used for backup and/or data mining purposes.