The best card identification for live streams. Built for breaks, rips and live shows.
cardstream watches your break, rip or show and identifies every trading card the moment it enters the frame — name, set and confidence, live. Analyse your live shopping streams with card tracking system. For streamers that want to know more.
From Pokémon to Magic: The Gathering
Switch category per show and the whole engine follows — detection, gating and the identify call all point at the right endpoint. Every match comes back with name, set, set code, card number, series and year.
Trading card games
collectibles/v2/tcg_id Modern and vintage TCG singles, straight off the stream. The endpoint reads the art, the frame and the text, so a card is identified from the same picture your viewers are looking at — no set symbol hunting, no collector-number squinting.
- Pokémon
- Magic: The Gathering
- Yu-Gi-Oh!
- One Piece
- Lorcana
- Digimon
- Dragon Ball Super
- Flesh and Blood
- Star Wars Unlimited
- Star Wars Destiny
- MetaZoo
- Riftbound
- Weiss Schwarz
- Union Arena
- Force of Will
- Grand Archive
- Vanguard
- Marvel Champions
- Sorcery
- Final Fantasy
- Gundam
- Duel Masters
- Naruto Mythos
- Hololive
- Garbage Pail Kids
Sports cards sport_id
Rookies, parallels, inserts and autos across every major sport — baseball, basketball, football, soccer, hockey and more — the exact card, the exact set, the exact year.
Graded slabs slab_id
Reads the label on a graded case — the card inside a PSA, BGS or CGC slab, identified without cracking it.
Comics comics_id
Covers identified the same way as cards: title, issue and year, from a single settled frame.
Plug in a proprietary recogniser — or your own
Everything that decides whether to call happens before the identification itself: detection, the motion gate and the same-card gate are all local and provider-agnostic. The call itself is one swappable step — Ximilar out of the box, a proprietary card identification service, or a model you trained yourself and host on your own hardware.
It is one small interface: a card crop goes in, a match comes out.
Implement IdentifyTarget and every gate, throttle and
threshold in front of it keeps working exactly as before — still one
crop per distinct card, whoever answers it.
# your own recogniser, same engine class HouseIdentifier(IdentifyTarget): def identify(self, crop_bgr): return my_service.match(crop_bgr) # one crop per distinct card, either way $ cardstream-web --detector rfdetr
One call per card, not per frame
The point is to keep streaming analysis down to the calls that actually tell you something new. The open-source alternative to closed card-recognition SaaS: no platform in the middle, no seat licence — your hardware, your API key, and a state machine that only calls out when the card in frame is genuinely new.
A naive per-frame pipeline at 15 fps fires 54,000 identifications an hour. cardstream fires one per distinct card you show — around a hundred in that same hour.
Same hour, same video, same cards: 54,000 calls against roughly 100. Motion and identity gates run locally on your own hardware — a call only goes out when a genuinely new card settles in frame.
No SaaS subscription, no per-seat pricing, no lock-in. Self-host the whole stack with identification or connect to the Ximilar API.
Everything a streaming card show needs
A co-host that never misses a card — for live commerce sellers on Whatnot- and Fanatics Live-style platforms, box breaks, card shop streams and collection cataloguing. Anywhere a camera meets cardboard.
Known the moment it hits the frame
No scan button. No waiting. Just show the card — name, set and confidence go from cardboard to card name in about half a second, live on stream.
One call per card
A motion gate and an embedding identity gate run locally on your own CPU. Hold a card still — zero repeat calls. Swap cards — exactly one new call.
Any stream source
Webcam, video files, RTSP, RTMP and SRT — pulled, or pushed straight from OBS with --listen. WebSocket JPEG feeds for custom rigs.
Any identification backend
Ximilar collectibles/v2 out of the box — or point the same engine at a proprietary card recogniser, or one you trained and host yourself.
Bring your own models
The locator weights are ours — a finetuned RF-DETR segmentation model, Apache-2.0, fetched by the installer. Box detectors (RF-DETR, RT-DETRv2) are supported too, if you would rather bring your own export.
Open source, self-hosted
One Python package, permissively licensed. Read it, fork it, run it on your own hardware. Your key, your data, your infrastructure.
Smart enough to know when not to call the API
A state machine stands between your stream and the API. Every frame
flows through DecisionCore — one state machine, running
locally — and three local gates decide when the one API step is actually
warranted.
Detect
local · no API callFind the card quadrilateral and deskew a clean crop. Throttled in three tiers by the local motion gate — moving, static-with-card, empty.
Motion gate
local · no API callCheap mean frame-diff. Only when the scene has settled for N frames is the card worth a closer look. Still moving? Wait.
Identity gate
local · no API callAn embedding comparison answers one question: is this the same card as before? Same card → re-emit the cached result.
Identify
ximilar · 1 callOnly a genuinely new, settled card triggers a Ximilar identification — async, debounced, off the frame loop. Result pushed back live.
Are you an individual streamer?
One person, one camera, one long night of breaks — you should not need an engineering team to know what card is on screen. Connect the stream you are already running and let cardstream analyse it live, whether you sell on a marketplace or straight off your own channel.
- Whatnot
- Fanatics Live
- eBay Live
- TikTok Shop
- Twitch
- YouTube Live
- your own site
No account access, no marketplace API keys, no bot in your chat — and no affiliation with any of these platforms. cardstream reads your video, nothing else.
You already stream from OBS
Add one more output next to the one feeding your show. Your buyers see exactly what they saw before — a copy of the same feed lands in cardstream, and every card that hits the table gets identified on the way past. The listener below needs the system ffmpeg binary — or skip the second output entirely and let cardstream read the OBS virtual camera as an ordinary webcam.
$ cardstream-web --listen \ --source rtmp://0.0.0.0:1935/live # point OBS's second target here
Or the camera that is already on the table
Overhead cam, capture card, phone as a webcam — whatever you rip and reveal under. Analysis runs on the machine next to the camera, so nothing but one crop per card ever leaves the room.
$ cardstream-web --source 0 # webcam · browser UI on localhost
Or anything with a URL
Encoders, switchers, restreamers, a second studio across town. RTSP, RTMP and SRT pulls, plus WebSocket JPEG feeds when your rig is homemade.
$ cardstream-web \
--source rtsp://studio/stream1 Live overlay
Name, set and confidence appear the moment a card settles — ready to read out, or to composite back into your scene.
Every card, logged
A running history of everything you showed, timed per appearance. The break notes write themselves.
Sized for one person
No platform fee, no seat licence. A three-hour show is a handful of identification calls, not one per frame.
From zero to live identification in 3 steps
Install it
A virtualenv, the release wheel (checksum-verified), the model weights and both commands on your PATH. Take the script, pip install the same wheel from PyPI (the weights are a separate download), or clone the repo and build it yourself — Docker and Windows are on the download page.
$ curl -fsSL https://raw.githubusercontent.com/Ximilar-com/cardstream/main/scripts/install.sh | sh # other install paths → cardstream.ai/download
$ pip install 'cardstream[client,onnx]' # or: uv tool install 'cardstream[client,onnx]' # the wheel has no weights — unpack the two tarballs from cardstream.ai/models # and point the flags at them: $ cardstream-web --segmentor-model segmentation_model/onnx/model.onnx \ --embed-model similarity_model/onnx/model.onnx
$ git clone https://github.com/Ximilar-com/cardstream && cd cardstream $ ./scripts/build-from-source.sh --models $ source .venv/bin/activate
Connect an identification system
Ximilar collectibles/v2 out of the box — a key from ximilar.com is the only credential the whole system needs. Or point the same step at your own recogniser.
$ export XIMILAR_API_KEY=your-key
Point a camera at a card
Open the browser UI on your webcam, or feed it your show — RTSP pull, or let OBS push RTMP straight into it. Breaking one set all night? Prefill it and the endpoint stops guessing: English Pokémon out of CRI is three fewer things to get wrong. Set --alphabet whenever you set --game — prefilling the game turns the endpoint's own writing-system detection off. Add --price-stats and every match also brings USD market prices: median, range and latest sale, on the card and in the history.
$ cardstream-web # → http://127.0.0.1:8001 — hold up a card # English Pokémon cards, one set (CRI - Chaos Rising), with USD market prices: $ cardstream-web --game Pokemon --set-code CRI --alphabet latin --price-stats
Open source. Self-hosted. Your stream, your stack.
No platform in the middle, no seat licence: connect the Ximilar API or your own identification system, and cardstream calls it once per distinct card instead of once per frame. Whether you're breaking on Whatnot, running a Fanatics Live-style show, or streaming your own live commerce setup, run cardstream tonight on the hardware you already have.