Exposes an API to osu!track that allows data to be queried, users to be updated, and other things.
Anyone is free to use the API for any purpose, but please keep your traffic reasonable.
This API must NOT be used to mass-scrape data from the osu!track database or attempt to serve as a proxy to the official osu! API. If you need bulk osu!track data for a project, get in touch with me at casey@cprimozic.net
It's OK to set up a bot or periodic job to auto-update your own user's stats on osu!track. However, please keep the refresh interval reasonable. Any auto-update rate more frequent than once ever 15 minutes (even though rate limits allow higher than this) may result in your IP getting temporarily blocked.
If you've got a question about a particular use-case or need data or functionality that this API doesn't provide, you can join the osu!track developers Discord: https://discord.gg/gjzBzCVFmy Feel free to @ me there (@ameo) and I'll answer any questions you have or help out if I can.
If you encounter any bugs or issues with the API, let me know as well!
There is some rate-limiting on this API. The limits are applied per IP address and are pretty generous.
There are two classes for rate limits:
The request count is shared for all endpoints of the same class.
If a rate limit is exceeded, the API will return a HTTP 429 error and a Retry-After header indicating how long you must wait before making another request.
The API is reachable at: https://osutrack-api.ameo.dev/
POST https://osutrack-api.ameo.dev/update?user={user}&mode={mode}
Rate limit class: Update (5 requests/minute)
user is the user ID of the user you'd like to updatemode is the gamemode you'd like to update; 0=osu!, 1=taiko, 2=ctb, 3=maniaThis endpoint will return the difference in stats since the last update if successful:
{
"username":"ameo",
"mode":0,
"playcount":0,
"pp_rank":0,
"pp_raw":0,
"accuracy":0,
"total_score":0,
"ranked_score":0,
"count300":0,
"count50":0,
"count100":0,
"level":0,
"count_rank_a":0,
"count_rank_s":0,
"count_rank_ss":0,
"levelup":false, // whether or not the user leveled up since the last update
"first":false, // whether this is the first update for the user, meaning that there was no previous update to compare to
"exists":true, // whether the user exists or not; if this is false, check the user ID you provided
// an array of new hiscores for the user
"newhs": [
{
"beatmap_id":"33394",
"score_id":"85808923",
"score":"5720257",
"maxcombo":"494",
"count50":"0",
"count100":"9",
"count300":"350",
"countmiss":"0",
"countkatu":"8",
"countgeki":"45",
"perfect":"1",
"enabled_mods":"8",
"user_id":"131464",
"date":"2010-04-22 08:25:22",
"rank":"SH",
"pp":"82.9195",
"replay_available":"0",
"ranking":0
}
]
}
GET https://osutrack-api.ameo.dev/stats_history?user={user}&mode={mode}&from={from}&to={to}
Rate limit class: Database (600 requests/minute)
user is the user ID of the user for which to retrieve updatesmode is the gamemode you'd like to retrieve updates for; 0=osu!, 1=taiko, 2=ctb, 3=maniafrom is optional, but if provided it is the start date of updates you'd like to retrieve in the format YYYY-MM-DD like 2020-01-01to is optional, but if provided it is the end date of updates you'd like to retrieve in the format YYYY-MM-DD like 2021-01-01If successful, returns an array of updates for the user in the selected mode like this:
[
{
"count300":3788588,
"count100":387592,
"count50":42411,
"playcount":23428,
"ranked_score":"4306096061",
"total_score":"19326454144",
"pp_rank":79461,
"level":99.1757,
"pp_raw":4006.24,
"accuracy":98.70355224609375,
"count_rank_ss":31,
"count_rank_s":408,
"count_rank_a":568,
"timestamp":"2021-02-04T23:24:42.000Z",
}
]
GET https://osutrack-api.ameo.dev/hiscores?user={user}&mode={mode}&from={from}&to={to}&userMode={userMode}
Rate limit class: Update (5 requests/minute)
user is the ID (default) or username of the user for which to return hiscores. See userMode for detailsmode is the gamemode you'd like to fetch hiscores for; 0=osu!, 1=taiko, 2=ctb, 3=maniafrom is optional, but if provided it is the start date of hiscores you'd like to retrieve in the format YYYY-MM-DD like 2020-01-01to is optional, but if provided it is the end date of hiscores you'd like to retrieve in the format YYYY-MM-DD like 2021-01-01userMode is optional can be one of either id or username. It defaults to id. It determines if user is interpreted as an ID or as a username.If successful, returns an array of all recorded hiscores for the user in the selected mode like this:
[
{
"beatmap_id":637549,
"score":2423423,
"pp":193.099,
"mods":584, // Same format as osu! API: https://github.com/ppy/osu-api/wiki#mods
"rank":"SH",
"score_time":"2019-05-12T06:30:16.000Z", // Timestamp of when the play took place
"update_time":"2019-05-12T06:30:40.000Z" // Timestamp of when osu!track recorded the play
}
]
GET https://osutrack-api.ameo.dev/peak?user={user}&mode={mode}
Rate limit class: Database (600 requests/minute)
user is the user ID of the user you'd like to get data formode is the gamemode you'd like to get data for; 0=osu!, 1=taiko, 2=ctb, 3=maniaIf successful, returns the best (lowest) global rank and accuracy for the user along with the timestamps at which they were at their best values:
[{
"best_global_rank": 7381,
"best_rank_timestamp": "2015-04-24T12:44:15.000Z",
"best_accuracy": 99.46027374267578,
"best_acc_timestamp": "2024-03-14T01:06:02.000Z"
}]
If user not found or no updates exist for the user, returns:
[{
"best_global_rank": null,
"best_rank_timestamp": null,
"best_accuracy": null,
"best_acc_timestamp": null
}]
GET https://osutrack-api.ameo.dev/bestplays?mode={mode}&from={from}&to={to}&limit={limit}
Rate limit class: Database (600 requests/minute)
mode is the gamemode you'd like to retrieve best plays for; 0=osu!, 1=taiko, 2=ctb, 3=maniafrom is optional, but if provided it is the start date of scores you'd like to retrieve in the format YYYY-MM-DD like 2020-01-01to is optional, but if provided it is the end date of scores you'd like to retrieve in the format YYYY-MM-DD like 2021-01-01limit is how many scores you want to return, an optional number from 1 to 10000. Scores are returned in descending order by pp value. {
"user": 6447454,
"beatmap_id": 111680,
"score": 25571304,
"pp": 1144.15,
"mods": 88,
"rank": "A",
"score_time": "2021-01-07T11:16:59.000Z",
"update_time": "2021-01-16T14:59:17.000Z"
},
{
"user": 6447454,
"beatmap_id": 1842043,
"score": 63633373,
"pp": 1092.05,
"mods": 72,
"rank": "SH",
"score_time": "2021-01-12T07:25:34.000Z",
"update_time": "2021-01-16T14:59:17.000Z"
}
]
GET https://osutrack-api.ameo.dev/matchmaking_history?user={user}&mode={mode}&pool_id={pool_id}&from={from}&to={to}
Rate limit class: Database (600 requests/minute)
user is the user ID of the user for which to retrieve matchmaking snapshotsmode is the gamemode you'd like to retrieve snapshots for; 0=osu!, 1=taiko, 2=ctb, 3=maniapool_id is optional. If provided, only rows for that pool are returned. If omitted, snapshots for every pool the user has played in the given mode are returned. Pool IDs can be discovered via /matchmaking_pools.from is optional, but if provided it is the start date of snapshots you'd like to retrieve in the format YYYY-MM-DD like 2026-01-01to is optional, but if provided it is the end date of snapshots you'd like to retrieve in the format YYYY-MM-DD like 2027-01-01Snapshots are recorded any time a user is updated (e.g. by visiting their osu!track page or hitting /update). Identical consecutive snapshots are deduplicated, so the row count reflects when stats actually changed rather than when the user was checked.
If successful, returns an array of matchmaking snapshots in ascending timestamp order:
[
{
"pool_id": 38,
"rating": 1914,
"rank": 498,
"plays": 7,
"first_placements": 0,
"total_points": 0,
"is_rating_provisional": 0,
"timestamp": "2026-04-19T06:18:37.000Z"
}
]
rating is the player's current Elo-equivalent rating in the poolrank is the player's rank within the poolplays is the number of matches the player has completed in the poolfirst_placements is the number of times the player finished first in the pooltotal_points is the player's accumulated points in the poolis_rating_provisional is 1 while the rating is still considered provisional (typically while plays is below the pool's threshold), 0 otherwiseGET https://osutrack-api.ameo.dev/matchmaking_pools
Rate limit class: Database (600 requests/minute)
Returns the list of every matchmaking pool osu!track has observed at least once. Pools rotate over time (e.g. weekly Quick Play seasons), so historical pools are kept around for charting older snapshots.
[
{
"id": 1,
"name": "osu!",
"ruleset_id": 0,
"variant_id": 0,
"active": 0,
"last_seen": "2026-04-19T06:54:58.000Z"
},
{
"id": 11,
"name": "1v1 (Week 1)",
"ruleset_id": 0,
"variant_id": 0,
"active": 0,
"last_seen": "2026-04-19T06:54:53.000Z"
}
]
ruleset_id is the gamemode the pool is for; 0=osu!, 1=taiko, 2=ctb, 3=maniavariant_id distinguishes pool variants for rulesets that have them (e.g. mania 4k vs 7k); may be 0 if not applicableactive is 1 if the pool is currently accepting matches, 0 otherwiselast_seen is the most recent time osu!track observed any user holding stats in this pool$ claude mcp add osutrack-api \
-- python -m otcore.mcp_server <graph>