What this actually is
A Discord bot that polls product pages across multiple retailers and pings a channel the moment something's worth acting on — back in stock, a real price change, or a Pokemon Center queue going live.
It started as a single-product Target stock checker and grew into a proper multi-retailer system, currently on v14. Target, Walmart, and Pokemon Center get full active monitoring; Amazon and Best Buy sit in a second tier built for sites that need heavier tooling to read reliably. The whole thing is alert-only — no automated add-to-cart, no queue-joining, no purchasing. It tells you something changed; you still do the buying.
Why this is two bots, not one
Target and Walmart both embed their product data as plain, server-rendered JSON right there in the first HTTP response — Target's page includes a standard application/ld+json block with availability and price, Walmart's includes a __NEXT_DATA__ script tag with the same. A regular HTTP request with realistic browser headers (and, for one site that actively challenges bots, TLS fingerprint spoofing via curl_cffi) gets everything needed. No JavaScript execution, no real browser. That's what makes it cheap enough to run this bot 24/7 on a Raspberry Pi with basically no resource cost.
Amazon doesn't play along the same way. It's known to be considerably more aggressive about blocking anything that isn't a real browser. Getting reliable stock/price data back means actually rendering the page — which is a completely different weight class: a browser process spun up per check, not a lightweight GET request.
So the design splits in two "Bot A" is the always-on headless bot covering everything plain HTTP can reach. "Bot B" is a separate, real-browser process (Playwright) reserved for sites that need it. They share one Discord webhook so alerts land in the same place either way — the split is purely about how each check happens, not where the results go, and any future retailer joins whichever tier its own page actually requires.
The actual signal each retailer gives up
Every one of these was found by opening a real product page and reading what came back — not from a public API, not from documentation. Retail sites don't publish this.
| Retailer | Where the data lives | What's extracted |
|---|---|---|
Target | <script type="application/ld+json"> | Availability, price, seller (schema.org Offer fields) |
Walmart | <script id="__NEXT_DATA__"> | Availability, price, seller name |
Pokemon Center | Response headers, cookies, redirect target, HTML keywords — checked in that priority order | Queue-it bot-wall state (not a per-product check) |
Amazon (Bot B) | Full rendered page text — no structured data block at all | Stock phrase, exact remaining-count phrase, buy-box presence, seller |
The Amazon row is the interesting one, since there's no JSON to just parse — the signal is whatever a human would visually read off the page. A few of the real phrases that turned out to be reliable:
"Only N left in stock - order soon."— genuinely in stock, but low enough to be worth its own urgency tier, not just a flat in/out flag."Currently unavailable."paired with"We don't know when or if this item will be back in stock."— a real, non-transient out-of-stock, not a blip."See All Buying Options"with no"Add to cart"anywhere on the page — the listing loads fine (a normal HTTP 200) but isn't actually purchasable through the main listing. A naive "page loaded, so it's in stock" check gets this one wrong.
Not every "in stock" alert should fire
Target, Walmart, and Amazon all allow third-party marketplace sellers on their platforms — effectively scalpers, frequently priced well above MSRP. A stock alert with no seller distinction is worthless if half of them are for a listing marked up 3x.
Each retailer's check also extracts a seller field alongside availability and price. When a listing is confirmed sold by someone other than the retailer itself, the loud stock-drop alert gets suppressed — the item is still tracked and visible on request, it just doesn't interrupt anyone for a price nobody wants to pay. An absent seller field is treated as "sold by the retailer" rather than "unknown," so the design leans toward not missing genuine restocks over aggressively filtering.
Two different ways of knowing a field is real Amazon's seller text ("Ships from Amazon / Sold by X") comes from directly reading real rendered product pages — it's exactly what a person sees on screen. Target and Walmart's seller fields come from the same structured data blocks already used for availability and price, following the shape those blocks are generally documented to have. Same outcome, two different kinds of evidence behind it.
A watchlist that manages itself
Adding something to watch is just posting a link in a dedicated Discord channel — no rigid syntax required for the common case. The bot detects the retailer from an explicit prefix (walmart: <url>) or, failing that, just sniffs it out of the URL's domain. Every message gets an explicit reply, confirmation or otherwise — nothing about this fails silently.
Two lifecycle rules keep a list from just growing forever:
- A hard cap per retailer. Once a list hits its limit, adding one more evicts the single oldest entry automatically. The confirmation message says exactly what got dropped.
- A 30-day full reset per retailer. Independent of the cap — a list that never gets full could otherwise sit there indefinitely with stale entries nobody's thought about in weeks. Every 30 days since it was last touched, a retailer's whole list clears itself and posts a notice explaining why.