Analyse your Whatnot or Fanatics Live stream
cardstream never logs in to Whatnot, Fanatics Live or any other marketplace. It watches the same video you are already sending them, on your own machine, and names every card that hits the table. Here is the whole path, from nothing to a live overlay — about fifteen minutes, once.
A computer near the camera
macOS, Linux or Windows. If you already run OBS on it, that machine is the right one — analysis happens locally, so nothing has to travel.
The video you already send
An OBS scene, a webcam, a capture card or an encoder. cardstream taps what you have; it does not ask you to restage the show.
A Ximilar API key
The one credential in the whole system, and it stays on your machine. No marketplace account, no password, no bot in your chat.
Get it running on its own
Before any of this touches your show, prove it works against your laptop webcam. Three commands.
Install it
The script builds a venv in ~/.cardstream, verifies
the release wheel against its checksums, fetches the model
weights and puts the commands on your PATH. Wheel, Docker and
source installs are on the download page.
$ curl -fsSL https://raw.githubusercontent.com/Ximilar-com/cardstream/main/scripts/install.sh | sh Add your key
Identification runs through Ximilar collectibles/v2 by
default, or your own system in its place.
XIMILAR_API_KEY is the only environment variable
anything reads — put it in your shell profile so it survives a
reboot on show night.
$ export XIMILAR_API_KEY=your-key
Hold a card up to your laptop
This opens the browser UI on your built-in webcam. Hold a card still for a beat: the overlay shows the state machine deciding, then the name, set and confidence, with the identify call’s wall time beside the match. That is the whole product — the rest of this page is only about where the pixels come from.
$ cardstream-web # → http://127.0.0.1:8001
Point it at your show
Pick one row. Which one depends on a single question — do you stream from a desktop or from a phone?
What you cannot do
Point cardstream at your public Whatnot or Fanatics playback page. There is no outbound stream URL for your own show, and scraping the player would add seconds of latency on top of the platform’s terms. Every route below taps your video upstream of the marketplace — which is exactly why cardstream needs no account, no password and no API key from them.
The OBS virtual camera
OBS can present your composed scene to the operating system as an ordinary webcam. cardstream then opens it exactly like any other camera — no second encode, no extra load on your encoder and no ffmpeg to install.
- In OBS, click Start Virtual Camera in the controls dock.
- Run cardstream against it as a webcam index. Index 0 is usually your built-in camera, so the virtual one is normally 1 — try 0, 1, 2 until you see your scene.
$ cardstream-web --source 1 Try this once before a show rather than during one: on macOS the terminal needs camera permission, and if OpenCV cannot open the virtual device on your machine, route B works everywhere.
A second output from OBS
cardstream listens on your own machine and OBS pushes a copy to it. Whatnot or Fanatics keep receiving precisely what they received before — this is an extra target, never a redirect.
- Start the listener first; it waits for the push and reconnects on its own.
- OBS has only one Stream output, so send the copy from a second one: either the
obs-multi-rtmpplugin, or Settings → Output → Recording → Custom Output (FFmpeg), type Output to URL, URLrtmp://127.0.0.1:1935/live, containerflv— then press Start Recording. - This route shells out to the system ffmpeg binary:
brew install ffmpegfirst.
$ cardstream-web --listen \ --source rtmp://0.0.0.0:1935/live
Its own camera on the table
A phone pushing straight to the app gives you nothing to tee. So stop chasing the outbound stream and give cardstream its own view of the same table: a second webcam overhead, or the camera’s HDMI out into a capture card.
- Point a webcam or capture card at the spot where you reveal.
- Run it on the machine next to that camera.
$ cardstream-web --source 0 It does not have to be your buyers’ angle. A tight, well-lit overhead shot identifies better than a compressed marketplace feed ever will.
Anything with a URL
rtsp://, rtmp:// and srt:// are pulled directly, plus ws:// JPEG feeds when your rig is homemade. Reconnects use capped backoff, so a studio link that drops mid-break comes back without you touching it.
- Give it the URL your encoder already publishes.
- The browser page becomes a passive viewer — analysis runs even with no browser open.
$ cardstream-web \ --source rtsp://studio/stream1
Tune it for the show you are running
Defaults are honest, but a break is not a generic camera feed — you usually know what you are opening before you open it.
Tell it what you are breaking
A game or set prefill narrows the search: faster calls, better
matches. One rule — always pass --alphabet when you
pass --game, because a game prefill turns the
endpoint’s own alphabet detection off and it then assumes latin,
so a Japanese card would match its English print.
$ cardstream-web --source 1 \ --game "Pokémon" --alphabet japanese --set-code M4
Change your mind mid-stream
When the next lot is a different game you do not restart anything: category, game, set code, alphabet and the result threshold are all editable in the browser settings dialog while the stream runs. Everything else — detector, gate, resolution — is read once at startup, so pick those now.
Keep the log, keep the port closed
--split-results gives every appearance its own row
instead of merging repeats — a running list of what you showed,
in the order you showed it, ready to reconcile against orders
afterwards. Leave --host at its default
127.0.0.1: that process holds your key and the local
UI is unauthenticated, so it should never be reachable from your
LAN.
$ cardstream-web --source 1 --split-results Then run your show. Detection, motion and the identity gate all run locally on your machine; the identification call fires once per card you put on the table — roughly a hundred in an hour, against the 54,000 frames that hour contains. The arithmetic is here.
The six things that actually go wrong
The virtual camera is not in the list
Work through --source 0, 1, 2 in turn — the indices are whatever the OS hands out. On macOS, give your terminal camera access under System Settings → Privacy & Security. If OpenCV still will not open it, switch to route B.
“ffmpeg not found”
Only --listen and --ffmpeg shell out to the system binary. Install it (brew install ffmpeg) and rerun; the virtual-camera, webcam and plain-pull routes need nothing extra.
OBS will not let me add a second stream
That is an OBS limit, not a cardstream one — it has a single Stream output. The obs-multi-rtmp plugin adds real extra targets; the Custom Output (FFmpeg) recording path in route B works with stock OBS.
Cards are found but never matched
Almost always resolution or motion. The card number has to be legible in the frame you send: keep OBS at 1080p, hold the reveal still for a beat, and only then loosen --result-threshold (default 0.9 — higher keeps weaker matches, 1.0 keeps everything).
The same card is identified twice
The identity gate scored the two views below --similarity-threshold (default 0.85) and called it a new card. Lower it a little. If you set a card down and pick it back up, raise --forget-after instead — after 2 seconds away, a card is treated as fresh by design.
Nothing is detected at all
Run with --show-detection to draw the box: detection always runs, it is just not drawn by default. No box means the card is too small or too fast in frame; a box with no match sends you to the row above.
Still stuck? The README documents every flag, and the docs hub groups them by what you are trying to do.