606 words
3 minutes
Export Mi Fit and Zepp workout data

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.

application-screenshot-1 application-screenshot-2

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.

Application token#

The endpoints of the API require a user context for which an authorization token is needed. There are at least two ways to extract the token, for which you will need to log in to the application first.

If you have root access on your Android device, you can find the token at /data/data/com.xiaomi.hm.health/shared_prefs/hm_id_sdk_android.xml (Mi Fit) or /data/data/com.huami.watch.hmwatchmanager/shared_prefs/hm_id_sdk_android.xml (Zepp). These files can be accessed via a file manager, or via ADB shell (Android 11+).

If you do not have root access, you can use Fiddler or HTTP Toolkit to analyze the requests sent by the application, which contain the exact same apptoken header, which is required by the endpoints discussed below.

fiddler-header

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:

KeyExample value
apptokenDQVBQE…WHtrY

And the following GET parameter:

KeyExample value
source”run.mifit.huami.com”

In Python:

def get_history():
    r = requests.get('https://api-mifit-de2.huami.com/v1/sport/run/history.json', headers={
        'apptoken': token
    }, params={
        'source': 'run.mifit.huami.com',
    })
    r.raise_for_status()

    return r.json()

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 parameter with an additional identifier:

KeyExample value
trackid123456789

In Python:

def get_detail(track_id, source):
    r = requests.get('https://api-mifit-de2.huami.com/v1/sport/run/detail.json', headers={
        'apptoken': token
    }, params={
        'trackid': track_id,
        'source': source,
    })
    r.raise_for_status()

    return r.json()

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": ""
  }
}

Summary#

An example Python implementation can be found on GitHub:

rolandsz
/
Mi-Fit-and-Zepp-workout-exporter
Waiting for api.github.com...
00K
0K
0K
Waiting...