By BluffKing · · Updated
Protobuf at the Poker Table
A September 2026 protocol comparison cut payload about 46% at 100 tables. Separate that historical result from today’s delta and compressed transport.
The earlier compact-JSON pass had already dropped defaults and repeated fields. What remained were the public events every action sends to all nine players at a table, still carrying field names and JSON structure each time. In September 2026 we had H5 negotiate protobuf-v1 and moved only four high-frequency public events to binary: actor_deadline, action_applied, pot_updated and street_revealed. Snapshots, hole cards and other control messages stayed on the existing JSON path with its privacy projection, REST was unchanged, and no generic compression was enabled.
A comparison on the production build at 100 tables and 900 connections (same server binary, only the negotiated protocol changed) cut WS downstream payload from about 1.73 MB/s to 0.93 MB/s and bytes per completed action from 4,181 to 2,254, about 46% less; 100-table reruns the same day gave 45.8%–46.3%, and all 240,000 REST requests across five rerun rounds succeeded. Both protocols still completed about 414 actions per second, and client end-to-end latency did not improve (the load generator shared the two-core host with the server), so this is 46% fewer bytes, not 46% more throughput or players. The figures count application payload only, without WebSocket framing, TCP or TLS.
Decoding binary is not the same as restoring correct state: seat 0 is a real seat, and a null min_raise_to differs from 0. The schema uses optional to keep missing values distinct, H5 rebuilds the existing message structures, and a 64-bit chip value outside JavaScript’s safe-integer range rejects the frame instead of being silently rounded. The cost is a schema, generated code and a decoding adapter, and capture and load tools must read binary too, or they report falsely low traffic.
The lesson is to check the share before estimating the gain: the four events were about 52.2% of payload in the JSON run and shrank about 85.6%, and 52.2% × 85.6% ≈ 44.7%, close to the measured 46%; quoting the ratio for the smallest message alone overstates the real saving. This was a historical experiment. Today’s transport uses delta envelopes with dictionary DEFLATE, public events always use Protobuf, and the connection URL no longer carries a wire parameter, so these percentages do not apply to it; the current code lives in server/src/ws_codec.rs, protocol/realtime.proto and client-game/src/services/wsCodec.ts.