check-stock▌
bestbuy.com/check-stock-muk8to · updated May 21, 2026
MDX-style export adds YAML metadata + attribution linking explainx.ai and this canonical listing URL.
Given a Best Buy SKU or product URL (and optional ZIP), return current price, online Ship-to-Home availability with ETA, pickup availability at nearby stores within radius, plus product title/brand/model/limit notice. Read-only — never adds to cart or reserves.
| name | check-stock |
| title | Best Buy Stock & Pickup Availability |
| description | >- Given a Best Buy SKU or product URL (and optional ZIP), return current price, online Ship-to-Home availability with ETA, pickup availability at nearby stores within radius, plus product title/brand/model/limit notice. Read-only — never adds to cart or reserves. |
| website | bestbuy.com |
| category | retail |
| tags | - retail - stock - pickup - akamai - graphql - read-only |
| source | 'browserbase: agent-runtime 2026-05-18' |
| updated | '2026-05-18' |
| recommended_method | browser |
| alternative_methods | [] |
| verified | true |
| proxies | true |
Best Buy Check Stock
Purpose
Given a Best Buy SKU (numeric product ID, e.g. 6418599) or a product URL — and optionally a ZIP code or store ID — return the product's current availability across fulfillment channels: online Ship-to-Home (with ETA), Pickup at nearby stores (per-store availability within radius_miles of the ZIP, with per-store ready-time), and the product's metadata (title, brand, model, current price, member-pricing tier, any "Limit X per customer" notice). Read-only — never click Add to Cart, Pick up at Store, Sign In, Add Protection, or any purchase / reservation control.
When to Use
- A user asks "is this in stock at my local Best Buy / for shipping to my ZIP?"
- Price-monitoring / availability-watch flows over a list of SKUs.
- Cross-retailer stock comparison (Amazon + Best Buy + Target).
- Verifying a deal is still bookable before notifying the user.
- Use the sibling skill
bestbuy.com/search-productsto resolve a query to a list of SKUs first; this skill only takes a known SKU/URL.
Workflow
Best Buy's PDP is a Next.js App Router page guarded by Akamai Bot Manager (_abck + bm_* cookie set). The entire fulfillment data shape (price, online + pickup + delivery availability, button state) is embedded in the SSR HTML as Apollo Client cache events under window[Symbol.for("ApolloSSRDataTransport")] — you do not need to wait for React to hydrate. Lead with a stealth+residential-proxy browser session, navigate once, then parse the static HTML.
Best Buy's developer API does not expose live store-level stock. The bestbuy.com/gateway/graphql endpoint is the canonical source the site itself uses (operation: FulfillmentOptionHook_FulfillmentDynamicQuery). Direct cookieless POSTs from a fresh IP are likely Akamai-blocked — treat the GraphQL endpoint as a candidate fast-path (see Browser fallback at end), not the recommended route.
1. Stealth + residential-proxy session — mandatory
SID=$(browse cloud sessions create --keep-alive --verified --proxies | jq -r .id)
export BROWSE_SESSION="$SID"
A bare session (no --verified, no --proxies) gets Akamai 403 / Access-Denied HTML on the first navigation. Both flags are required.
2. Set the user's ZIP before navigation
Without a user ZIP, Best Buy's SSR populates fulfillment data using the request-IP geolocation, falling back to ZIP 55423 / store 7 (Richfield, MN — Best Buy HQ) when geo is ambiguous. To get the data scoped to the user's ZIP, set the locDestZip cookie on the session before opening the PDP:
browse open "https://www.bestbuy.com/" --remote
# Use Set-Cookie / Network.setCookies via the CDP layer, or use the location-picker UI:
# Click "Update location" in the header → input ZIP → Submit. Wait load. Then proceed.
The cookie that drives fulfillment context is locDestZip (the ZIP). locStoreId is the resolved primary store. Both auto-populate after a successful zip-picker submission. Verify by reading document.cookie after the picker dismisses.
3. Navigate to the canonical PDP URL
Two URL schemes exist; both work but only one is canonical post-2024:
| Scheme | Example | Behavior |
|---|---|---|
| Legacy | https://www.bestbuy.com/site/{sku}.p?skuId={sku} | 301-redirects to canonical |
| Canonical (current) | https://www.bestbuy.com/product/{slug}/{bsin} | Direct PDP — preferred |
The bsin is a 10-character alphanumeric ID (e.g. JJ8ZHP82P6). If you only have the SKU, hit the legacy URL with --allow-redirects and capture the Location header to learn the canonical URL — but note the redirect-leak gotcha (see below: an unknown/inactive SKU may redirect to a totally unrelated product).
browse open "https://www.bestbuy.com/site/${SKU}.p?skuId=${SKU}" --remote
browse wait load
browse wait timeout 1500 # Apollo SSR events finish streaming after `load`
4. Extract product metadata from JSON-LD
Read the static HTML and pull <script id="product-schema" type="application/ld+json">:
HTML=$(browse get html body --remote)
echo "$HTML" | node -e "
let h=''; process.stdin.on('data',d=>h+=d).on('end',()=>{
const m=h.match(/<script id=\"product-schema\" type=\"application\\/ld\\+json\">([\\s\\S]*?)<\\/script>/);
if (m) console.log(JSON.stringify(JSON.parse(m[1]), null, 2));
});"
You get a structured Product object with name, sku, model, brand.name, color, url, image, aggregateRating { ratingValue, reviewCount }, additionalProperty[] (full spec sheet), and offers[]. Caveat: for dotComDisplayStatus: "inactive" products (discontinued online), offers[] is empty or contains only a Refurbished/Open-Box offer — the active "new" price lives in the Apollo cache (step 5).
5. Extract price + fulfillment from the Apollo SSR cache
The richest signal is in inline <script> tags that hydrate Apollo's cache via window[Symbol.for("ApolloSSRDataTransport")] ??= []).push(...). Each push contains a stream of {type: "started" | "next" | "completed", options/value, id} events. The relevant events are the type: "next" payloads whose value.data.productBySkuId is populated. Specifically look for:
| Source query | Fields to extract |
|---|---|
InactiveProductHeader_Init / PDP_ProductSkuIdComposite_Init | productBySkuId.{brand, skuId, name.short, manufacturer.modelNumber, primaryImage.piscesHref, dotComDisplayStatus, bsin, upc} |
FulfillmentOptionHook_FulfillmentDynamicQuery | productBySkuId.price.customerPrice, productBySkuId.fulfillmentOptions.{buttonStates[], shippingDetails[], deliveryDetails[], ispuDetails[]} |
A robust extractor regexes for "productBySkuId":\{[\s\S]*?\}\} and "fulfillmentOptions":\{[\s\S]*?\} after stripping JS quoting, then JSON.parse on the surrounding object. The hydration stream lives inside large inline script tags; don't try to parse it as standalone JSON — find the inner object literals.
6. Map the data to the output schema
- Online (Ship-to-Home) state — derive from
fulfillmentOptions.buttonStates[].buttonState:ADD_TO_CART/BUY_NOW→"In Stock"SOLD_OUT→"Sold Out"COMING_SOON→"Coming Soon"(readreleaseDateDisplayValuefor the date)NOT_AVAILABLE→"Currently Unavailable"CHECK_STORES→ online not available, pickup may be — fall through to step 6 pickup logic
- Ship-to-Home ETA — from
shippingDetails[].shippingAvailability[].customerLOSGroupyou getdisplayDateType,minLineItemMaxDate,maxLineItemMaxDate,name(e.g. "Standard"). The user-facing "Get it by Wed, May 20" string is rendered server-side and also surfaces in the SSR HTML — search for"shippingDisplayDateType"and adjacent date-text fragments.shippingEligible: false⇒ no Ship-to-Home. - Pickup stores — from
ispuDetails[].nearbyLocations[]. Each entry hasavailability.{maxDate, minPickupInHours, pickupEligible, quantity, fulfillmentType}andstore.{storeId, displayName, address, city, state, zip, distance}. Map:pickupEligible: true && minPickupInHours <= 24→"Available Today"withready_time = "Ready in ${minPickupInHours} hour(s)"pickupEligible: true && minPickupInHours > 24→"Available Tomorrow"(or usemaxDate) withready_time = "Ready ${maxDate}"pickupEligible: false→"Not Available"
- Price + member tier —
productBySkuId.price.customerPriceis the price for the currentplanPaidMemberType(default"NULL"= logged-out / non-member). To get member-tier pricing (My Best Buy Plus / Total), re-execute the same query withplanPaidMemberType: "PLUS_NEW"or"TOTAL"— these are typically only visible to members, but the SSR may render member-only prices in adjacentpriceConditionblocks. - "Limit X per customer" — search the rendered HTML for
Limit\s+\d+\s+per\s+customer. This is a presentational string near the price block; it does not live in the GraphQL response.
7. (Optional) Filter by radius_miles
The default inStorePickup.searchNearby: true returns the closest ~10 stores. Best Buy's default radius is 25 miles. To enforce a custom radius_miles, post-filter the returned nearbyLocations[] by .store.distance (the field is miles as a number). To force a wider search, the only verified way is via the live "Find a store" UI — there's no searchRadius field on ProductFulfillmentInput.inStorePickup exposed publicly. Document the cap in your output.
8. Release the session
browse cloud sessions update "$SID" --status REQUEST_RELEASE
Browser fallback / candidate API path
If a future agent wants to skip step 3's page render entirely, the GraphQL endpoint can in principle be hit directly:
POST https://www.bestbuy.com/gateway/graphql
Content-Type: application/json
Origin: https://www.bestbuy.com
Referer: https://www.bestbuy.com/product/{slug}/{bsin}
Cookie: locDestZip={zip}; locStoreId={storeId}; _abck=...; bm_sz=...
Body (operationName: FulfillmentOptionHook_FulfillmentDynamicQuery, query text as observed in the SSR HTML's Apollo started events). This was not end-to-end verified in skill construction — direct cookieless POSTs from an untrusted IP are very likely Akamai-blocked (the _abck / bm_sz cookies are sensor-checked). The safe pattern is: navigate the PDP once in a stealth+proxies browser, harvest the Akamai cookies from the session, then re-issue the GraphQL POST from page context using fetch() with credentials: "include". Treat the GraphQL path as a 2x-faster optimization, not the primary path.
Site-Specific Gotchas
- READ-ONLY. Do not click Add to Cart, Pick up at Store, Sign In, Add Protection, "Add Open-Box to Cart", or any reservation control. Capturing data is fine; transitioning state is not.
- Akamai Bot Manager. Stealth (
--verified) + residential proxies (--proxies) are mandatory. A bare session gets a 403 + Akamai's Access-Denied HTML or an interstitial. Cookies returned:_abck,bm_ss,bm_s,bm_so,bm_sz,akacd_PR_www_bestbuy_com,bby_cbc_lb— the_abckis the canonical Bot-Manager session token. - URL-migration redirect-leak gotcha. Best Buy migrated PDP URLs from
/site/{sku}.p?skuId={sku}to/product/{slug}/{bsin}. The legacy URL still 301-redirects, but an unknown / deactivated SKU may redirect to a completely unrelated product instead of 404. Example observed during skill construction: legacy URL for SKU6418599returned 301 → MacBook Air M1 (which matches), but the redirect mechanism doesn't always preserve mapping. Always verify the redirected URL'sbsinmatches the SKU's expected canonical path by readingproductBySkuId.skuIdfrom the SSR HTML and comparing against the input SKU. If they mismatch, the SKU likely doesn't exist anymore — returnsuccess: false, reason: "sku_not_found". dotComDisplayStatus: "inactive"is a distinct outcome. When a product is no longer sold online (only refurb / open-box),dotComDisplayStatus == "inactive",buttonStates[0].buttonState == "NOT_AVAILABLE",shippingAvailability[0].shippingEligible == false,ispuAvailability[0].pickupEligible == false, andJSON-LD offers[]is empty (or contains only refurbished). This is NOT an error — returnonline.availability: "Currently Unavailable"with the refurb offer (if any) under arefurbished_offerfield.- Default ZIP is Richfield, MN (
55423), default store is7. Without alocDestZipcookie, the SSR renders fulfillment context against Best Buy's HQ ZIP. The PDP HTML will say "Get it by … to 55423" — silently emitting this to a user in California is a bug. Always verifyshippingDetails[].destinationZipCodematches the user's input ZIP before emitting, and re-fetch with the right cookie if not. - Data is in the SSR HTML — do not wait for React. The Apollo SSR transport events stream all
productBySkuIdandfulfillmentOptionspayloads inline during initial HTML render.browse wait timeout 1500afterloadis sufficient; React hydration is irrelevant. Don't trybrowse snapshotto find fulfillment text — the rendered React tree's text content is the same data you already have inwindow[Symbol.for("ApolloSSRDataTransport")]events, but harder to parse. buttonStateis the canonical availability signal, not visible button text. Observed enum values during construction:NOT_AVAILABLE,ADD_TO_CART,BUY_NOW,SOLD_OUT,COMING_SOON,CHECK_STORES. Map to user-facing strings yourself; don't trust scraped button labels (they're A/B-test-controlled).- Pickup data depends on
inStorePickup.storeIdANDsearchNearby: true. The GraphQLfulfillmentInput.inStorePickuprequires astoreIdeven when you want a nearby-search result — pass7(HQ store) or any valid store ID; withsearchNearby: trueBest Buy returns the actually-nearby stores based ondestinationZipCode. Don't try to omitstoreId. radius_milesis not a publicly-exposed filter.ProductFulfillmentInput.inStorePickuphas nosearchRadiusfield. The default ~25-mile radius is server-controlled. Post-filternearbyLocations[]bystore.distance(anumberin miles) to honor a custom radius.- PDP HTML for active products may exceed 1MB. The Browserbase Fetch API caps response bodies at 1MB. Inactive/discontinued PDPs (~900KB) fit; active PDPs (with full review prerender) may not. Always use a live browser session for active products —
browse get html bodyreads from the rendered DOM, no size cap. - Best Buy Developer API does not expose store-level stock. The
https://api.bestbuy.com/v1/products(...)endpoint requires an API key and only returns catalog metadata + online availability. There is no documented endpoint for per-store pickup quantity./gateway/graphqlis the only source. POST /gateway/graphqlfrom cookieless IP is candidate-only, untested in skill construction. The construction environment couldn't validate direct POST behavior (sandbox DNS policy blocked outbound to bestbuy.com and to Browserbase's CDP connect server). The skill assumes — but does not prove — that the GraphQL endpoint is Akamai-protected in the same way as the page. Future agents should re-verify before relying on the API fast-path.- GraphQL operation:
FulfillmentOptionHook_FulfillmentDynamicQuery. Variables:skuId: String!,fulfillmentInput: ProductFulfillmentInput!,productPriceInput: ProductItemPriceInput!,openBoxCondition: Int. The full query text (with all fragments) is embedded in the SSR HTML as an Apollostartedevent — copy it from there rather than hand-writing it. Operation names and shapes were stable across two PDP fetches during construction; if Best Buy renames them, the SSR HTML always has the current shape. - Member-tier pricing is logged-in-only.
customerPricereflectsplanPaidMemberType: "NULL"(logged-out) by default. To surface My Best Buy Plus / Total prices, the page context needs an authenticated session — which violates read-only. Emitmember_pricing.my_best_buy_plus = null, my_best_buy_total = nullunless an authenticated session is explicitly in scope (out of scope for this skill). AAAA…base64 surprise frombrowse cloud fetch --output. When the response is binary (images, gzip), the Fetch API returns{content, encoding: "base64"}—--outputwrites the raw envelope, not the decoded bytes. To save the actual binary, parse the JSON andBuffer.from(content, "base64")yourself. Affects the "fetch the hero image for thumbnail" path; not relevant for HTML extraction.
Expected Output
A single JSON object, with these distinct outcome shapes:
// Active product, online + pickup data populated for user's ZIP
{
"success": true,
"sku": "6418599",
"bsin": "JJ8ZHP82P6",
"title": "Sony - WH-1000XM5 Wireless Noise-Canceling Over-the-Ear Headphones - Black",
"brand": "Sony",
"model": "WH1000XM5/B",
"upc": "027242923386",
"url": "https://www.bestbuy.com/product/{slug}/{bsin}",
"primary_image_url": "https://pisces.bbystatic.com/image2/BestBuy_US/images/products/6418/6418599_sd.jpg",
"price": { "current": 399.99, "currency": "USD" },
"member_pricing": { "my_best_buy_plus": null, "my_best_buy_total": null },
"limit_per_customer": null,
"online": {
"availability": "In Stock",
"button_state": "ADD_TO_CART",
"ship_to_home_eta": "Get it by Wed, May 20",
"destination_zip": "94103",
"shipping_eligible": true
},
"pickup": {
"zip": "94103",
"radius_miles": 25,
"stores": [
{
"store_id": "186",
"store_name": "Harrison Street",
"address": "1717 Harrison St, San Francisco, CA 94103",
"distance_miles": 0.6,
"availability": "Available Today",
"min_pickup_in_hours": 1,
"max_date": "2026-05-18",
"quantity": 5,
"ready_time": "Ready in 1 hour"
}
]
}
}
// Inactive / discontinued product (only refurb available)
{
"success": true,
"sku": "6418599",
"bsin": "JJ8ZHP82P6",
"title": "MacBook Air 13.3\" Laptop - Apple M1 chip - 8GB Memory - 256GB SSD - Gold",
"brand": "Apple",
"model": "MGND3LL/A",
"dot_com_display_status": "inactive",
"online": { "availability": "Currently Unavailable", "button_state": "NOT_AVAILABLE", "shipping_eligible": false },
"pickup": { "zip": "55423", "radius_miles": 25, "stores": [] },
"refurbished_offer": {
"price": 364.99,
"sku": "6489687",
"condition": "Refurbished",
"currency": "USD"
}
}
// SKU redirected to an unrelated product (legacy-URL mismatch)
{ "success": false, "reason": "sku_not_found", "input_sku": "9999999", "redirected_to_sku": "6418599" }
// Akamai 403 / bot-detection wall on first navigation
{ "success": false, "reason": "akamai_blocked", "status_code": 403, "url": "https://www.bestbuy.com/product/..." }
// Sold out for the user's ZIP (online out, all nearby stores out)
{
"success": true,
"sku": "...",
"online": { "availability": "Sold Out", "button_state": "SOLD_OUT", "shipping_eligible": false },
"pickup": { "zip": "94103", "radius_miles": 25, "stores": [/* all with availability: "Not Available" */] }
}
// Coming Soon (pre-order)
{
"success": true,
"sku": "...",
"online": {
"availability": "Coming Soon",
"button_state": "COMING_SOON",
"release_date": "2026-06-15",
"ship_to_home_eta": "Get it by Mon, Jun 15",
"shipping_eligible": true
},
"pickup": { "zip": "...", "stores": [] }
}
How to use check-stock on Cursor
AI-first code editor with Composer
Prerequisites
Before installing skills in Cursor, ensure your development environment meets these requirements:
- ›Cursor installed and configured on your development machine
- ›Node.js version 16.0+ with npm package manager (verify with
node --version) - ›Active project directory or workspace where you want to add check-stock
Execute installation command
Execute the skills CLI command in your project's root directory to begin installation:
The skills CLI fetches check-stock from GitHub repository bestbuy.com/check-stock-muk8to and configures it for Cursor.
Select Cursor when prompted
The CLI will show a list of available agents. Use arrow keys to navigate and space to select Cursor:
Verify installation
Confirm successful installation by checking the skill directory location:
Reload or restart Cursor to activate check-stock. Access the skill through slash commands (e.g., /check-stock) or your agent's skill management interface.
Security & Verification Notice
We perform automated surface-level scans (Gen AI Scanner, Socket, Snyk) during installation. These checks detect common vulnerabilities but do not guarantee complete security. Always review skill source code and verify the publisher's reputation before production use.
Skills execute code in your development environment. Always verify the publisher's identity, review recent commits, and test in isolated environments before production deployment.
List & Monetize Your Skill
Submit your Claude Code skill and start earning
Use Cases▌
Task Automation & Efficiency
Automate repetitive workflows and reduce manual effort
Example
Generate reports, summarize documents, draft communications
Save 3-5 hours per week on routine tasks
Knowledge Enhancement
Learn new skills, understand complex topics, get expert guidance
Example
Explain concepts, provide examples, suggest learning resources
Accelerate learning and skill development by 2x
Quality Improvement
Enhance output quality through reviews, suggestions, and refinements
Example
Review drafts, suggest improvements, catch errors
Improve work quality by 30-40% with less effort
Implementation Guide▌
Prerequisites
- ›Claude Desktop or compatible AI client with skill support
- ›Clear understanding of task or problem to solve
- ›Willingness to iterate and refine outputs
Time Estimate
15-45 minutes depending on use case complexity
Installation Steps
- 1.Install skill using provided installation command
- 2.Test with simple use case relevant to your work
- 3.Evaluate output quality and relevance
- 4.Iterate on prompts to improve results
- 5.Integrate into regular workflow if valuable
Common Pitfalls
- ⚠Expecting perfect results without iteration
- ⚠Not providing enough context in prompts
- ⚠Using skill for tasks outside its intended scope
- ⚠Accepting outputs without review and validation
Best Practices▌
✓ Do
- +Start with clear, specific prompts
- +Provide relevant context and constraints
- +Review and refine all outputs before using
- +Iterate to improve output quality
- +Document successful prompt patterns
✗ Don't
- −Don't use without understanding skill limitations
- −Don't skip validation of outputs
- −Don't share sensitive information in prompts
- −Don't expect skill to replace human judgment
💡 Pro Tips
- ★Be specific about desired format and style
- ★Ask for multiple options to choose from
- ★Request explanations to understand reasoning
- ★Combine AI efficiency with human expertise
When to Use This▌
✓ Use When
Use when skill capabilities match your task, clear ROI on time saved, and you can validate outputs. Best for repetitive tasks, learning, and quality improvement.
✗ Avoid When
Avoid when task requires deep expertise you can't validate, involves sensitive decisions, or when learning process is more valuable than speed of completion.
Learning Path▌
- 1Familiarize yourself with skill capabilities and limitations
- 2Start with low-risk, non-critical tasks
- 3Progress to more complex and valuable use cases
- 4Build expertise through regular use and experimentation
Discussion
Product Hunt–style comments (not star reviews)- No comments yet — start the thread.
Ratings
4.6★★★★★71 reviews- ★★★★★Olivia Robinson· Dec 28, 2024
check-stock reduced setup friction for our internal harness; good balance of opinion and flexibility.
- ★★★★★Pratham Ware· Dec 24, 2024
check-stock reduced setup friction for our internal harness; good balance of opinion and flexibility.
- ★★★★★Hana Diallo· Dec 24, 2024
check-stock has been reliable in day-to-day use. Documentation quality is above average for community skills.
- ★★★★★Hiroshi Wang· Dec 16, 2024
Useful defaults in check-stock — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
- ★★★★★Hana Taylor· Dec 16, 2024
Keeps context tight: check-stock is the kind of skill you can hand to a new teammate without a long onboarding doc.
- ★★★★★Soo Singh· Dec 16, 2024
Registry listing for check-stock matched our evaluation — installs cleanly and behaves as described in the markdown.
- ★★★★★Nia Kim· Dec 12, 2024
Registry listing for check-stock matched our evaluation — installs cleanly and behaves as described in the markdown.
- ★★★★★Olivia Li· Dec 12, 2024
Solid pick for teams standardizing on skills: check-stock is focused, and the summary matches what you get after install.
- ★★★★★Meera Martinez· Dec 4, 2024
check-stock has been reliable in day-to-day use. Documentation quality is above average for community skills.
- ★★★★★Ama Sharma· Nov 23, 2024
check-stock fits our agent workflows well — practical, well scoped, and easy to wire into existing repos.
showing 1-10 of 71