Build responsive pricing UIs today with efficient polling and caching — structured so you can swap in a streaming transport later without touching your UI.
No WebSocket or SSE endpoint today. The API is HTTP request/response. Prices update on a schedule rather than tick-by-tick, so well-tuned polling gives you up-to-date data without a persistent connection. The patterns below keep your client ready for a streaming transport if one ships.
Batch your watchlist into a single ids request (up to 100 cards), poll only while the tab is visible, and re-render just the rows whose prices changed.
"js-comment">// Refresh a watchlist with the batch endpoint — one request, many cards.
async function refresh(ids, key) {
const res = await fetch(
"https:">//api.tcgpricelookup.com/v1/cards/search?ids=" + ids.join(","),
{ headers: { "X-API-Key": key } }
);
if (!res.ok) return; "js-comment">// see backoff section for 429 / 5xx handling
const { data } = await res.json();
for (const card of data) updateIfChanged(card);
}
"js-comment">// Poll only while the tab is visible to save quota.
let timer;
function start(ids, key, intervalMs = 30_000) {
stop();
timer = setInterval(() => {
if (document.visibilityState === "visible") refresh(ids, key);
}, intervalMs);
}
function stop() { clearInterval(timer); }Match cadence to how visible the data is. Polling faster than prices actually move just burns your daily quota.
| Use case | Refresh interval |
|---|---|
| Active watchlist / open card page | 15–30s |
| Background pages / dashboards | 60–120s |
| Bulk valuation / nightly sync | Once per scheduled run |
429 and 5xx, honoring Retry-After when present.Keep one reducer that applies price updates and one adapter that decides how they arrive. Polling is your adapter today; if a stream ships, you swap the adapter and the rest of your app is unchanged.
"js-comment">// Keep update handling separate from how updates arrive.
"js-comment">// Today the adapter polls; a future one could read a stream —
"js-comment">// your UI never has to change.
function applyPriceUpdate(state, card) {
const prev = state[card.id];
const next = card.prices?.raw?.near_mint?.tcgplayer?.market ?? null;
if (prev?.market === next) return state; "js-comment">// no-op, skip re-render
return { ...state, [card.id]: { ...card, market: next } };
}
const pollingAdapter = { subscribe: (ids, key, cb) => start(ids, key, 30_000) };
"js-comment">// const streamAdapter = { subscribe: ... } // drop-in later