How to Scrape Amazon Without Getting Blocked (2026 Guide)
Prerequisites
- Basic Python knowledge (3.8+)
- Familiarity with HTTP requests and HTML parsing
- A proxy provider or residential IP source
- pip installed for package management
Amazon is one of the most heavily protected websites on the internet. Their anti-bot system combines behavioral analysis, device fingerprinting, rate limiting, and CAPTCHA challenges to block automated access. Despite this, Amazon product data is among the most valuable in e-commerce — pricing, reviews, bestseller rankings, and inventory data drive critical business decisions. This guide walks through a practical, step-by-step approach to scraping Amazon reliably in 2026, covering the techniques that actually work and the common mistakes that get you blocked.
-
Understand Amazon's Anti-Bot Layers
Before writing any code, you need to understand what you are up against. Amazon's detection system operates on multiple layers:
1. IP reputation — Datacenter ranges are registered to hosting providers and identifiable by ASN, which makes them the easiest class of traffic to filter. Residential and mobile addresses are harder to classify from the ASN alone, but they can still be flagged on request patterns. 2. TLS fingerprinting — Amazon inspects TLS handshake characteristics (JA3/JA4 fingerprints) to identify automated clients. Standard Python requests libraries have distinctive TLS fingerprints. 3. Browser fingerprinting — JavaScript-based checks examine canvas rendering, WebGL, audio context, and dozens of other signals. 4. Behavioral analysis — Request timing, navigation patterns, and mouse/keyboard events are analyzed on rendered pages. 5. Rate limiting — Too many requests from the same IP or session trigger progressive challenges (CAPTCHAs, then blocks).
Your scraping strategy needs to address all five layers to maintain reliable access.
Tip: Amazon's detection is adaptive — techniques that work today may stop working in weeks. Build your scraper with modularity so you can swap components (proxy provider, fingerprint strategy, parsing logic) independently.
-
Set Up Your Python Environment
Start by creating a clean virtual environment and installing the necessary packages. We will use
curl_cffiinstead ofrequestsbecause it produces realistic TLS fingerprints that match real browsers.bashpython3 -m venv amazon-scraper source amazon-scraper/bin/activate pip install curl_cffi selectolax fake-useragentTip: Avoid using the standard `requests` library directly — its TLS fingerprint is well-known to anti-bot systems. `curl_cffi` impersonates real browser TLS stacks.
-
Configure Realistic Request Headers
Your request headers must be internally consistent and match what a real browser would send. The most common mistake is sending a Chrome user-agent with headers that do not match Chrome's header order or values.
pythonfrom curl_cffi import requests from fake_useragent import UserAgent import random import time ua = UserAgent(browsers=['Chrome'], os=['Windows', 'macOS']) def get_headers(): user_agent = ua.random return { 'User-Agent': user_agent, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9', 'Accept-Encoding': 'gzip, deflate, br', 'DNT': '1', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-Site': 'none', 'Sec-Fetch-User': '?1', 'Cache-Control': 'max-age=0', } def scrape_amazon(url, proxy=None): session = requests.Session(impersonate='chrome') proxies = {'https': proxy} if proxy else None response = session.get( url, headers=get_headers(), proxies=proxies, timeout=30 ) return responseTip: Header order matters. Real Chrome sends headers in a specific order, and some anti-bot systems check this. The `curl_cffi` library with `impersonate='chrome'` handles header ordering automatically.
-
Implement Proxy Rotation with Smart Retry Logic
Never scrape Amazon from a single IP. You need a pool of residential or mobile IPs, and your rotation strategy should be smarter than random assignment. Key principles:
– Assign one IP per product category or search term to mimic a real user browsing within a category. – If an IP receives a CAPTCHA, retire it for at least 30 minutes. – Use mobile carrier IPs when available. Carrier-grade NAT puts many real subscribers behind the same address, so the IP by itself carries less signal about any one client. – Track success rates per IP and remove consistently poor performers.
pythonimport random from collections import defaultdict from datetime import datetime, timedelta class ProxyManager: def __init__(self, proxies: list[str]): self.proxies = proxies self.cooldowns: dict[str, datetime] = {} self.failures: dict[str, int] = defaultdict(int) def get_proxy(self) -> str | None: available = [ p for p in self.proxies if p not in self.cooldowns or datetime.now() > self.cooldowns[p] ] if not available: return None # Weight toward proxies with fewer failures weights = [1 / (self.failures[p] + 1) for p in available] return random.choices(available, weights=weights, k=1)[0] def report_failure(self, proxy: str, is_captcha: bool = False): self.failures[proxy] += 1 cooldown = timedelta(minutes=30) if is_captcha else timedelta(minutes=5) self.cooldowns[proxy] = datetime.now() + cooldown def report_success(self, proxy: str): self.failures[proxy] = max(0, self.failures[proxy] - 1) -
Add Human-Like Request Timing
Uniform request intervals are a dead giveaway. Real users do not request pages at exact 2-second intervals. Implement randomized delays with a realistic distribution.
pythonimport random import time def human_delay(min_seconds=1.5, max_seconds=5.0): """Generate a human-like delay using a log-normal distribution.""" # Log-normal produces occasional longer pauses, mimicking # a real user who sometimes reads the page longer delay = random.lognormvariate(0.5, 0.5) delay = max(min_seconds, min(delay, max_seconds)) time.sleep(delay) def scrape_product_list(urls: list[str], proxy_manager: ProxyManager): results = [] for url in urls: proxy = proxy_manager.get_proxy() if not proxy: print('All proxies on cooldown. Waiting...') time.sleep(60) proxy = proxy_manager.get_proxy() try: response = scrape_amazon(url, proxy=proxy) if 'captcha' in response.text.lower(): proxy_manager.report_failure(proxy, is_captcha=True) continue proxy_manager.report_success(proxy) results.append(response.text) except Exception as e: proxy_manager.report_failure(proxy) print(f'Error: {e}') human_delay() return resultsTip: For high-volume scraping, consider batching requests by category. Scrape all products in one category before moving to the next, with a longer pause between categories. This mirrors real browsing behavior.
-
Parse Product Data Efficiently
Use
selectolaxinstead of BeautifulSoup for parsing — it is significantly faster and handles Amazon's HTML well. Focus on extracting structured data from the key page elements.pythonfrom selectolax.parser import HTMLParser def parse_product_page(html: str) -> dict: tree = HTMLParser(html) def text(selector: str) -> str: node = tree.css_first(selector) return node.text(strip=True) if node else '' def attr(selector: str, attribute: str) -> str: node = tree.css_first(selector) return node.attributes.get(attribute, '') if node else '' return { 'title': text('#productTitle'), 'price': text('.a-price .a-offscreen'), 'rating': text('#acrPopover .a-icon-alt'), 'review_count': text('#acrCustomerReviewText'), 'availability': text('#availability span'), 'brand': text('#bylineInfo'), 'asin': attr('[data-asin]', 'data-asin'), 'image_url': attr('#landingImage', 'src'), 'features': [ li.text(strip=True) for li in tree.css('#feature-bullets li span.a-list-item') ], }Tip: Amazon frequently changes its HTML structure. Build your parser with fallback selectors and log warnings when primary selectors fail to match — this gives you early warning of layout changes.
-
Handle CAPTCHAs and Blocks Gracefully
Even with good infrastructure, you will occasionally encounter CAPTCHAs or soft blocks. Your scraper needs to detect these and respond appropriately rather than continuing to hammer the same endpoint.
Key detection patterns: – CAPTCHA page: Contains 'captcha' in the response body or a redirect to
/errors/validateCaptcha– Dog page: Amazon's generic error page showing a dog photo — means your session is flagged – 503 errors: Temporary rate limiting — back off and retry – Robot check redirect: URL changes to/gp/product/robot-checkWhen detected, retire the current proxy/session and switch to fresh infrastructure. Do not retry the same request from the same IP.
pythondef detect_block(response) -> str | None: """Returns block type or None if response is clean.""" if response.status_code == 503: return 'rate_limited' body = response.text.lower() if 'captcha' in body or 'validatecaptcha' in body: return 'captcha' if 'sorry, we just need to make sure' in body: return 'robot_check' if '[email protected]' in body: return 'hard_block' if response.url and 'robot-check' in str(response.url): return 'robot_check' return None -
Consider Real-Device Infrastructure for Production
The techniques above work for moderate-scale scraping, but production workloads hitting Amazon daily will eventually face diminishing returns from proxy rotation alone. Amazon's fingerprinting has become sophisticated enough that the gap between emulated and real browser environments is a primary detection vector.
For production-grade Amazon scraping, consider infrastructure that uses real devices rather than emulated browsers. Services like Archonum route requests through actual smartphones with native fingerprints, which removes the TLS mismatch, canvas fingerprint, and WebGL inconsistencies that trip up even well-configured headless browsers. This approach trades the complexity of managing fingerprint consistency for a simpler integration where the browser and the exit IP are the same device.
The decision between DIY scraping (as outlined in steps 1-7) and managed real-device infrastructure usually comes down to scale and how much maintenance you want to own. If you need data from Amazon for business-critical decisions and can tolerate occasional gaps, the DIY approach works. If Amazon data feeds a process that cannot tolerate gaps, the ongoing work of a DIY scraper — chasing fingerprint changes, burning and replacing IPs, patching selectors after every layout change — often costs more engineering time than purpose-built infrastructure costs in fees.
Tip: Track your scraper's success rate weekly and treat your own measured baseline as the threshold, not a number from a vendor page. A sudden drop against that baseline usually means Amazon has changed detection; a gradual decline suggests your IPs are being burned.
Scraping Amazon reliably in 2026 requires a multi-layered approach: realistic TLS fingerprints, properly configured headers, smart proxy rotation, human-like timing, and robust error handling. The code examples in this guide provide a solid foundation, but remember that Amazon actively evolves their anti-bot systems. What works today may need adjustment in a few months. The most resilient approach is to build your scraper with modular components that can be swapped independently, and to monitor success rates continuously so you can react quickly when detection patterns change. For teams where Amazon data is mission-critical, real-device infrastructure removes one layer of that game entirely: there is no fingerprint to keep consistent when the browser is a real phone.
FAQ
Scraping publicly available Amazon product data is generally legal under US law following the hiQ v. LinkedIn precedent. However, Amazon's Terms of Service prohibit automated access, so there is a contractual risk. Most e-commerce companies treat Amazon scraping as a standard business practice, but you should consult your own legal counsel for your specific jurisdiction and use case.
Amazon publishes no quota, and there is no fixed number to work from. The ceiling is set by your infrastructure: throughput is bounded per IP, so your pool size, the cooldown you enforce after a challenge, and how well your timing is randomized determine how much volume you can sustain. Measure your own ceiling rather than working from someone else's figure. Ramp volume gradually, record the request rate at which CAPTCHAs and 503s start appearing, and run below it.
Residential IPs are necessary but not sufficient. Amazon also checks TLS fingerprints, JavaScript execution environment, header consistency, and behavioral patterns. If you are using a standard Python HTTP library through a residential proxy, the TLS fingerprint alone identifies you as non-browser traffic. Use curl_cffi or a real browser automation tool.
For product pages and search results, well-configured HTTP requests with curl_cffi are faster and more efficient. Use headless Chrome only for pages that require JavaScript rendering to display data (some Amazon pages lazy-load content). Be aware that default Puppeteer and Playwright configurations are easily detected — you need stealth plugins and proper configuration.
Amazon reviews are paginated and require navigating through multiple pages per product. Use the /product-reviews/ URL pattern with pageNumber parameter for direct access. The same anti-bot techniques apply, but review pages tend to be less aggressively protected than search results or product detail pages.
The proxy types differ in how their addresses are allocated, not in a trust score you can look up anywhere. Datacenter ranges are registered to hosting providers and identifiable by ASN, which makes them the easiest class to filter. ISP proxies (static residential) are registered to consumer ISPs but hold one address per session. Residential and mobile addresses sit behind consumer ISPs and carrier-grade NAT, where many real subscribers share the same address. Remember that the IP is only one layer. A real-device connection also removes the fingerprint mismatch, because the browser making the request runs on the phone that owns the address.
Skip the Cat-and-Mouse Game
Archonum runs Chrome on real consumer smartphones, so the fingerprint is native and the exit IP belongs to the device making the request. No TLS spoofing, no fingerprint emulation, no proxy hop between the browser and the site.