How to Scrape Best Buy Prices and Stock in 2026: The Short Answer
If you want to scrape Best Buy for live prices and store-level availability in 2026, you have two realistic paths. The first is the official Best Buy Developer API, which exposes catalog, pricing, and (with approval) some availability data through REST endpoints keyed by SKU. The second is the public storefront, where SKU pages at /site/-/<slug>/<sku>.p?skuId=<sku> render the price in a .priceView-customer-price node and store-level inventory is fetched from internal JSON endpoints keyed by SKU and ZIP code.
The trade-off matters because the official API requires an application, a key, and adherence to rate limits that Best Buy sets per-tier — historically around 5 requests per second on the free tier and higher quotas for approved partners. Store-level availability (which store has how many units) is not reliably exposed on the public API tier most developers get. That data lives on the site, behind Best Buy's anti-bot stack. So a Best Buy price tracker or Best Buy stock checker that needs per-store granularity almost always ends up scraping HTML or internal JSON — and that means proxies.
This guide walks through the technical reality of doing that with ProxyHat: URL patterns, CSS selectors, the internal fulfillment endpoint, Akamai Bot Manager's _abck and bm_sz sensor cookies, and a worked Python example using curl_cffi over residential proxies with city-level geo targeting.
Technical Context: Why This Problem Exists
Best Buy runs its storefront on Akamai's edge. Akamai Bot Manager is one of the more aggressive commercial anti-bot systems in retail — it ships a JavaScript sensor that fingerprints the browser (canvas, WebGL, fonts, timing, pointer events), sets an _abck cookie, and re-issues that cookie on subsequent requests. If the sensor values look wrong or the IP reputation is flagged, Akamai returns a 403 or a JavaScript challenge page instead of the product HTML. The bm_sz cookie is the companion tracking cookie that ties the sensor run to a session.
Datacenter IPs get challenged within a handful of requests because Akamai maintains reputation lists for hosting ASNs (AWS, GCP, DigitalOcean, Hetzner, OVH). A fresh datacenter IP will often load one or two pages, then start receiving challenges. Mobile and residential IPs from real consumer ISPs have dramatically higher success rates because the ASN reputation is clean. This is the core reason a Best Buy stock checker built on datacenter proxies burns out quickly.
The second complication is that store availability is genuinely per-location. Best Buy computes fulfillment options using the ZIP code associated with the request (either from the postalCode cookie, the storeId cookie, or a query parameter). If you request from a Chicago residential IP, you see Chicago-area store stock. If you request from a Berlin IP, you see the default fulfillment set or a redirect. That means a national Best Buy stock checker needs to rotate US residential IPs across the metros you care about.
URL Patterns and Selectors
SKU pages
Best Buy product pages follow a predictable pattern:
https://www.bestbuy.com/site/<slug>/<sku>.p?skuId=<sku>
The slug is cosmetic — Best Buy redirects to the canonical slug if you pass a placeholder. So you can build URLs like:
https://www.bestbuy.com/site/-/6523402.p?skuId=6523402
and Best Buy will 301 to the full slug. This is useful for batch jobs where you only have SKUs.
Price and title selectors
On the rendered HTML, the customer-facing price sits in:
div.priceView-customer-price > span[aria-hidden="true"]
The product title is in .sku-title h1. The "add to cart" button container is .add-to-cart-button and its data-button-state attribute tells you whether the item is orderable online. For a Best Buy price tracker, .priceView-customer-price is the primary signal; for a stock checker, the button state plus the fulfillment JSON (below) is more reliable.
Internal fulfillment and price JSON
Best Buy's front end calls internal endpoints to populate store pickup and shipping options. The two most useful ones are:
https://www.bestbuy.com/productfulfillment?skus=<sku>&storeId=<store>
https://api.bestbuy.com/click/-/sku/<sku>/pdp
The /productfulfillment endpoint returns JSON keyed by SKU and store with fields like inStoreAvailability, shippingAvailability, pickupAvailability, and the per-store quantity bucket. The pdp endpoint returns a compact price object. Both are gated by the same Akamai sensor cookies as the HTML, so they are not a way to bypass anti-bot — they are a way to get clean structured data once you have a working session.
A truncated sample response from /productfulfillment looks like:
{
"skuId": "6523402",
"storeId": "281",
"inStoreAvailability": true,
"pickupAvailability": true,
"shippingAvailability": true,
"quantity": 7,
"storeName": "Chicago - Clark St",
"zipCode": "60601"
}
That single object is what most Best Buy stock checker projects actually need.
Category and search pagination
Category pages use ?cp=<page> for pagination and searchResultsPageSize=<n> for page size (up to 100). Search pages accept ?q=<term>&cp=<page>. The product cards on these pages are under .shop-sku-list-item and each card exposes the SKU in a data-sku-id attribute, which lets you enumerate SKUs before hitting the detail pages.
Why Store-Level Stock Needs US Residential Proxies with City Geo
Availability is computed server-side from the ZIP code associated with the request. If your scraper always exits from a single IP, you only ever see one store's inventory. If your scraper exits from a datacenter IP, Akamai challenges you before you see anything. The correct setup is:
- US residential IPs — because Best Buy's catalog and availability are US-centric and Akamai flags non-residential ASNs.
- City-level geo targeting — because each metro maps to a different store set. If you want Chicago, Atlanta, and LA stock, you need three different exit cities.
- Sticky sessions per ZIP — because the
_abcksensor cookie needs to warm up on a consistent IP before you hit the fulfillment endpoint.
ProxyHat supports city-level targeting via the username string. For a Chicago exit you'd use user-country-US-city-chicago; for Atlanta, user-country-US-city-atlanta. The full list of supported metros is on the locations page.
Worked Python Example: Fetch a SKU and Parse Availability
Below is a complete, runnable example using curl_cffi (which impersonates a real browser TLS fingerprint, important for Akamai) and ProxyHat residential proxies. The script fetches a SKU page, extracts the price, then hits the /productfulfillment endpoint for a specific store.
import re, json, time
from curl_cffi import requests
PROXY = "http://user-country-US-city-chicago:pass@gate.proxyhat.com:8080"
SKU = "6523402"
SKU_URL = f"https://www.bestbuy.com/site/-/{SKU}.p?skuId={SKU}"
FF_URL = f"https://www.bestbuy.com/productfulfillment?skus={SKU}&storeId=281"
def fetch(url, session_id, retries=3):
for attempt in range(retries):
proxy_user = f"user-country-US-city-chicago-session-{session_id}"
proxy = f"http://{proxy_user}:pass@gate.proxyhat.com:8080"
try:
r = requests.get(url, proxy=proxy, impersonate="chrome131", timeout=20)
if r.status_code == 200:
return r
if r.status_code == 403:
time.sleep(2 ** attempt) # backoff on Akamai challenge
continue
r.raise_for_status()
except Exception as e:
time.sleep(2 ** attempt)
return None
# 1. Warm the session on the SKU page
sid = f"chi-{SKU}-{int(time.time())}"
html = fetch(SKU_URL, sid)
if html:
price_match = re.search(r'priceView-customer-price.*?aria-hidden="true">\$([0-9.,]+)', html.text, re.S)
title_match = re.search(r'sku-title.*?<h1[^>]*>(.*?)</h1>', html.text, re.S)
print("Title:", title_match.group(1).strip() if title_match else "?")
print("Price:", price_match.group(1) if price_match else "?")
# 2. Hit fulfillment with the same session cookies
ff = fetch(FF_URL, sid)
if ff:
data = ff.json()
print(json.dumps(data, indent=2)[:600]) # truncated
The impersonate="chrome131" argument is what makes curl_cffi survive Akamai's TLS fingerprint check — it replays the ClientHello and JA3/JA4 hash of a real Chrome build. Plain requests with a residential proxy will still get challenged because the TLS fingerprint gives it away.
Rotation, Backoff, and Pagination Strategy
Sticky sessions per ZIP
Use a deterministic session ID per ZIP code, e.g. user-country-US-city-chicago-session-60601. This keeps the _abck cookie warm for that metro and avoids re-running the sensor on every request. Rotate the session ID only when you see repeated 403s, which usually means Akamai has flagged that particular cookie.
Backoff on 403 / Akamai challenges
When you receive a 403 or a page containing _abck challenge JavaScript, do not retry immediately. Exponential backoff (2s, 4s, 8s) plus a session rotation is the right pattern. Hitting the same endpoint with the same session after a challenge will burn the session permanently.
Pagination of category pages
For category enumeration, request ?cp=1&searchResultsPageSize=100 first, parse the data-sku-id attributes from each .shop-sku-list-item, then walk subsequent pages. Keep concurrency low — 2–4 concurrent requests per session is a sane ceiling for Best Buy. Higher concurrency triggers Akamai's rate-based challenge faster than anything else.
Concurrency budget
A practical budget: 100 concurrent sessions across metros, 2 requests per second per session, with 4-second backoff on 403. That yields roughly 200 requests per second nationally, which is more than enough for a Best Buy price tracker polling a few thousand SKUs every 15 minutes.
Comparing Approaches: API vs HTML vs Internal JSON
| Approach | Price data | Store-level stock | Anti-bot exposure | Setup cost |
|---|---|---|---|---|
| Official Best Buy API | Yes, reliable | Limited / requires approval | None (keyed) | Application + key approval |
| HTML scraping (SKU pages) | Yes, from .priceView-customer-price | Indirect (button state) | High (Akamai) | Residential proxies + TLS impersonation |
Internal /productfulfillment JSON | Yes | Yes, per store | High (same Akamai cookies) | Same as HTML, plus session warming |
ProxyHat-Specific Setup
For a Best Buy scraper you want residential, US, city-targeted, with sticky sessions. The ProxyHat connection string for a Chicago sticky session is:
http://user-country-US-city-chicago-session-abc123:pass@gate.proxyhat.com:8080
For SOCKS5 (useful if your HTTP client has SOCKS support and you want to avoid HTTP CONNECT overhead):
socks5://user-country-US-city-chicago-session-abc123:pass@gate.proxyhat.com:1080
Full connection details, username flag syntax, and code samples for Python, Node.js, and curl are in the ProxyHat documentation. Pricing for residential traffic is on the pricing page. If you're building a broader retail scraping pipeline, the web scraping use case and SERP tracking pages cover adjacent patterns.
Ethics, Terms of Service, and Legal Caveats
Scraping Best Buy sits in a gray zone that depends heavily on what you collect and how you use it. The practical guardrails:
- Public catalog and price data only. Do not scrape account pages, checkout flows, or anything behind a login. The hiQ v. LinkedIn precedent supports scraping public data, but it is not a blanket shield.
- Honor robots.txt and rate limits. Best Buy's robots.txt disallows some paths; respect it. Aggressive scraping that degrades the site for real users is both unethical and a legal liability under the Computer Fraud and Abuse Act (CFAA).
- No GDPR-protected personal data. Prices and stock are not personal data. Reviews tied to user handles are. Don't collect the latter.
- No checkout or purchase automation. Botting the cart is a ToS violation and, for high-demand launches, potentially a violation of anti-botting statutes in some states.
- Use the official API when it suffices. If you only need national pricing and basic availability, the developer API is cheaper, more reliable, and legally cleaner than scraping.
If your use case is a Best Buy price tracker for your own shopping or a legitimate competitive intelligence product, public price and stock scraping is defensible. If you're building a checkout bot, stop — that's a different and much riskier category.
Key Takeaways
The official API is the right default; scraping is for store-level granularity. Best Buy's API covers catalog and national pricing well but not per-store inventory at scale.
Akamai Bot Manager is the real obstacle, not the HTML structure.
_abcksensor cookies plus TLS fingerprinting mean you need both residential IPs and a TLS-impersonating client like curl_cffi.Store stock requires city-targeted US residential proxies. Availability is computed per ZIP, so a national Best Buy stock checker needs multiple city exits, not one national IP.
Sticky sessions per ZIP, backoff on 403, low concurrency. That combination keeps success rates above 90% in practice; higher concurrency burns sessions.
Stay on public catalog data and respect ToS. No login, no checkout, no personal data. The CFAA and GDPR are real risks if you cross those lines.
FAQ
What is the best way to scrape Best Buy prices and stock in 2026?
Use the official Best Buy Developer API for national pricing and catalog data. For per-store availability, scrape the public storefront using curl_cffi (for TLS impersonation) over US residential proxies with city-level geo targeting. Hit the internal /productfulfillment endpoint for structured JSON once the session is warmed. Avoid datacenter IPs — Akamai Bot Manager challenges them within a few requests.
Why does scraping Best Buy matter for proxy users?
Best Buy's storefront is protected by Akamai Bot Manager, which fingerprints browsers and flags datacenter ASNs. Proxy users care because the only reliable way to access store-level inventory at scale is residential IPs with city geo targeting and sticky sessions. Without proxies, a Best Buy stock checker dies after a handful of requests.
Which proxy type works best for scraping Best Buy?
US residential proxies with city-level targeting. Datacenter IPs get challenged almost immediately by Akamai. Mobile proxies work but are slower and more expensive. Residential gives the best balance of success rate, speed, and cost. Use sticky sessions per ZIP code so the _abck sensor cookie stays warm across requests.
How do you avoid blocks when scraping Best Buy?
Use a TLS-impersonating client like curl_cffi, rotate sticky sessions per ZIP, keep concurrency to 2–4 requests per session, and apply exponential backoff (2s, 4s, 8s) on 403 responses. Never reuse a challenged session — rotate the session ID. Avoid scraping login or checkout pages, which are more aggressively protected and legally riskier.
Is scraping Best Buy legal?
Scraping public price and stock data is generally defensible under the hiQ v. LinkedIn precedent, but it is not risk-free. Respect robots.txt, avoid personal data, and never automate checkout. The official API is the legally safest path when it covers your needs.






