Check the stores, not the product page. Online units and store units are separate counts at Kohl's: Scavio's Kohl's API returns a SKU's online units from POST /api/v1/kohls/product, and /api/v1/kohls/store-availability returns that SKU's pickup units at every Kohl's store within about 50 miles of a ZIP, 2 credits a check. On November 10, 2026, a $5 Streamline Strawberry Magnetic Fidget Toy showed 0 units online and 421 units across all 48 stores near Chicago's ZIP 60601.
The question comes from r/NeeDoh, where a shopper asked on October 21, 2026 how anyone was scoring the online Kohl's drops of NeeDoh squish toys: refreshing the search and product pages did not help, and after a restock alert the item was "immediately out of stock". The thread drew 47 upvotes and 77 comments. The answers that worked pointed at the stores: commenters said the Kohl's app, on pickup, shows how many units their local store has. That is the number this post is about, for every store near you in one call.
The NeeDoh drops themselves are over: a later r/NeeDoh thread on October 30 said there were "no other drops for the foreseeable future", and a Kohl's search for "needoh" on November 10 returned 462 fidget toys and squishies but no NeeDoh product. The method works for any item that sells out online, and the next test is Black Friday: Mashable reports Kohl's sale running from November 22 to November 30, with Black Friday on November 27.
What one check returns today
From that same "needoh" search, the Streamline Strawberry Magnetic Fidget Toy was flagged unavailable online but available for pickup. Its product call (2 credits, 2.4 seconds; description and images trimmed):
{
"id": "8484528",
"title": "Streamline Strawberry Magnetic Fidget Toy",
"brand": "Streamline",
"status": "Out of Stock",
"dept": "223",
"price": 5,
"pickup_eligible": true,
"ship_to_store_eligible": true,
"rating": 5,
"review_count": 1,
"variants": [
{
"sku": "85920807",
"upc": "000659549258917",
"color": "Multi",
"availability": "Out of Stock",
"online_units": 0,
"max_per_order": 99,
"price": 5,
"regular_price": 5,
"pickup_eligible": true,
"in_store": true
}
]
}Sold out online: online_units: 0. Then the stores, with the SKU and dept from that response and a ZIP:
All 48 stores had it, 421 units between them: 12 at Bucktown, the nearest at 3.7 miles, and 22 at Bolingbrook, 28.6 miles out. Sold out online was not sold out.
Step 1: Find the SKU
Search for the item, then read the product. The search result id is the product id (the number after prd- in a kohls.com URL):
curl -s https://api.scavio.dev/api/v1/kohls/search \
-H "Authorization: Bearer $SCAVIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "needoh"}'
curl -s https://api.scavio.dev/api/v1/kohls/product \
-H "Authorization: Bearer $SCAVIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"product_id": "8484528"}'Each search item carries available_online, available_pickup and available_ship_to_store, a useful first filter. The product lists every SKU, one per color and size, with its online_units and the product's dept. For an item with sizes, pick the SKU for your size: stock is per SKU, not per product. Search matches loosely, so check the titles; "needoh" returned other brands' fidget toys rather than an empty page.
Step 2: Check every store near you
curl -s https://api.scavio.dev/api/v1/kohls/store-availability \
-H "Authorization: Bearer $SCAVIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sku": "85920807", "dept": "223", "zip": "60601"}'In 2.3 seconds (47 of 48 stores and the hours trimmed):
{
"sku": "85920807",
"zip": "60601",
"dept": "223",
"count": 48,
"in_stock_count": 48,
"total_pickup_units": 421,
"stores": [
{
"store_id": "725",
"name": "BUCKTOWN",
"pickup_units": 12,
"stock_level": "In Stock",
"in_stock": true,
"ship_to_store_units": 0,
"pickup_eligible": true,
"ship_to_store_eligible": true,
"ship_to_store_window": "Thu, Nov 12 - Tue, Nov 17",
"distance_miles": 3.68,
"address": "2140 N ELSTON AVE",
"city": "CHICAGO",
"state": "IL",
"zip": "60614",
"phone": "(773) 342-9032"
}
]
}pickup_units is the store's count; stock_level turns low counts into "Low Stock" (1 or 2 units in our captures) and 0 into "Out of Stock". Stores come back nearest first, with address, phone and the week's opening hours. It does not always go this way: a clearance color of a Croft & Barrow sweater the same morning was 0 online and 0 at all 48 of these stores, while a $24.99 sale color of the same sweater had 114 units at 45 of them (how deep Kohl's clearance goes). One call tells you which case you are in.
Step 3: Re-check on a schedule and alert on the change
A drop or a doorbuster is a count that moves. Store each check and alert when a store you can reach goes from 0 to a positive count:
import os, sqlite3, requests
from datetime import datetime
WATCH = [{"sku": "85920807", "dept": "223"}] # from Step 1
ZIP, MAX_MILES = "60601", 15
db = sqlite3.connect("kohls_stock.db")
db.execute("CREATE TABLE IF NOT EXISTS stock (checked_at TEXT, sku TEXT, store_id TEXT, name TEXT, miles REAL, units INTEGER)")
now = datetime.now().isoformat(timespec="minutes")
for w in WATCH:
r = requests.post(
"https://api.scavio.dev/api/v1/kohls/store-availability",
headers={"Authorization": f"Bearer {os.environ['SCAVIO_API_KEY']}"},
json={**w, "zip": ZIP},
timeout=120,
)
if r.status_code != 200:
continue # try again on the next run
for s in r.json()["data"]["stores"]:
if s["distance_miles"] > MAX_MILES:
continue
prev = db.execute("SELECT units FROM stock WHERE sku = ? AND store_id = ? ORDER BY checked_at DESC LIMIT 1",
(w["sku"], s["store_id"])).fetchone()
if s["pickup_units"] > 0 and (prev is None or prev[0] == 0):
print(f"{s['name']} ({s['distance_miles']} mi): {s['pickup_units']} units of {w['sku']}")
db.execute("INSERT INTO stock VALUES (?, ?, ?, ?, ?, ?)",
(now, w["sku"], s["store_id"], s["name"], s["distance_miles"], s["pickup_units"]))
db.commit()Run it from cron and send the print to whatever pings your phone. Keep SKUs and store ids as strings. Then go buy it yourself.
What this can and cannot tell you
- A count at one moment: the units are what kohls.com showed when you asked. A store's last unit can be gone by the time you get there. Call the store before a long drive.
- SKU, department and ZIP: the call needs all three, takes a ZIP (not a city) and covers about 50 miles around it. For a single store you already know,
/productwithstore_idadds that store's availability and price to every SKU. - Ship to store:
ship_to_store_unitsandship_to_store_windowsay whether the item can be sent to a store and when, separate from what is on the shelf. - No history: every response is now. The history starts with your first check, so start before the sale you care about.
- Monitoring only: the API reads; it does not add to cart, hold stock or check out, and we do not support checkout bots.
- US only: kohls.com in the United States.
One SKU checked every 15 minutes for 14 hours a day is 56 calls, 112 credits a day, $0.11 at the Growth rate of $1 per 1,000 credits; through the November 22-30 sale that is about 1,000 credits, $1.01. The 50 free credits on signup cover the first 25 checks. For clearance lists, SKU prices and Kohl's Cash windows, see how to get Kohl's clearance prices; for the same check at other retailers, see Target stock by store and Ulta in-store stock.
Try the Kohl's API free, 50 credits, no card, or run the store availability call in the playground.
Reference: Kohl's API overview · store availability docs · product docs · search docs · stores docs
Frequently asked questions
How do I know if my Kohl's store has an item in stock?
Get the item's SKU and department code from Scavio's /api/v1/kohls/product, then send both with your ZIP to /api/v1/kohls/store-availability. Each store within about 50 miles comes back with pickup_units, a stock level (In Stock, Low Stock, Out of Stock), its distance, address and hours. One call is 2 credits.
Why does Kohl's say out of stock online but in stock at a store?
Online units and store units are separate counts. On November 10, 2026, a $5 Streamline magnetic fidget toy showed 0 units online and "Out of Stock" on its product page data, while the 48 Kohl's stores within about 50 miles of Chicago's ZIP 60601 held 421 units for store pickup between them, 4 to 22 per store.
How often does Kohl's restock?
Kohl's does not publish a restock schedule, and nothing in the product or store data predicts one. What you can measure is when a store's count changes: check the same SKU on a schedule, store each count with the time, and the history shows how often each store moves.
Can I use this to check out automatically?
No. The API reads what kohls.com shows: prices, online units and store pickup units. It does not add to cart, reserve stock or check out, and we do not support checkout bots. Use it to know which store has the item, then buy it yourself.