Skip to main content

HYROX race data client – retrieve full race results via Python

Project description

pyrox-client

Unofficial Python client for HYROX race results — load public results into pandas DataFrames.

Unit Tests Integration Tests

Docs PyPI - Version Wheel Downloads

Load HYROX race results into pandas in a few lines. Built for people who love fitness and data.

Unofficial Python client for HYROX race results — load public results into pandas DataFrames in a few lines. Built for people who love fitness and data: analyse performance trends, understand HYROX’s unique demands, and open up new research avenues.

Documentation

Install

uv pip install pyrox-client

or

pip install pyrox-client

Quickstart

Below we have added two quick examples. One of loading race data - with different data requests, and one of retrieving race data / extracting athlete information and plotting values with example outputs to show a small glimpse of the analysis possible if retrieving the race data.

import pyrox

# Create client
client = pyrox.PyroxClient()

# Discover available races
all_races = client.list_races()          
s6_races = client.list_races(season=6)   

# Get multiple races from a season
subset_s6 = client.get_season(season=6, locations=["london", "hamburg"])

# Get single race df
london_race = client.get_race(season=6, location="london")
rott_race = client.get_race(season=6, location="rotterdam")
london_male = client.get_race(season=6, location="london", gender="male")
# Filter athletes finishing under an hour (times parsed to minutes)
london_sub60 = client.get_race(season=6, location="london", total_time=60)
# Open interval: keep athletes with 50 < total_time < 60 minutes
london_50_60 = client.get_race(season=6, location="london", total_time=(50, 60))
#  Returning data for May (London Olympia race)
london_2025_s7 = client.get_race(season=7, location="london", year=2025)
#  Returning data for November (London Excel Race)
london_2024_s7 = client.get_race(season=7, location="london", year=2024)

What's included?

  • Servers publicly available race results from the offical results website
  • Historical coverage of Season 2-7 (for now) (season 5 and 6 are most used/tested in analysis; please open issues for any data problems spotted)
  • Client-side caching by default (local). Set use_cache=False when querying get_race() or get_season() to opt out.
  • Read-only CDN data source – the client always fetches from the public Pyrox CloudFront bucket (no bucket configuration required or supported).
  • Client-side helpers for gender, division, and total finish time filtering (single threshold or open interval)

API

list_races(season: int | None = None) -> pd.DataFrame
  • returns a Dataframe of available races
from pyrox import PyroxClient

client = PyroxClient()
print(client.list_races(season=5).head(3))
#    season   location
# 0       5  amsterdam
# 1       5    anaheim
# 2       5  barcelona
get_race(
    season: int,
    location: str,
    year: int | None = None,
    gender: str | None = None,      # "male" | "female" | "mixed"
    division: str | None = None,    # "open" | "pro" | "pro_doubles" (case-insensitive contains)
    total_time: float | tuple[float | None, float | None] | None = None,
    use_cache: bool = True,
) -> pd.DataFrame
  • returns a single race as a pandas dataframe - with optional filtering. total_time operates on minutes after parsing (e.g. total_time=60 keeps athletes under an hour, total_time=(50, 60) keeps athletes between 50 and 60 minutes exclusive; use None for an open bound).
get_season(
    season: int,
    locations: list[str] | None = None,
    use_cache: bool = True,
) -> pd.DataFrame
  • returns a combinded Dataframe for a whole season (or a set of locations passed in)
get_athlete_in_race(
    season: int,
    location: str,
    athlete_name: str,
    year: Optional[int] = None,
    gender: Optional[str] = None,
    division: Optional[str] = None,
    use_cache: bool = True,
)
  • returns a pd Dataframe filtered down to the matching athlete
  • matching is case-insensitive
  • if more than one row matches, all rows are returned
  • names are in the format shown on 'results.hyrox' i.e. (LastName, FirstName)
df = client.get_athlete_in_race(
    season=7,
    location="London",
    year=2023,
    gender="male",
    division="open",
    athlete_name="LastName, FirstName",
)
clear_cache(pattern: str = "*") -> None
  • clears local cache entries (regex pattern search option included)
cache_info() -> dict
  • returns cache statistics: {"total_size": int, "total_items": int, "items": list[str]}

Example - compare an athlete's two races vs field averages

below code requires pandas and numpy and the graphs are generated via matplotlib and seaborn

import pandas as pd
import numpy as np
import pyrox

client = pyrox.PyroxClient()

run_cols = [f"run{i}_time" for i in range(1, 8+1)]
station_cols = [
    "skiErg_time","sledPush_time","sledPull_time","burpeeBroadJump_time",
    "rowErg_time","farmersCarry_time","sandbagLunges_time","wallBalls_time",
]
station_labels = ["SkiErg","Sled Push","Sled Pull","BBJ","Row","Farmers","Lunges","Wall Balls"]

def pick_athlete_row(df: pd.DataFrame, athlete: str) -> pd.Series:
    m = df["name"].astype(str).str.contains(athlete, case=False, na=False)
    sub = df[m]
    if sub.empty:
        raise ValueError(f"Athlete '{athlete}' not found")
    return sub.iloc[0]

rot = client.get_race(season=6, location="rotterdam", gender="male", division="open")
bcn = client.get_race(season=7, location="barcelona", gender="male", division="open")

athlete = "surname, name"
user_rot = pick_athlete_row(rot, athlete)
user_bcn = pick_athlete_row(bcn, athlete)

rot_run_avg = rot[run_cols].mean()
bcn_run_avg = bcn[run_cols].mean()
rot_sta_avg = rot[station_cols].mean()
bcn_sta_avg = bcn[station_cols].mean()

runs_cmp = pd.DataFrame({
    "segment": range(1, 9),
    "Rotterdam (athlete)": [user_rot[c] for c in run_cols],
    "Barcelona (athlete)": [user_bcn[c] for c in run_cols],
}).set_index("segment")

stations_cmp = pd.DataFrame({
    "station": station_labels,
    "Rotterdam (athlete)": [user_rot.get(c, np.nan) for c in station_cols],
    "Barcelona (athlete)": [user_bcn.get(c, np.nan) for c in station_cols],
}).set_index("station")

Output

Disclaimer

Pyrox is an independent project and is not affiliated with, endorsed or sponsored by the official Hyrox business and event organisers. Hyrox and related marks are trademarks of their respective owners; and they are used here only for descriptive purposes.

Client-side caching is user controlled via the use_cache flag shown above.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyrox_client-0.2.3.tar.gz (277.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyrox_client-0.2.3-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

Details for the file pyrox_client-0.2.3.tar.gz.

File metadata

  • Download URL: pyrox_client-0.2.3.tar.gz
  • Upload date:
  • Size: 277.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyrox_client-0.2.3.tar.gz
Algorithm Hash digest
SHA256 be34280c0c2d8c552bd42239daee2d997695e1a14546b254a835e43f11a71a7c
MD5 868e62ea516f50d42450bed35ba8c224
BLAKE2b-256 91ecc7accc5682193f4d6ef1b5a96b39aa9eb9d79ed6db2953a5d6aef8b508ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrox_client-0.2.3.tar.gz:

Publisher: release.yml on vmatei2/pyrox-client

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyrox_client-0.2.3-py3-none-any.whl.

File metadata

  • Download URL: pyrox_client-0.2.3-py3-none-any.whl
  • Upload date:
  • Size: 11.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyrox_client-0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 0bfcd17280be0f69f90422e377e5cbfc64c80596927c3f8f52c70889f87234c1
MD5 6079eb555475bc89d1ac1799ea452e41
BLAKE2b-256 e1217c8845af7184c3c62ac0937e8e9c72fbd0b7e50548af80b6baf24d07e135

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrox_client-0.2.3-py3-none-any.whl:

Publisher: release.yml on vmatei2/pyrox-client

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page