bancho.py vs. osuBasil

A complete reference for the osu! stable client protocol, comparing bancho.py with Basil's implementation. Scoped to the non-api. hosts (c./ce./c4./c5./c6., osu., b., a.). api. is Basil's own tournament API, with no real bancho.py counterpart, so it's out of scope here. Current as of 2026-08-05.

Same behavior as bancho.py, or an improvement (noted in the cell).

⚠️
Still handled, but the behavior differs from bancho.py's.

Missing, or a stub that returns a hardcoded/empty response.

Bancho Protocol (c./ce./c4./c5./c6.<domain>)

Endpoint Description bancho.py osuBasil
GET / Status page for the bancho host. ✅ An HTML page with online player/match counts and the full list of handled packets. ⚠️ Returns the literal string "cho". Not called by the real osu! client either way.
GET /online List of current online players. ✅ HTML list of online users and bots. ❌ No route.
GET /matches List of ongoing multiplayer matches. ✅ HTML list of active matches. ❌ No route.
POST / Login (no osu-token header) or packet dispatch (with one).
PART_LOBBY / JOIN_LOBBY packets Enter/leave the multiplayer lobby's live match list. ✅ Toggles player.in_lobby; JOIN_LOBBY also sends every active match. ❌ Not handled: both packets are silently skipped.
Every other client packet Login/logout, chat, spectating, multiplayer, channels, friends, tournament client (42 packets in total). ✅ One handler per packet, matching bancho.py's names and behavior.

osu! Web (osu.<domain>)

Endpoint Description bancho.py osuBasil
GET / Health-check stub. ❌ No root route registered. ✅ Redirects to the project's GitHub repository (osuBasil-only addition, not called by the real client).
GET /web/osu-osz2-getscores.php A beatmap's leaderboard. ✅ Real leaderboard, scores and all. ⚠️ Status-only reply (the map's real RankedStatus, no score rows). By design, this server has no online leaderboard, only tournament match reports.
GET /web/osu-search.php / osu-search-set.php Beatmap search / a set's info by any beatmap in it. ✅ Proxies an external mirror API. ✅ Queries the local database. No external mirror dependency, works fully offline.
GET /d/{mapSetId} Download a beatmapset archive. ✅ Built on the fly from local storage instead of a mirror.
GET /web/maps/{mapFilename} A single .osu difficulty file, by filename.
POST /web/osu-submit-modular-selector.php Score submission.
GET /web/osu-getreplay.php Replay download.
POST /web/osu-getbeatmapinfo.php Per-map grade and ranked-status lookup, batched. ✅ Full lookup. ⚠️ Checks the requester is logged in, then returns an empty result.
GET /web/lastfm.php Client-integrity flag reporting.
GET /web/osu-markasread.php Mark an offline message as read. ❌ No-op: this server has no offline mail system.
GET /web/osu-getseasonal.php / GET /seasonal/{fileName} Seasonal background images.
GET /web/bancho_connect.php Client connectivity check on startup. ✅ Empty stub. ✅ Empty stub.
GET /web/check-updates.php Client update check. ✅ Empty stub. ✅ Empty stub.
POST /web/osu-screenshot.php Screenshot upload. ✅ Full upload and validation. ❌ Always rejected with a 400 "not supported" response.
GET /ss/{screenshotId}.{ext} Serve an uploaded screenshot. ❌ No route, consistent with uploads being rejected above.
GET /web/osu-getfavourites.php / osu-addfavourite.php A player's favourited beatmaps. ✅ Real persistence. ❌ Empty stub, nothing is stored.
GET /web/osu-rate.php Rate a beatmap. ✅ Real rating persistence. ❌ Always replies "not ranked".
POST /web/osu-comment.php In-replay comments. ✅ Real comment persistence. ❌ Empty stub.
GET /web/osu-getfriends.php A player's friend list, by id. ❌ No route.
GET /p/doyoureallywanttoaskpeppy Easter-egg DM from peppy. ❌ No route.
POST /users In-game account registration. ✅ Gated by allowed email domains. ✅ Gated by an admin key sent in the email field instead.
POST /difficulty-rating Star rating for a beatmap/mod combination. ⚠️ Redirects to the rating page on osu.ppy.sh rather than computing anything itself. ✅ Computed locally with ppy's own osu!lazer ruleset libraries. No internet dependency.

Beatmap Assets (b.<domain>)

Endpoint Description bancho.py osuBasil
GET /thumb/{setId}l.jpg / {setId}.jpg Beatmapset thumbnail/preview image. ✅ Redirects to b.ppy.sh's real CDN, on the request path as-is. ✅ Resized from local storage and served directly (cached after the first request). No internet dependency, but narrower: any path other than these two 404s locally instead of passing through.

Avatar Files (a.<domain>)

Endpoint Description bancho.py osuBasil
GET /{userId} A player's avatar image. ⚠️ Served by nginx as static files, not by any Python route: present, but at a different layer of the stack than the rest of this table. ✅ An application route with a built-in fallback: BasilBot has its own icon, a generic default avatar for everyone else.