If you've tried to study microstructure on Kalshi, you know the wall: the public API serves trades and candles, not book history. There is no official way to ask "what did the ladder look like at 19:42:31 last Tuesday?" — once a snapshot passes, it's gone. (For a map of the vendors that do record this data — ours and others — see our buyer's guide to historical Polymarket & Kalshi order-book data.)
We've been recording it. Today we're releasing the Kalshi Microstructure Tape: L2 depth and the executed trade tape, together — because depth without prints is a photograph, and prints without depth are footsteps without a floor plan.
What's in it
- 556.7M depth rows covering June 21 – September 6, 2026 in this dated vintage: the ladder to 20 levels per side, polled at measured median global intervals of 30.539 s before July 12 and 43.294 s afterward — across whatever sat in Kalshi's top 150 markets by 24-hour volume each cycle (50 before July 12): MLB, WNBA, ATP/WTA/ITF tennis, UFC, LoL/CS2/Dota2/Valorant, UCL/UEL/MLS/Liga MX soccer, NFL and CFB books, and more. The family mix varies by day; measure it from the ticker column.
- 15.8M trade prints, deduplicated by trade_id, each carrying price,
size, taker side, and a game-state field recorded when our poller
retrieved the print. Retrieval lag was measured on the July 19 launch
vintage, not re-measured on this one. For event-time analysis, join
prints to a score timeline at
created_time(the exchange trade time, on every row);capture_ts − created_timegives per-print lag. - Daily parquet files, a full per-day manifest, measured capture statistics, and a UTC coverage map derived from global poll timestamps — see the limits below for what those measurements do and do not establish.
The honest limits, up front
This is a live capture, and live captures have edges. The trade tape
holds every print family the recorder captured — 15 families (game moneylines,
spread/total and five European soccer families) in the 2026-09-06 vintage
— but it is not a full-exchange tape. MLB print capture went live on
2026-07-10 at 23:04 UTC; the recorder's startup backfill reaches
prints created from July 8, so the July 8–10 trade files hold backfilled
rather than live-captured MLB prints, and before that the tape is WNBA
plus sparse NFL/NCAAF pregame prints. The corrected
CAPTURE_STATS.json derives its family list from the delivered parquet.
The per-print
game-state field is capture-time, not event-time: measured across all
2,039,483 packaged prints of the launch vintage, the poller's retrieval
lag was median 26.3s, p90 87s, p99 53 minutes, with 82,183 prints arriving
more than five minutes late (mostly quiet-hour and restart backfills); later
vintages have not re-measured it — compute it per print from
capture_ts − created_time. Every row carries the
exchange's created_time, which is what event-time analysis should
join on. The depth ladder is capped at 20
levels per side (Kalshi exposes more; we store the top 20). Our capture
host slept through two windows in mid-July, and has been intermittently
dark since August 9. The corrected coverage map derives gaps over 120
seconds from adjacent global poll timestamps in UTC; 150 qualifying gaps
occur August 14–September 6. A global poll says some selected book was
captured, not that every ticker was present or continuously observed.
We list all of this because one overclaim costs more trust than ten disclosures. It's also why we keep capturing and cut refreshed dated vintages: every day of capture is a day nobody else can go back and get.
Start with $9
The tryout contains Jul 18–19 UTC write-day partitions — ~21.5M depth rows and 747K prints across both feeds, using the same data schema but its own manifest and coverage note. A boundary depth poll is timestamped Jul 17 23:59:42 UTC. Neither partition has a global-poll gap over two minutes, but that does not guarantee every ticker was sampled at every poll. Build your pipeline against it; if the data isn't what you need, you found out for $9. A free 400-row sample and the complete schema are on the samples page.
To verify a personalized ZIP, hash its included MANIFEST.json bytes and
compare that digest with this SKU's archive_metadata.source_documents
entry in the public catalog. Only after it matches,
check the sizes and hashes of the files named in that manifest. A buyer ZIP's
whole-file hash changes when its license comment is added.
Research and backtest data, not signals — as with everything we sell.