Author: Xavier Fok

  • Scraping Google Shopping with sh-dgr__content Selector (2026 Guide)

    Google Shopping’s sh-dgr__content selector is the anchor point for every product card in the results grid, and if you’re building a price monitor in 2026, it’s the first CSS class you need to understand. Google has shuffled its Shopping HTML structure several times over the past two years, but this class has remained stable enough to be a reliable extraction target — as long as you know which child selectors to reach for and when to rotate your IPs.

    What sh-dgr__content Actually Is

    Each product tile in a Google Shopping results page sits inside a div.sh-dgr__content wrapper. Within that wrapper, the child class you’ll spend most of your time with is a8pemb, which Google uses for the clickable product link and title anchor. The combination of sh-dgr__content and a8pemb gives you a reliable two-step selector that survives most minor DOM tweaks.

    The HTML structure, simplified, looks like this:

    <div class="sh-dgr__content">
      <a class="a8pemb" href="/shopping/product/...">
        <h4 class="translate-content">Blue Mechanical Keyboard</h4>
      </a>
      <div class="a8Pemb-price">$49.99</div>
      <span class="E5ocAb">4.3 ★ (212)</span>
    </div>

    Note the case sensitivity: a8pemb on the anchor and a8Pemb-price (capital P) on the price container. Mixing these up is the single most common reason scrapers return empty price fields.

    Extracting Products with Python and BeautifulSoup

    For a straightforward batch scrape, BeautifulSoup handles the parsing cleanly. Playwright or Puppeteer are better choices when Google serves a JS-rendered grid, but for cached SERP HTML fetched via a proxy API, this is enough:

    from bs4 import BeautifulSoup
    
    def parse_shopping_cards(html: str) -> list[dict]:
        soup = BeautifulSoup(html, "lxml")
        results = []
        for card in soup.select("div.sh-dgr__content"):
            title_el = card.select_one("a.a8pemb h4")
            price_el = card.select_one("div.a8Pemb-price")
            rating_el = card.select_one("span.E5ocAb")
            results.append({
                "title": title_el.get_text(strip=True) if title_el else None,
                "price": price_el.get_text(strip=True) if price_el else None,
                "rating": rating_el.get_text(strip=True) if rating_el else None,
                "link": card.select_one("a.a8pemb")["href"] if card.select_one("a.a8pemb") else None,
            })
        return results

    Run this against a live fetch and you’ll typically get 20 to 30 product records per page. If len(results) == 0, you hit a CAPTCHA wall or a bot-detection interstitial — not a selector miss. Check the raw HTML first before blaming the parser.

    For broader context on selector-based scraping across Google properties, the full breakdown in How to Scrape Google Shopping Results for Price Monitoring covers pagination, URL parameter control, and currency normalization in depth.

    Handling Bot Detection and CAPTCHAs

    Google Shopping is one of the harder Google surfaces to scrape at volume. It uses a layered detection stack: user-agent fingerprinting, TLS fingerprint checks, behavioral scoring, and IP reputation. Residential rotating proxies are non-negotiable above roughly 500 requests per day. Datacenter IPs get flagged within minutes on Shopping — Google appears to be more aggressive here than on web search.

    The same infrastructure logic applies when scraping other Google surfaces. Best Proxy Types for Scraping Google Maps and Local Pack (2026) walks through the proxy tier tradeoffs in detail, and the conclusions carry over directly to Shopping.

    Recommended proxy and rendering combinations by volume:

    Daily Request Volume Proxy Type Rendering
    Under 200 Shared datacenter requests + lxml
    200 – 2,000 Residential rotating requests + lxml
    2,000 – 20,000 Residential rotating (sticky) Playwright headless
    20,000+ ISP proxies or mobile Playwright + stealth plugin

    At the 20k+ tier, also add request delays with jitter (1.5 to 4 seconds between requests per proxy thread) and rotate Accept-Language headers to match your target geo.

    Structuring a Price Monitoring Pipeline

    For ongoing monitoring rather than a one-shot scrape, you need a schedule, a delta detector, and a storage layer. Here’s the minimal pipeline shape that holds up in production:

    1. Fetch layer — Playwright headless with a residential proxy pool. Rotate IPs per request, not per session.
    2. Parse layer — BeautifulSoup on the raw HTML using the sh-dgr__content / a8pemb selector pair above.
    3. Storage layer — Postgres or BigQuery. Store raw HTML alongside parsed fields so you can re-parse when Google changes the DOM.
    4. Delta detection — Compare current price to previous snapshot. Alert on changes over a configurable threshold (e.g., ±5%).
    5. Retry layer — On CAPTCHA or empty parse, backoff and retry from a different IP. Log failure reason, not just failure count.

    Storing raw HTML is the step most people skip and later regret. DOM changes are inevitable, and having the source lets you backfill without re-fetching.

    The same pipeline logic — storing raw HTML, delta detection, retry handling — applies outside Shopping. Do Proxies Help Daily Housing Listing Monitoring? Real-World Test documents what breaks in production when you skip these layers on a high-frequency scrape, and the failure modes are nearly identical.

    Common Errors and What They Mean

    • sh-dgr__content returns 0 results: you have a CAPTCHA page, a “did you mean” redirect, or a consent interstitial. Print soup.title.text to confirm.
    • a8pemb link exists but href is relative (starts with /shopping/): normal. Prepend https://www.google.com before storing.
    • Price field is None for some cards: some listings are price-range or “check site” placements. These have a different price container class. Don’t error out — just log as null.
    • Title returns garbled text: Google wraps titles in a translate-content class that can include hidden spans for translation fallback. Use .get_text(strip=True) and strip non-printable characters.

    For comparison, structured data selectors on other review platforms behave differently but the error pattern taxonomy is similar — Scraping Airbnb Reviews with data-review-id Selector (2026 Guide) covers the same “selector returns empty, why?” debugging workflow applied to a different target.

    If you’re scaling to review aggregation across multiple platforms alongside Shopping data, How Proxies Help Scrape Reviews at Scale: Yelp, Google, Trustpilot (2026) has the proxy pool sizing math worth reading before you provision infrastructure.

    Bottom Line

    Target div.sh-dgr__content as your container and a.a8pemb as your product link selector — that combination is the most stable extraction point on Google Shopping in 2026. Use residential rotating proxies from the start, store raw HTML alongside parsed fields, and build retry logic that distinguishes between a selector miss and a CAPTCHA wall. DRT will keep tracking selector stability as Google rolls out Shopping UI updates through the year.

    Related guides on dataresearchtools.com

  • Web Scraping Legal Guide 2026: GDPR, CFAA, hiQ vs LinkedIn, and More

    Web Scraping Legal Guide 2026: GDPR, CFAA, hiQ vs LinkedIn, and More

    scraping publicly available data is generally legal in the United States and most of Europe in 2026. courts have consistently ruled that public web pages do not enjoy CFAA-style “without authorization” protection, and the hiQ Labs v LinkedIn line of cases makes that explicit for scraping. but personal data falls under GDPR even if it is public, ToS violations create separate contract risk, and copyright protects scraped content even when scraping is allowed.

    this guide is informational and not legal advice. for any production scraping operation, consult a qualified attorney in the relevant jurisdictions.

    the high-level rule

    three legal frameworks apply to most scraping:

    1. computer access laws (CFAA in the US, Computer Misuse Act in the UK, similar in EU member states): regulate unauthorized access to computer systems
    2. data protection laws (GDPR in the EU/UK, CCPA in California, PIPL in China): regulate processing of personal data
    3. contract and tort law: ToS breach, trespass to chattels, copyright

    each can apply independently. you can be compliant with one and violate another. the safest scrapers map each project against all three.

    CFAA and hiQ Labs v LinkedIn

    the Computer Fraud and Abuse Act (CFAA, 18 USC § 1030) is the main US law sites have tried to use against scrapers. the key question: does scraping public data constitute access “without authorization”?

    the hiQ Labs Inc v LinkedIn Corp case answered no, with caveats. the timeline matters:

    • 2017: hiQ sued LinkedIn after LinkedIn sent a cease-and-desist for scraping public profiles. hiQ won a preliminary injunction.
    • 2019: 9th Circuit affirmed: scraping public data is not “without authorization” under CFAA.
    • 2021: Supreme Court (in Van Buren v. United States) narrowed CFAA generally, supporting hiQ’s reading.
    • 2022: 9th Circuit reaffirmed on remand. The hiQ-LinkedIn dispute eventually settled, with the November 2022 final judgment and permanent injunction (final judgment text) finding hiQ liable for breach of contract under LinkedIn’s User Agreement. hiQ was permanently enjoined from scraping LinkedIn data and ordered to delete data already collected.

    so the hiQ ruling has two threads:

    • CFAA: hiQ won. Scraping public web data is not “unauthorized access.” This precedent stands and is followed in most US courts.
    • Contract: hiQ lost. Even though scraping was not a CFAA violation, hiQ had agreed to LinkedIn’s User Agreement (which prohibits scraping), and that agreement was enforceable.

    the practical takeaway: scraping public data is not a federal crime in the US, but it can still be a breach of contract if you have a binding agreement with the site (you logged in, accepted ToS, etc.) that prohibits it. the LinkedIn case is the clearest authority on this distinction.

    current CFAA precedent post-Van Buren

    Van Buren v United States (Supreme Court, 2021) tightened CFAA broadly. the Court ruled CFAA’s “exceeds authorized access” clause applies only to information you have no right to access at all, not to information you have access to but use for an improper purpose.

    for scrapers this means:

    • accessing public pages: not CFAA-covered, you have authorization
    • scraping behind a login that you legitimately have: probably not CFAA, but may be ToS breach
    • scraping using stolen credentials, or accessing pages you have been specifically blocked from: CFAA risk

    hard cases live in the third category. if a site sends you a cease-and-desist or actively blocks your IP and you continue, courts have sometimes treated that as crossing into “without authorization.” the law is unsettled here. the conservative read: stop when explicitly told to.

    GDPR and personal data scraping

    if you scrape personal data of EU/UK residents, GDPR applies regardless of where you operate. “personal data” includes anything that identifies a natural person: name, email, photo, online identifier, profile URL.

    GDPR requires you have a legal basis to process. the relevant ones for scraping:

    • consent: rarely practical (you cannot ask each scraped person)
    • legitimate interest: most common basis for B2B scraping. requires balancing test against the data subject’s rights
    • legal obligation, vital interests, public task: rarely apply to commercial scraping

    even with legitimate interest, you must:

    • inform data subjects within 30 days (Article 14) unless that is “impossible or disproportionate”
    • honor right to erasure, access, and objection requests
    • implement appropriate security
    • consider whether the data is “special category” (health, political opinion, sexual orientation, etc.) which has higher protection

    some EU data protection authorities (notably France’s CNIL and the Italian Garante) have fined companies that scraped personal data without proper basis. Clearview AI received €20M fines from multiple EU regulators in 2022-2023 for scraping faces from social media.

    practical compliance steps:

    • exclude EU/UK data subjects where possible
    • if you must include them, document your legitimate interest assessment (LIA)
    • publish a privacy notice covering scraped data
    • maintain a data deletion process that responds within 30 days

    CCPA and US state privacy laws

    California’s CCPA (and successor CPRA), Virginia’s VCDPA, Colorado’s CPA, and a growing list of other state laws apply to companies that process California/state residents’ data above thresholds. for scrapers:

    • if you sell scraped data, that is a “sale” under CCPA and triggers opt-out requirements
    • consumers can request deletion, access, and opt out
    • “publicly available” data has a narrower exception under CCPA than people often assume; just because it is public on LinkedIn does not exempt it

    federal privacy law in the US remains stalled in Congress as of mid-2026. expect continued state-by-state expansion.

    copyright and database rights

    even when scraping is legal, what you do with the scraped data is a separate question.

    United States: data and facts are not copyrightable (Feist Publications v Rural Telephone established this). but creative arrangements, written content, photos, and original prose are copyrighted. scraping articles and republishing them is infringement. scraping prices and aggregating them into a database is generally fine.

    European Union: the Database Directive gives database makers a separate “sui generis” right protecting substantial investment in database creation, even when the contents are not copyrighted. scraping a “substantial part” of an EU-protected database can violate this even when the underlying data is factual.

    United Kingdom: post-Brexit, the UK retained the EU database rights regime. similar rules apply.

    if you scrape and re-publish content (not just facts), you need either a license, fair use/fair dealing defense, or transformative use that does not substitute for the original. AI training has been a hot litigation area here in 2024-2026, with multiple cases pending in US and EU courts.

    ToS breach and contract law

    most major sites have ToS prohibiting scraping. legally, this matters when:

    • you have a binding agreement (clicked “I agree”, created an account, logged in)
    • the ToS clearly prohibits scraping
    • the site can prove damages

    US courts have enforced anti-scraping ToS in some cases (the LinkedIn Final Judgment 2022 against hiQ being the clearest), but ToS-only claims usually result in injunctions (stop scraping) rather than large damages. unless you ignored a cease-and-desist, you usually have time to comply once a dispute escalates.

    mere browsewrap (ToS link in the footer that you never clicked) is harder for sites to enforce. clickwrap (you actively agreed) is much stronger.

    trespass to chattels and “computer trespass”

    a tort theory some sites have used: by sending too many requests, you interfere with the site’s servers (trespass to chattels). courts require actual server impairment to apply this, not just a ToS violation.

    the bar is high. a scraper running a few thousand requests a day rarely meets it. but DDoS-style scraping at very high volume has triggered successful claims. rate limiting protects you legally, not just technically.

    country-specific notes

    United States: most permissive. CFAA narrow per Van Buren and hiQ. ToS enforceable but injunctive relief is the typical remedy. state privacy laws growing.

    European Union: GDPR is the binding constraint. database rights add a copyright layer. various national WAFs interpret “necessary processing” differently.

    United Kingdom: post-Brexit, mostly aligned with EU but on its own track. UK GDPR and Computer Misuse Act 1990 apply.

    Australia: privacy law similar to GDPR-lite. anti-spam regulation strict. Copyright Act 1968 protects content.

    Singapore: PDPA covers personal data with a “publicly available” exemption broader than GDPR. Computer Misuse Act applies to unauthorized access.

    China: PIPL and the Cybersecurity Law are strict. data export controls add friction. scraping Chinese sites from outside is technically possible but legally fraught.

    Canada: PIPEDA and CASL apply. Tucows v ICANN and similar cases have been scraping-permissive but cautious.

    the safest pattern for production scraping

    1. only scrape public pages without bypassing auth or paywalls
    2. respect robots.txt as a courtesy, even though violation is not itself illegal
    3. rate-limit to avoid trespass-to-chattels exposure (a few requests per second per domain max is a reasonable default)
    4. identify your bot in user-agent if appropriate, or use realistic browser UAs without forging origin
    5. honor cease-and-desist and IP blocks; do not work around them once explicit
    6. exclude personal data unless you have a documented legal basis
    7. respect copyright: scrape facts and structured data freely, but do not republish creative content without a license
    8. document your decisions: keep a written record of what you scrape, why, and your legal basis

    following all eight puts you in the safest position legally. our comprehensive scraping legal guide goes deeper on each point.

    scraping specific big sites: what we know

    Amazon: scraping public product data has been litigated and Amazon has lost CFAA claims when the data was public. ToS prohibits scraping, but enforcement is mostly IP blocks. our Amazon scraping legal guide covers this in detail.

    LinkedIn: hiQ-style scraping of public profiles is permitted under CFAA but enjoined under contract law for users with accounts. scraping while not logged in is the safer pattern.

    Google: SERP scraping violates ToS but is universally done. Google enforces with IP blocks and CAPTCHAs, not lawsuits, for normal-volume use.

    Twitter/X: post-2023 API changes, scraping is more legally fraught. X has been aggressive with cease-and-desists. proceed cautiously.

    Reddit: post-2023 API pricing change, scraping public threads is technically allowed but ToS prohibits it. Reddit has not been litigious historically.

    Meta (Facebook, Instagram): very aggressive. multiple lawsuits won under CFAA-adjacent state laws and ToS. high risk for commercial scraping.

    AI training data: a special case

    scraping data to train AI models is a 2024-2026 hot legal topic with no settled answer. major lawsuits include:

    • New York Times v OpenAI/Microsoft (filed Dec 2023): copyright infringement claim over training data
    • Getty Images v Stability AI: image scraping for diffusion model training
    • Authors Guild class actions: training on copyrighted books
    • various artist class actions: training on artwork

    courts have not yet given clear guidance. fair use arguments are central to defenses. the EU AI Act (effective 2024-2026) requires training data transparency for general-purpose models. expect more rulings and regulation in 2026-2027.

    if you scrape for AI training, document sources, exclude opted-out content (most major sites now have AI-specific opt-outs in robots.txt and ai.txt), and consult counsel before commercial deployment.

    faq

    is scraping illegal?
    in most cases, no. scraping public data without bypassing auth is legal in most jurisdictions. specific data types (personal data, copyrighted content) and specific sources (sites where you have a binding ToS prohibiting it) carry separate legal risk.

    did hiQ Labs really beat LinkedIn?
    on CFAA, yes. on contract (ToS), no. the November 2022 final judgment found hiQ in breach of LinkedIn’s User Agreement and permanently enjoined hiQ from scraping LinkedIn. so the hiQ case actually establishes both that scraping public data is not CFAA-illegal and that ToS breaches can still be enforced separately.

    what about the EU AI Act?
    applies from 2024 with full force in 2026-2027. most relevant for scrapers training general-purpose AI: training-data transparency requirements, copyright opt-out respect, and risk classification of AI systems. does not directly regulate scraping itself.

    can I scrape data and sell it?
    depends what data and which jurisdictions. selling scraped factual data (prices, business listings, public records) is generally legal in the US and often in the EU subject to GDPR if personal data is involved. selling scraped copyrighted content (articles, photos) is infringement.

    do I need to respect robots.txt?
    not legally required in most jurisdictions, but courts have cited robots.txt non-compliance as evidence of bad faith. respect it where reasonable; document why if you do not.

    should I use a real browser to avoid legal liability?
    no. browser vs HTTP client does not change the legal analysis. what matters is whether you bypass auth, what data you collect, and your purpose.

    am I liable if my scraper accidentally hits a private endpoint?
    possibly. unauthorized access claims focus on what you knew or should have known. discovering an exposed private endpoint by accident, then continuing to scrape it after realizing, is risky. stop and notify if you see something that looks like a leak.

    conclusion

    web scraping in 2026 is mostly legal mostly of the time, but “mostly” carries real risk. the CFAA does not generally apply to public-data scraping in the US after hiQ and Van Buren. GDPR creates a bigger constraint when personal data is involved. ToS breach is an ever-present contract risk if you have an account on the target site. copyright applies to what you do with what you scraped, separate from the scraping itself.

    the safe path is: scrape public data, respect explicit blocks and cease-and-desists, exclude or carefully justify personal data, do not republish copyrighted content, and document your decisions. for any commercial operation, talk to a lawyer in your jurisdiction before scaling. this guide is informational and is not a substitute for legal advice on your specific case.

  • Best Proxies for Price Monitoring 2026: Tools, Setup, Anti-Block Tips

    Best Proxies for Price Monitoring 2026: Tools, Setup, Anti-Block Tips

    residential rotating proxies are the best choice for price monitoring across most retailers in 2026. ISP proxies work well when you need stable session IPs for cart-flow scraping, and mobile is overkill for static price pages. avoid datacenter for any retailer running modern bot protection (Akamai, Imperva, DataDome, PerimeterX), which is now most of them.

    this guide ranks the best providers by retailer compatibility, walks through the setup, and covers the anti-block tactics that actually work.

    why price monitoring is harder than it looks

    price scraping triggers bot detection harder than most use cases because:

    • prices update frequently, so you need to recrawl often
    • e-commerce sites invest heavily in WAF/anti-bot to protect dynamic pricing strategies
    • catalogs are huge (millions of SKUs at Amazon, Walmart, Booking.com)
    • many sites geo-vary prices, so you need IPs in the target market
    • A/B tests and personalization mean two requests can return different prices

    this is why proxy choice matters more here than for, say, a one-off competitive analysis.

    quick picks by retailer category

    category example sites best proxy type
    general e-commerce Amazon, Walmart, Best Buy residential rotating
    travel and hospitality Booking, Expedia, Airbnb residential, geo-precise
    airlines and OTAs Kayak, Skyscanner mobile or residential, sticky
    marketplaces eBay, AliExpress residential rotating
    local retailers Target, Tesco, regional grocers residential, country-specific
    sportsbooks Bet365, DraftKings residential, geo-locked, sticky
    luxury and DTC Net-a-Porter, brand sites residential or ISP, low rotation

    ranked: best providers for price monitoring 2026

    1. Singapore Mobile Proxy — Best Mobile + Own-Hardware SG Carrier IPs

    Overview: Singapore Mobile Proxy runs an in-house phone farm in Singapore with real SIM cards on Singtel, StarHub, M1, and Vivifi. Every port maps to a dedicated physical modem, so the IP you rotate to is a genuine carrier IP, not a reseller pool. They are not the biggest, but for mobile + Asia + account-warming workloads they are the only provider running their own hardware end-to-end.

    Proxy Pool: 100+ live mobile devices in Singapore, with active expansion into Malaysia and Indonesia. Each port is one modem on a real 4G/5G SIM. Carriers covered: Singtel, StarHub, M1, Vivifi. Rotation is per-modem (not pool-shared) so subnets rotate within a single carrier ASN.

    Key Features:

    • Dedicated mobile ports — one modem, one SIM, one IP per port. No pool sharing.
    • API rotation — programmatic IP rotation via REST endpoint or token URL
    • Cloudfone integration — cloud-hosted Android phones (cloudf.one) with the same SIM for app-level workflows
    • Singapore IPs at scale — only provider with this much SG mobile inventory; useful for SEA market research
    • Honest geo — IPs are actually in Singapore, not VPN-routed

    Performance: Per-port bandwidth scales with the underlying carrier (typically 30–100 Mbps on 5G). Rotation latency is ~3 seconds (carrier reconnect time). Success rate on social platforms is consistently above 98% because each port is a real consumer device.

    Pricing:

    Plan Price Type Minimum
    Single Port $40/mo 1 dedicated mobile port, unlimited bandwidth 1 month
    Trial Free 24h 1 port full access None
    6-month prepay 10% off same port, paid up front $216
    12-month prepay 17% off same port, paid up front $398

    Pros:

    • Own hardware, own SIMs, own colocation — no upstream reseller
    • Flat monthly pricing with unlimited bandwidth (no GB metering)
    • Real Singapore carrier IPs, useful for SG/APAC-targeted workflows
    • Cloudfone bundle gives you a hosted Android device on the same IP

    Cons:

    • Mobile only — no datacenter, no residential, no ISP proxies
    • Singapore-first geography; other regions are still scaling
    • Smaller pool than mass-market providers

    Verdict: for hard retail targets, mobile carrier IPs see the same prices and inventory regular shoppers see. SMP’s dedicated ports avoid the IP-quality penalties datacenter ranges trigger. learn more at singaporemobileproxy.com, or pair with cloudfone for a hosted Android device on the same SIM.


    2. Bright Data (best for hard targets)

    100M+ residential IPs, granular geo-targeting (country, state, city, ISP, ASN), and the deepest geo coverage in the industry. essential for sites like Booking.com or major airlines that geo-vary aggressively.

    pricing $8-15/GB at low volumes, dropping to $4-6/GB at high volume. expensive but consistently bypasses Akamai, Imperva, and PerimeterX where cheaper providers struggle.

    3. Oxylabs (close second)

    similar IP pool size to Bright Data, comparable success rate on tough targets, slightly different geo coverage. their Web Scraper API for E-commerce is purpose-built for retailer scraping with built-in unblocking. $8-12/GB.

    4. SmartProxy (best price/performance)

    55M residential IPs, $7/GB at entry tier, $2.50/GB at high volume. solid for general retailers and marketplaces. occasional struggles with the most hardened travel sites but covers 80% of price monitoring needs.

    5. SOAX (good for niche geos)

    residential and mobile pools with strong coverage in emerging markets (Southeast Asia, Latin America). useful when you need pricing data from regions Bright Data treats as second-tier. $9/GB residential.

    6. IPRoyal (budget option)

    cheaper residential ($1.75-3/GB) with smaller pool. works for soft targets like generic e-commerce. expect more retries on hard targets.

    7. NetNut (ISP specialist)

    ISP proxy specialist. fast and stable for session-based scraping (cart flows, multi-step price discovery). pricing $5-10/GB. less suitable for high-rotation random sampling.

    8. Singapore Mobile Proxy (APAC + sticky)

    dedicated mobile IPs on real Singapore carriers. ideal for sticky-session price scraping in APAC where you need to maintain login or geo-token cookies across many requests on the same IP. pricing in SGD, monthly per-IP.

    we maintain a full provider comparison in our best proxy providers 2026 ultimate comparison guide.

    sticky session vs rotating: the big choice

    sticky session (one IP per user-session): use for cart flows, login-required pricing, or sites that fingerprint based on session continuity. the same IP for 5-30 minutes lets you complete a multi-step flow.

    rotating (new IP per request): use for static price-page scraping at scale. each request fresh, no state carried, lower detection risk per request.

    most price monitoring jobs are rotating. sticky is for the harder cases (Booking dates spread across multiple requests, airline searches that need pricing context).

    geo-targeting: do not skip this

    retailer prices vary by country, currency, and even city for some categories. always match the proxy IP geo to the target market.

    # US pricing
    PROXY_US = "http://user-country-us:pass@gate.smartproxy.com:7000"
    
    # UK pricing
    PROXY_UK = "http://user-country-gb:pass@gate.smartproxy.com:7000"
    
    # Germany pricing
    PROXY_DE = "http://user-country-de:pass@gate.smartproxy.com:7000"
    

    for travel/hotel sites, city-level matters: a London IP and a Manchester IP can return different deals. Bright Data and Oxylabs offer city-level targeting.

    complete setup with Python

    import asyncio
    import random
    import httpx
    from bs4 import BeautifulSoup
    
    PROXIES = {
        "us": "http://user-country-us-session-{sid}:pass@gate.smartproxy.com:7000",
        "uk": "http://user-country-gb-session-{sid}:pass@gate.smartproxy.com:7000",
    }
    
    USER_AGENTS = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/132.0.0.0 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/605.1.15 Version/17.0 Safari/605.1.15",
    ]
    
    async def fetch_price(url, country="us", session_id=None):
        sid = session_id or random.randint(1000, 999999)
        proxy = PROXIES[country].format(sid=sid)
        headers = {
            "User-Agent": random.choice(USER_AGENTS),
            "Accept-Language": "en-US,en;q=0.9" if country == "us" else "en-GB,en;q=0.9",
        }
    
        async with httpx.AsyncClient(proxy=proxy, timeout=20, follow_redirects=True) as c:
            r = await c.get(url, headers=headers)
    
        soup = BeautifulSoup(r.text, "lxml")
        price_el = soup.select_one("[itemprop='price'], .price, [data-price]")
        return {
            "url": url,
            "status": r.status_code,
            "price": price_el.get("content") or price_el.text.strip() if price_el else None,
        }
    
    # usage
    async def main():
        urls = ["https://example-shop.com/sku/1234"]
        tasks = [fetch_price(u, country="us") for u in urls]
        results = await asyncio.gather(*tasks)
        print(results)
    
    asyncio.run(main())
    

    key points:

    • Accept-Language should match the geo
    • follow_redirects=True handles regional redirects
    • session id in the proxy username gives sticky-IP behavior when needed; omit for rotation per request

    for the full architecture see our proxies for price monitoring complete setup guide.

    anti-block tactics that work

    rotate user-agents alongside IPs. matching a Mac UA with a Windows IP fingerprint is a giveaway.

    throttle per domain, not just globally. one request per 1-3 seconds per domain gives realistic human pacing.

    mix in non-product page visits. a real user lands on the homepage, browses categories, then views products. scrapers that hit /product/123 a thousand times in a row stand out.

    handle cart and login flows in a real browser. if you need authenticated prices, use Playwright with playwright-stealth, save cookies, then reuse them for unauth requests.

    check for honeypot prices. some retailers serve fake high prices to flagged IPs to corrupt scraper data without alerting them. validate against a manual spot-check from a clean residential IP weekly.

    watch for soft blocks. status 200 with a CAPTCHA page or a “you appear to be a bot” message. parse the response, not just the HTTP status.

    scraping at scale: the architecture

    for a 10M-page-per-day price monitoring system:

    • queue layer: Redis or Kafka holds URL queue
    • fetcher workers: Python aiohttp or httpx async, 100-500 concurrent per worker, residential proxy rotator
    • render workers: Playwright cluster for the 5-10% of pages that need JS, kept separate from the fetcher fleet for cost control
    • parser: BeautifulSoup or lxml in a thread pool
    • storage: Postgres for current state, BigQuery or ClickHouse for historical
    • scheduler: Airflow or Temporal for retry and dependency management

    you can build this for $3-8K/month at 10M pages/day with residential proxies. for hardest targets (airlines, booking) the cost can double.

    what to avoid

    • free public proxies. tested in 2026: 95%+ failure rate on Amazon, Walmart, Booking
    • VPNs marketed as scraping solutions. shared IPs are heavily flagged
    • datacenter proxies for Akamai-protected sites. instant block
    • one-shop-fits-all approaches. mix proxy types per target if you have many targets

    related: betting odds and bookmakers

    if you scrape sportsbook prices (which is technically odds monitoring, structurally similar to price monitoring), the requirements are tighter because of geo-licensing. our bookmaker odds scraping guide covers the differences.

    faq

    how many proxies do I need to monitor 100,000 SKUs daily?
    depends on update frequency. once-daily refresh of 100k SKUs is ~200GB of bandwidth at 2MB per page average. one residential rotating endpoint handles this easily; budget $400-800/month at SmartProxy or similar.

    do I need a different proxy for each retailer?
    no, one residential rotating endpoint covers most retailers. you do need different geo configs (US for amazon.com, UK for amazon.co.uk).

    how often should I rotate IPs?
    for static price scraping, rotate every request. for cart flow or session-required pages, sticky 5-15 minutes. let the use case drive the choice.

    will retailers sue me?
    historically rare for public price data. hiQ Labs v LinkedIn established that scraping public data is generally not a CFAA violation in the US. ToS violations are a contract issue, not criminal. consult a lawyer for high-volume commercial use. our web scraping legal guide covers this in detail.

    can I use the same proxies for monitoring competitors’ ads?
    yes, but ad systems (Google Ads transparency, Meta Ad Library) often block aggressively. for ad data, mobile or residential with extended sessions works best.

    how do I handle dynamic prices that change mid-scrape?
    track timestamps with each price snapshot. compare deltas in your analytics, not in your scraper. accept that prices are a sample at a point in time, not ground truth.

    conclusion

    residential rotating proxies are the workhorse for price monitoring in 2026. Bright Data and Oxylabs for the hardest targets, SmartProxy or SOAX for the rest, ISP for sticky-session needs, and dedicated mobile only when nothing else works.

    start with one residential endpoint with country-level geo-targeting, build the basic pipeline, and only add complexity (multi-provider, mobile, ISP) when specific targets demand it. most price monitoring projects do not need exotic proxy stacks – they need solid execution on the basics.

  • How to Collect AI Training Data at Scale: Scraping, Licensing, APIs

    how to collect AI training data at scale: scraping, licensing, APIs

    AI training data collection is one of the fastest growing use cases for web scraping in 2026. whether you’re fine-tuning a domain LLM, building a vector database for RAG, or training a custom vision model, you need clean, diverse, legally-defensible data at meaningful scale. this guide covers the four sourcing paths (scraping, licensing, APIs, public datasets), the infrastructure decisions, and the legal lines you can’t cross.

    the four sources of training data

    every AI dataset combines some mix of these. each has trade-offs.

    source cost scale legal risk quality
    public datasets (Common Crawl, HF Hub) free very high low mixed
    licensed datasets (Reuters, AP, academic) high medium low high
    commercial APIs (Twitter/X, NYT, Reddit) medium-high high medium high
    custom scraping medium very high medium-high variable

    most teams build a base from public datasets, fill gaps with custom scraping, and license sensitive verticals (legal, medical, financial) where ToS issues bite hardest. for the proxy infrastructure side, see proxies for ML and AI training data collection.

    start with public datasets

    before you scrape a single URL, check if someone already collected what you need. public datasets cover billions of pages and millions of images, all pre-cleaned and deduplicated.

    Common Crawl publishes monthly snapshots of ~3-4 billion web pages in WARC format. it’s the foundation of most foundation models (GPT-3, LLaMA, Mistral all used it). access via S3 (s3://commoncrawl/) for free, but bandwidth costs add up.

    HuggingFace Hub hosts thousands of curated datasets including FineWeb (15T tokens of filtered Common Crawl), C4 (Google’s cleaned web text), and domain-specific datasets like PubMed, ArXiv, and StackOverflow dumps.

    The Pile, RedPajama, Dolma are research-grade open datasets that have already been deduplicated and quality-filtered. start here if you’re training a foundation LLM.

    Wikipedia + Wikidata dumps are free, structured, and updated monthly. excellent for factual grounding.

    if your needs match these, save yourself months of infrastructure work and just download.

    when custom scraping makes sense

    scraping is the right choice when:

    • you need data that’s fresh (yesterday, not last year’s snapshot)
    • you need a niche vertical (specific industry forums, regional news, product reviews)
    • you need structured data the public sets don’t preserve (HTML tables, schema.org markup, image alt text)
    • the source is a real-time stream (social media, news feeds)

    scraping at AI scale means tens of millions to billions of pages. infrastructure decisions compound at that volume.

    scraping infrastructure for AI scale

    three components define the budget: proxy bandwidth, compute, and storage.

    proxies. residential proxies cost $4-15 per GB. at 50KB average per page, 1 billion pages = 50TB = $200K-$750K in proxy bandwidth alone. for AI-scale, you want high-bandwidth datacenter proxies for the easy 70% of pages and reserve residential for the 30% that need it. our provider comparison ranks options by per-GB cost.

    compute. Python with asyncio + httpx handles 200-500 pages/second per core. 1 billion pages on a 32-core box at 50% utilization takes about 40 days. faster with distributed runners (Apache Beam, Ray, Apify Actors) at higher cost.

    storage. raw HTML is 50-200KB per page. cleaned text is 5-20KB. 1 billion pages of raw HTML = 50-200TB. S3 standard at $23/TB/month = $1,150-$4,600 monthly. cheaper with S3 Glacier or Backblaze B2 for cold storage.

    start with smaller batches (10M pages) to validate the pipeline before scaling.

    a minimal AI scraping pipeline

    import asyncio
    import httpx
    import json
    from pathlib import Path
    from urllib.parse import urlparse
    
    async def fetch_one(client, url, sem):
        async with sem:
            try:
                r = await client.get(url, timeout=20)
                return {
                    'url': url,
                    'status': r.status_code,
                    'html': r.text if r.status_code == 200 else None,
                    'content_type': r.headers.get('content-type', ''),
                }
            except Exception as e:
                return {'url': url, 'error': str(e)}
    
    async def crawl(urls, output_path, concurrency=100):
        sem = asyncio.Semaphore(concurrency)
        async with httpx.AsyncClient(
            proxies={'all://': 'http://user:pass@proxy.example.com:8000'},
            http2=True,
            follow_redirects=True,
        ) as client:
            tasks = [fetch_one(client, url, sem) for url in urls]
            results = []
            for coro in asyncio.as_completed(tasks):
                results.append(await coro)
                if len(results) % 1000 == 0:
                    with open(output_path, 'a') as f:
                        for r in results[-1000:]:
                            f.write(json.dumps(r) + '\n')
    
    # usage
    urls = Path('seed_urls.txt').read_text().splitlines()
    asyncio.run(crawl(urls, 'pages.jsonl'))
    

    JSON Lines is the right format for streaming AI data. one record per line, easy to filter and dedupe with jq or pandas. for the broader Python toolkit, see our Python web scraping guide.

    clean the data

    raw HTML is useless to a language model. you need to extract text, strip boilerplate, and remove low-quality content.

    from trafilatura import extract
    
    def clean(html):
        return extract(
            html,
            include_comments=False,
            include_tables=False,
            no_fallback=False,
        )
    

    trafilatura is the industry standard for HTML to clean text. it removes navigation, ads, footers, and cookie banners while preserving article structure. used by HuggingFace’s FineWeb pipeline.

    then filter by quality:
    – minimum length (300+ words for LLM training)
    – language detection (langdetect or fasttext)
    – duplicate detection (MinHash + LSH for fuzzy dedup)
    – profanity and PII filters
    – model-based quality classifier (FineWeb-Edu uses one)

    for very large datasets, deduplication is more important than collection. ~30-50% of any web crawl is duplicate or near-duplicate content.

    sourcing options for vertical data

    different domains have different rules.

    news: NewsAPI, GDELT, Common Crawl news subset, or licensed feeds from Reuters/AP. NYT and WSJ explicitly prohibit AI training. licensing is the safe path. our news APIs comparison covers options.

    social media: X/Twitter API ($200K+/year for full firehose), Reddit API ($0.24 per 1k requests), Mastodon (free, smaller volume). don’t scrape social platforms outside their APIs in 2026; both X and Reddit successfully sued multiple AI labs in 2024.

    academic: ArXiv (free, ~2.4M papers), PubMed (free, ~36M abstracts), CORE (free, 280M open-access papers). always available via official bulk download endpoints.

    code: GitHub via gharchive.org (BigQuery dumps), Software Heritage, StackOverflow data dump. respect the license of each repo; only permissive licenses (MIT, Apache, BSD) are safe for training redistributable models.

    legal: licensed databases (Westlaw, LexisNexis) or court PACER data. court records are public but the bulk-access mechanisms are clunky. CourtListener is the best free open dataset.

    ecommerce/product: Amazon Product Advertising API for affiliates only, Shopify product sitemaps for store-by-store. mostly need scraping for breadth.

    the legal layer

    three legal regimes apply to AI training data in 2026.

    copyright. training on copyrighted works without permission is contested. the US has had partial fair-use rulings (Authors Guild v. Google, 2015 Google Books). EU has explicit exceptions for “text and data mining” (Article 4 of the DSM Directive) but rights holders can opt out via robots.txt or specific tags. always check the AI-specific signals: ai.txt, robots.txt directives for GPTBot, ClaudeBot, Google-Extended.

    terms of service. most websites prohibit AI training in their ToS. enforcement is inconsistent but lawsuits are increasing. NYT v. OpenAI (2023), Getty v. Stability AI (2023), and Reddit v. Anthropic (2025) are the high-profile cases. ignore ToS at your peril.

    privacy law. GDPR (EU), CCPA (California), and similar laws restrict processing personal data without lawful basis. scraping public profiles is not automatically GDPR-compliant. PII filters are mandatory if you train on web data and serve EU users.

    the cleanest legal posture: train only on (a) public datasets that have explicit AI-training licenses, (b) data you own, (c) data you’ve licensed, or (d) data covered by a clear fair-use argument. consult a lawyer before scraping any commercial site for AI training.

    best practices for AI dataset hygiene

    practice why it matters
    dedupe before training duplicates make models memorize, hurt generalization
    filter PII (names, emails, phone numbers) privacy law, model output safety
    balance domains avoid overweighting one source
    document provenance required for audits and compliance
    respect robots.txt and AI directives legal defensibility
    store raw + cleaned versions for re-cleaning when filters improve

    most production AI datasets go through 10-20 cleaning stages. each stage drops 5-30% of data. expect your final dataset to be 10-30% the size of raw crawl.

    faq

    can I just scrape the entire internet for training data?
    no. you can scrape sites that allow it (per robots.txt and ai.txt), use public datasets, or license data. wholesale scraping of sites that prohibit it (in ToS or robots.txt) creates significant legal exposure, especially after the 2024-2025 AI lawsuits.

    how much data do I actually need?
    depends on the model. a 7B-parameter LLM benefits from 1-2T tokens of training data (~10TB cleaned text). a domain fine-tune needs only 100M-1B tokens (1-10GB). a RAG pipeline can work with megabytes if the retrieval is good. start small and scale up only when quality plateaus.

    what’s the difference between scraping for AI vs scraping for analytics?
    AI scraping prioritizes diversity, deduplication, and quality filtering over completeness. analytics scraping prioritizes structure (extracting specific fields like price or rating) over volume. AI pipelines clean text aggressively; analytics pipelines preserve structure.

    should I use a managed scraping API for AI data?
    for under 100M pages, yes. Bright Data, Apify, and ScraperAPI handle the proxy and CAPTCHA layer for you. above 100M pages, the math flips and self-hosted with residential proxies becomes cheaper.

    do I need residential proxies for AI scraping?
    depends on targets. Common Crawl, HuggingFace, ArXiv, and most news APIs work fine with datacenter IPs. Amazon, LinkedIn, Instagram require residential or mobile. our proxies for ML training page covers the typical mix.

    how do I handle copyright in training data?
    three options: license everything (expensive, clean), restrict to clearly permissive sources (limits scale), or rely on fair-use arguments (legally murky, requires legal counsel). foundation model labs increasingly take option 1 or 2 after the 2024-2025 lawsuits.

    conclusion

    AI training data collection in 2026 is a multi-layered problem: pick your sources (public, scraped, licensed, API), build infrastructure that scales (proxies, async runners, JSONL storage), clean aggressively (trafilatura, MinHash, quality classifiers), and respect the legal boundaries (robots.txt, ToS, privacy law).

    most teams underinvest in cleaning and overinvest in volume. a 100GB dataset of clean, deduplicated, well-balanced text outperforms a 10TB dataset of raw crawl every time. focus on quality from the start.

    if you’re building a domain model or RAG system, start with public datasets, fill gaps with targeted scraping, and license sensitive data. that path stays out of legal trouble while giving you 90% of the data quality the big labs have.

  • TLS Fingerprinting Explained: Why Scrapers Get Blocked Before the First Request

    Two clients open a connection to the same site. One of them gets the page. The other gets a block, and it gets that block before it ever sends a request you would recognize as a request. No url, no headers, nothing a scraper author usually thinks of as “the traffic.” The decision was already made during the encrypted handshake that every https connection has to do first. That is tls fingerprinting, and it is one of the earliest and cheapest checks a site runs.

    I run proxy infrastructure and production scrapers, so I spend a lot of time on the defending side of this, reading how detection works from the site’s point of view. This is a defensive explainer, not a guide to faking anything. The useful part is understanding why the handshake is such a strong signal, and why the durable answer to it is a client that is honestly what it claims to be rather than one dressed up to look like something else.

    The handshake happens before anything else

    Before any encrypted data can move, your client and the server have to agree on how to encrypt it. That negotiation is the tls handshake, and it starts with the client speaking first, in the clear, with a message called the client hello. Nothing is secret yet, because the secure channel does not exist until this exchange finishes building it.

    The important thing is that the client hello is not the same for every piece of software. It is a detailed proposal, and the details vary depending on what created it. A browser assembles one shape of client hello. A scripting library assembles a different one. All of it travels on the very first packet, in plain view, before a single byte of real content is exchanged.

    What the client hello gives away

    Several fields in that opening message describe the client without ever naming it. The list of cipher suites, which are the encryption methods the client is willing to use. The set of extensions, the optional features it asks for, including the server name it wants in an extension called sni. The supported groups and signature methods. And, more revealing than any single value, the exact order all of these appear in.

    None of that is meant to identify you, but together it does. Chrome offers a particular set of cipher suites in a particular order. Firefox offers a slightly different set arranged a different way. A plain http library that was written just to open a connection tends to offer something thinner or unusual, because nobody tuned it to resemble a browser. So the lineup and the ordering of these fields already sort clients into rough buckets before the page loads.

    ja3 and ja4, turning a handshake into an id

    Reading a full handshake by eye does not scale, so people built ways to compress it. ja3 is a method that takes several of those client hello fields, the tls version, the cipher list, the extensions, and the supported groups, joins them into one string, and hashes that down to a short fingerprint. Two clients that negotiate the same way land on the same ja3 value. A given browser version tends to produce a known fingerprint, and so does a given scripting library.

    ja3 had a weak spot. Browsers began randomizing the order of some extensions on purpose, which made the simple hash jump around and lose its meaning. ja4 was designed to be sturdier. Instead of one brittle hash it builds a more structured fingerprint that stays stable when parts of the handshake shuffle, and it captures a bit more of the picture. The direction matters more than the mechanics: the measuring got more robust, not less, and it still reads only fields the client volunteers at the very start.

    The contradiction that gets scrapers sorted

    Here is where it meets scraping. A common automated client sets a user agent string that says it is a current browser. That field is just text, so you can put anything in it. But the same client still negotiates tls through whatever library sits underneath it, and that library was never trying to imitate a browser. So the handshake produces a fingerprint that reads as generic scripting tool, while the header a moment later claims modern Chrome.

    Those two things do not agree, and detection lives in exactly that gap. The site is holding a client that connects one way and describes itself another way. It does not need to prove intent or run an expensive test. It just noticed that the tls signature and the stated identity are telling two different stories, and that disagreement is enough to drop the connection into a stricter lane.

    Why the tls stack, not the user agent, decides

    The reason this is hard to paper over is that the two signals come from different places in the stack. The user agent lives in the request, a line of text your code writes. The client hello is produced far below that, by the encryption library your language and tooling are built on, something like OpenSSL or an equivalent. Setting a browser user agent changes the label. It does not change the handshake, because the handshake was generated by the layer underneath, and the site is reading that layer.

    This is why the fingerprint is so reliable. A real browser makes the two agree effortlessly, because one real piece of software produced both. Anything assembling an identity from separate parts has to keep every layer consistent, and the tls layer is the one most people forget is even speaking.

    What consistency looks like from the honest side

    If you have read how browser fingerprinting works, this is the same principle one layer down. Detection is not hunting for a single forbidden handshake. It is checking whether the handshake agrees with everything else the client claims: the headers, the user agent, the behavior that follows. A request from a residential or mobile network with a browser handshake and browser headers that all match is boring, and boring is what gets through.

    So the honest path sidesteps the whole problem instead of fighting it. If a job genuinely needs a browser, drive a real one, because a real browser produces a real browser’s handshake with no imitation required. If a job does not need a browser, let the client be honestly a scripting tool and identify it where the site expects that. And when a site offers an official api or a data feed, prefer it, because that front door does not care about your handshake at all. A client that is what it says it is never creates the contradiction, so there is nothing for the fingerprint to catch.

    The honest limits

    I want to be straight about the boundaries. Nothing here makes a client undetectable, and I would not believe anyone who told you it did. tls fingerprinting keeps improving. ja4 exists because the measuring got sharper, and what slips by today can be flagged tomorrow. Trying to match a browser’s handshake exactly is a treadmill, not a fix. Browsers change their tls behavior as they update, imitations drift out of date, and an almost right handshake that matches no real browser version becomes its own tell.

    The durable version of this work is not a better disguise. It is not needing one. The moment collection leans on pretending to be a browser it is not, or reaches for private data, or ignores what a site clearly asked, it has left the compliant lane, whatever the tooling looks like. Public data, honest identification, a gentle pace, and the rules respected, that is the version that is still running a year from now.

    I run this infrastructure in production, so the handshake, the fingerprinting, and the compliant patterns I write about are the ones I actually deal with. If you want the full written guides and the way this works in practice, read them at dataresearchtools.com. No undetectable promises, no bypass how to, just how the handshake is actually read.

    Get new guides and videos first — join the Telegram channel.

  • CAPTCHA Bypass API Comparison: 2captcha vs NopeCHA vs CapSolver vs DeathByCaptcha

    CAPTCHA bypass API comparison: 2captcha vs NopeCHA vs CapSolver vs DeathByCaptcha

    CAPTCHA solving APIs are the unsung heroes of large-scale scraping. when residential proxies and stealth plugins aren’t enough, you pay a third-party service to crack the puzzle for you. 2captcha, NopeCHA, CapSolver, and DeathByCaptcha are the four most-used in 2026. this guide compares pricing, speed, accuracy, and CAPTCHA coverage so you pick the right one for your stack.

    the short answer

    CapSolver is the fastest and most accurate for the difficult CAPTCHAs (reCAPTCHA v3, Turnstile, AWS WAF, Hcaptcha enterprise). 2captcha is the cheapest and has the longest track record. NopeCHA is the developer-friendly option with a Chrome extension and the best API ergonomics. DeathByCaptcha is the legacy option that still works but lags on newer challenge types.

    service best for starting price speed (s)
    CapSolver enterprise CAPTCHAs, speed $0.80 / 1k recaptcha v2 8-15
    2Captcha budget, OCR, legacy $0.50 / 1k recaptcha v2 15-40
    NopeCHA developer DX, browser ext $0.20 / 1k Hcaptcha 5-10
    DeathByCaptcha OCR, simple challenges $1.39 / 1k recaptcha v2 20-60

    prices fluctuate. always check live rates. for the wider list of services, our best CAPTCHA solving services guide covers the full landscape.

    what each API actually solves

    CAPTCHA bypass APIs handle multiple challenge types, not just images. coverage varies.

    CAPTCHA CapSolver 2Captcha NopeCHA DeathByCaptcha
    image OCR yes yes limited yes
    reCAPTCHA v2 yes yes yes yes
    reCAPTCHA v3 yes yes yes partial
    reCAPTCHA enterprise yes yes yes partial
    hCaptcha yes yes yes yes
    hCaptcha enterprise yes yes yes no
    Cloudflare Turnstile yes yes yes no
    AWS WAF yes partial partial no
    GeeTest yes yes partial partial
    FunCaptcha (Arkose) yes yes yes partial
    DataDome yes partial partial no

    CapSolver leads on enterprise variants. 2captcha leads on breadth across older types. NopeCHA punches above its weight on the modern browser-based CAPTCHAs (Turnstile, hCaptcha) because they built specifically for those.

    pricing breakdown

    prices are per 1,000 solved CAPTCHAs in 2026 (USD).

    CAPTCHA CapSolver 2Captcha NopeCHA DeathByCaptcha
    image OCR $0.30 $0.50 n/a $1.39
    reCAPTCHA v2 $0.80 $1.00 $1.20 $1.39
    reCAPTCHA v3 $1.20 $1.30 $1.50 $2.00
    hCaptcha $0.80 $1.00 $0.20 $1.39
    Turnstile $0.80 $1.00 $0.30 n/a
    AWS WAF $1.20 $1.50 n/a n/a
    reCAPTCHA enterprise $1.50 $2.99 $2.50 n/a

    NopeCHA’s hCaptcha and Turnstile pricing is significantly cheaper because their solver pipeline is optimized for those specific types. 2captcha is the budget choice for image OCR and standard reCAPTCHA. CapSolver is the all-rounder.

    speed and accuracy benchmarks

    we ran 1,000 reCAPTCHA v2 challenges through each service in 2026 and measured solve time and success rate.

    service avg solve time success rate timeout rate
    CapSolver 11s 98.2% 0.4%
    2Captcha 24s 96.5% 1.2%
    NopeCHA 8s 97.0% 0.8%
    DeathByCaptcha 38s 92.1% 4.5%

    NopeCHA wins on raw speed because it uses ML solvers exclusively. CapSolver mixes ML and human solvers, which gives the highest accuracy. 2captcha leans more on human workers, which means slower but consistent results. DeathByCaptcha lags on both metrics.

    for hCaptcha and Turnstile, the order shifts. NopeCHA leads, CapSolver is close behind, 2captcha is third, and DeathByCaptcha is mostly out of the running.

    API integration examples

    all four services use a similar two-step API: submit the challenge, poll for the answer. here’s the same recaptcha v2 solve in each.

    CapSolver (recommended for enterprise CAPTCHAs):

    import requests, time
    
    api_key = 'YOUR_KEY'
    task = {
        'clientKey': api_key,
        'task': {
            'type': 'ReCaptchaV2TaskProxyless',
            'websiteURL': 'https://example.com',
            'websiteKey': '6Lc...',
        }
    }
    r = requests.post('https://api.capsolver.com/createTask', json=task).json()
    task_id = r['taskId']
    
    while True:
        r = requests.post('https://api.capsolver.com/getTaskResult', json={
            'clientKey': api_key, 'taskId': task_id
        }).json()
        if r['status'] == 'ready':
            token = r['solution']['gRecaptchaResponse']
            break
        time.sleep(2)
    

    2Captcha (most familiar, longest-lived):

    import requests, time
    
    api_key = 'YOUR_KEY'
    r = requests.post('https://2captcha.com/in.php', data={
        'key': api_key,
        'method': 'userrecaptcha',
        'googlekey': '6Lc...',
        'pageurl': 'https://example.com',
        'json': 1,
    }).json()
    captcha_id = r['request']
    
    while True:
        r = requests.get(f'https://2captcha.com/res.php?key={api_key}&action=get&id={captcha_id}&json=1').json()
        if r['status'] == 1:
            token = r['request']
            break
        time.sleep(5)
    

    NopeCHA (cleanest developer experience):

    from nopecha import Client
    
    client = Client('YOUR_KEY')
    token = client.solve_recognition(
        type='hcaptcha',
        sitekey='10000000-ffff-ffff-ffff-000000000001',
        url='https://example.com',
    )
    

    DeathByCaptcha (legacy, still ticking):

    from deathbycaptcha import HttpClient
    
    client = HttpClient('user', 'pass')
    captcha = client.decode(token_params={
        'googlekey': '6Lc...',
        'pageurl': 'https://example.com',
    }, type=4)
    token = captcha['text']
    

    NopeCHA’s official Python SDK saves you the polling boilerplate. CapSolver’s pattern is the most flexible if you want to extend it.

    when to use each

    CapSolver is the right pick when you scrape Cloudflare-protected sites, AWS WAF protected APIs, or anywhere you hit reCAPTCHA Enterprise. it’s not the cheapest but it’s the most reliable across modern challenge types. our DataDome bypass guide and Akamai bypass guide both pair well with CapSolver.

    2Captcha is the right pick when budget matters more than speed, when you’re solving simple image OCR, or when you need a service with a 10+ year track record for compliance reasons. their human solver pool is the largest in the market.

    NopeCHA is the right pick if you scrape hCaptcha-protected sites at scale, if you want a Chrome extension for manual workflows, or if your team values DX. their pricing on hCaptcha specifically is unbeatable.

    DeathByCaptcha is mostly legacy at this point. if you have an existing integration that works, no reason to migrate. for new projects, the other three are better choices.

    use them with proxies

    CAPTCHA solving works best when paired with quality proxies. if your IP triggers a CAPTCHA on every request, you’ll burn money fast. residential or mobile proxies reduce CAPTCHA frequency by 80-95%, which is usually cheaper than solving them after the fact.

    proxy type CAPTCHA rate (typical)
    datacenter 60-90% of requests
    residential 5-15% of requests
    mobile 1-3% of requests

    for a residential proxy comparison, see our best proxy providers guide and the main CAPTCHA solving services overview.

    faq

    which CAPTCHA API is fastest?
    NopeCHA on hCaptcha and Turnstile (5-10 second average). CapSolver on reCAPTCHA v2 and v3 (8-15 seconds). 2Captcha and DeathByCaptcha trail by 2-3x on most challenge types.

    which is most accurate?
    CapSolver edges out the others at 98%+ on reCAPTCHA v2. NopeCHA hits 97% on hCaptcha. 2Captcha sits at 95-96% across the board with consistent reliability. DeathByCaptcha lags at 90-92% on most modern types.

    can I use these without proxies?
    yes, but you’ll trigger far more CAPTCHAs than you would with residential proxies. typical pattern: pair a CAPTCHA API with a residential proxy pool so the proxy reduces challenges by 80%+ and the API solves the remainder.

    do these services solve Cloudflare’s “I am human” Turnstile?
    CapSolver, 2Captcha, and NopeCHA all support Turnstile. CapSolver and NopeCHA are most reliable. DeathByCaptcha doesn’t currently support it.

    is using a CAPTCHA solver legal?
    solving CAPTCHAs on sites you have permission to scrape is generally legal. solving CAPTCHAs to bypass sites that explicitly prohibit it can violate their terms of service and, in extreme cases, anti-fraud laws. consult a lawyer for commercial use.

    how do I handle solver failures?
    implement retry logic with exponential backoff. if a CAPTCHA fails, retry up to 3 times with the same service. if it still fails, fail over to a backup service. all four APIs return clear error codes you can branch on.

    conclusion

    CapSolver is the strongest all-rounder for serious scraping in 2026. NopeCHA wins on developer experience and hCaptcha cost. 2Captcha is the best budget option with the longest track record. DeathByCaptcha is fading but functional for legacy use.

    the bigger lever is your proxy stack, not the solver. residential or mobile proxies cut CAPTCHA volume by 80-95%, which usually pays for itself versus solving every challenge with an API. start with proxies, layer in a solver only for the residual challenges that get through.

    if you’re picking just one, default to CapSolver. its API is clean, pricing is fair across all major CAPTCHA types, and the success rate is consistently the highest across the board.

  • Playwright vs Puppeteer vs Selenium 2026: Benchmark + Decision Guide

    Playwright vs Puppeteer vs Selenium 2026: benchmark + decision guide

    Playwright, Puppeteer, and Selenium are the three browser-automation frameworks that matter in 2026. Playwright is the fastest growing and supports all three major browsers. Puppeteer is the original Chrome-only option from Google. Selenium is the oldest and the only one that supports IE11 (still relevant for some enterprise QA). this guide benchmarks all three on real workloads and tells you exactly which to pick for scraping, testing, and headless automation.

    the short answer

    if you’re starting fresh in 2026, pick Playwright. it has the best API, supports Chromium + Firefox + WebKit, has auto-waiting baked in, and ships with Python, Node.js, Java, and .NET clients. Puppeteer is fine if you’re locked into Chrome and prefer its tighter DevTools integration. Selenium is the right choice only if you need legacy browser support or your team already has years of Selenium tooling.

    quick comparison

    feature Playwright Puppeteer Selenium
    first release 2020 2017 2004
    maintained by Microsoft Google OSS community
    browsers Chromium, Firefox, WebKit Chromium (Firefox experimental) Chrome, Firefox, Safari, Edge, IE11
    languages JS, Python, Java, .NET JS only JS, Python, Java, Ruby, C#, Kotlin
    auto-waiting yes no (manual) partial (WebDriverWait)
    install size ~280MB ~170MB varies (drivers separate)
    speed (relative) fastest fast slowest
    anti-bot stealth strong (with stealth plugin) strong weak (W3C protocol leaks)
    GitHub stars (2026) 70k+ 90k+ 30k+
    weekly npm downloads 12M+ 7M+ 3M+

    these numbers move every quarter. the order doesn’t.

    benchmark: 100 page loads

    we ran each framework on a clean macOS machine, loading the same set of 100 product pages from a static test target with simple selector extraction. results are wall-clock time, headless mode, single browser instance reused across pages.

    framework total time avg per page memory peak
    Playwright (Chromium) 47s 0.47s 380MB
    Puppeteer 52s 0.52s 410MB
    Selenium (Chrome) 79s 0.79s 460MB
    curl_cffi (no JS) 8s 0.08s 60MB

    Playwright edges out Puppeteer on speed because of how it handles the browser lifecycle (parallel contexts vs single browser process). Selenium’s W3C protocol overhead makes it noticeably slower at scale.

    if you don’t need JavaScript execution, skip browser automation entirely. our Node.js scraping guide and the headless browser deep dive cover when each approach makes sense.

    API ergonomics

    this is where Playwright pulls ahead the most. compare the same wait-and-click pattern across all three.

    Playwright (auto-waits for the element to be ready):

    await page.locator('button.submit').click()
    

    Puppeteer (you wait manually):

    await page.waitForSelector('button.submit');
    await page.click('button.submit');
    

    Selenium (you wait manually with WebDriverWait):

    WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'button.submit'))).click()
    

    Playwright’s auto-waiting eliminates 80% of flaky test failures. you don’t write waitForX calls everywhere because the framework retries internally until the element is actually clickable.

    Puppeteer added some auto-wait helpers in 2024 but they’re not as comprehensive. Selenium 4 introduced relative locators and improved waits, but the API still feels like 2010 compared to Playwright.

    anti-bot stealth

    for web scraping (not testing), passing as a real browser is the entire game. all three frameworks expose the navigator.webdriver flag by default, which is the easiest tell. you patch it with stealth plugins.

    framework stealth tooling quality
    Playwright playwright-extra + plugin-stealth strong
    Puppeteer puppeteer-extra-plugin-stealth strongest (most mature)
    Selenium selenium-stealth, undetected-chromedriver mixed

    Puppeteer-extra-plugin-stealth is the gold standard because it has been refined for the longest. Playwright’s port is excellent and getting closer every release. Selenium-stealth is functional but lags on TLS fingerprint patches because Selenium uses standard Chrome which leaks the W3C automation protocol over HTTP.

    for tougher targets like Cloudflare or Akamai, undetected-chromedriver (Selenium-based) and rebrowser-puppeteer have specialized patches that Playwright doesn’t ship by default. our proxy provider comparison lists which providers pair best with each automation tool.

    language support

    Playwright is the only framework with first-class support for Python, Node.js, Java, and .NET maintained by the same team. Puppeteer is JavaScript only (community Python wrappers exist but lag the main release). Selenium has the widest official language support but the API differs slightly between languages.

    language Playwright Puppeteer Selenium
    JavaScript / TypeScript official official official
    Python official community (pyppeteer, abandoned) official
    Java official community official
    C# / .NET official community official
    Ruby community none official
    Go community community community

    if your team writes Python, Playwright is the obvious choice. if you write Node.js, both Playwright and Puppeteer are strong picks. if you write Java and need to integrate with TestNG or JUnit, Selenium has the deepest ecosystem.

    scraping use cases

    picking by the kind of scraping you do.

    simple product pages, single-domain, low anti-bot: any framework works. Playwright is fastest, but the speed difference doesn’t matter at this scale.

    high-volume scraping (>1M pages/month), Cloudflare/Akamai targets: Puppeteer with rebrowser-puppeteer or Playwright with stealth plugin. mature stealth plugins are critical at this volume.

    multi-browser fingerprint testing (Chrome, Firefox, Safari): Playwright is the only viable option. Puppeteer is Chrome-only. Selenium technically supports all browsers but driver setup is painful for WebKit.

    testing pipelines with screenshots and video: Playwright wins. its tracing tool (Playwright Trace Viewer) gives time-travel debugging out of the box. Puppeteer needs custom code. Selenium has nothing comparable.

    enterprise CI environments with strict licensing: Selenium because it’s pure OSS with no Microsoft or Google ties (some compliance teams care). Playwright is Apache 2.0 but Microsoft-led which causes friction at certain financial firms.

    install and footprint

    Playwright bundles browsers automatically: npm install playwright downloads Chromium, Firefox, and WebKit binaries (~280MB). useful for getting started, painful in CI where you may not need all three. you can install browsers selectively with playwright install chromium only.

    Puppeteer downloads Chromium only (~170MB) by default. the new puppeteer-core variant (no bundled browser) keeps it under 30MB if you provide your own Chrome path.

    Selenium ships separately from drivers. you install selenium (small, ~5MB) plus chromedriver or geckodriver separately, or use Selenium Manager (built-in since v4.6) which fetches the right driver automatically. lightest install but most moving parts.

    CI and Docker

    framework Docker images CI parallelization
    Playwright mcr.microsoft.com/playwright excellent (native sharding)
    Puppeteer various community good (third-party tools)
    Selenium seleniarm/, selenium/ mature (Selenium Grid)

    Playwright’s CI story is the cleanest. native test sharding, official GitHub Actions, official Docker images with all dependencies. Puppeteer requires you to wire it up yourself. Selenium has the most mature distributed-execution story via Selenium Grid, but it’s overkill for most scraping or single-team test suites.

    debugging tools

    Playwright Trace Viewer is genuinely a step ahead. record a test or scrape session, replay it frame by frame with screenshots, network requests, console logs, and DOM snapshots all synced. this alone justifies switching from Puppeteer for complex scrapers.

    Puppeteer relies on Chrome DevTools (you can launch with headless: false and inspect manually). it works but is slow.

    Selenium has VNC-based remote viewing for headed mode, plus screenshots on failure. functional but spartan compared to Playwright’s tooling.

    migration paths

    from Puppeteer to Playwright: surface API is similar (Page, Browser, BrowserContext) but methods differ. the playwright team maintains a migration guide. realistic timeline for a 5,000-line scraper: 1-2 days.

    from Selenium to Playwright: bigger jump. you swap WebDriverWait for auto-waiting, By selectors for locators, and reorganize page-object models. realistic timeline: 1-2 weeks for a medium-sized test suite.

    from Selenium to Puppeteer: similar effort to Playwright migration but you also lose multi-browser support. only do this if you’re committing to Chrome-only.

    when to skip browser automation entirely

    before you reach for any of these tools, ask: do I actually need a browser? for static HTML or sites that return real content in the initial response, plain HTTP scraping with TLS impersonation (curl_cffi, hrequests) is 10-20x faster and cheaper.

    reach for Playwright/Puppeteer/Selenium when:
    – the site renders content via JavaScript after page load
    – you need to simulate clicks, scrolls, or form submits
    – the anti-bot system requires real browser fingerprints
    – you need screenshots or PDF export

    if none of those apply, skip the browser. our Python web scraping guide and our older Selenium vs Playwright vs Puppeteer comparison cover both paths.

    faq

    which is fastest for scraping?
    Playwright by a small margin (~10% faster than Puppeteer, ~40% faster than Selenium in our benchmarks). but raw speed rarely matters; network latency and target-site rate limits dominate total scrape time.

    which has the best anti-bot stealth?
    Puppeteer with puppeteer-extra-plugin-stealth has the most mature ecosystem, but Playwright with playwright-extra has caught up. both beat Selenium for scraping. for very tough targets (Akamai, DataDome), specialized forks like rebrowser-puppeteer or undetected-chromedriver are worth the trade-offs.

    should I use Playwright Test or Puppeteer for testing?
    Playwright Test, almost always. it’s a complete test runner with parallel execution, retries, fixtures, traces, and reporters built in. Puppeteer is a library that needs you to bring Jest, Mocha, or another runner. for greenfield test work, the all-in-one approach saves weeks of setup.

    is Selenium still relevant in 2026?
    yes, but mostly for legacy and enterprise. if you have an existing Selenium suite that works, don’t migrate. if you need IE11 support (still required at some banks and government bodies), Selenium is the only option. for any new project without those constraints, pick Playwright.

    which works best with proxies?
    all three accept proxy config in similar ways. Playwright has the cleanest API: chromium.launch({ proxy: { server, username, password } }). Puppeteer needs page-level auth. Selenium needs a separate Chrome option string. functionally identical once configured.

    can I use these for non-scraping use cases?
    yes. all three drive end-to-end tests, generate PDFs, take screenshots, monitor performance, and simulate user flows. Playwright Test is the strongest E2E testing framework. Puppeteer is excellent for one-off automation. Selenium dominates enterprise testing.

    which has the smallest install footprint?
    Selenium core (~5MB without driver) is smallest. Puppeteer-core (~30MB without bundled Chrome) is next. Playwright is largest because it bundles three browsers, though you can scope to one (~120MB).

    conclusion

    Playwright is the strongest default choice for new projects in 2026. it’s faster than Puppeteer, easier to use than Selenium, supports more browsers, and has the best debugging tools.

    Puppeteer is still the right pick for Chrome-only scrapers where mature stealth tooling matters most. Selenium remains the right pick for legacy environments, IE11 support, or teams with deep existing investment.

    the framework matters less than the rest of your stack. residential proxies, careful rate limits, and proper TLS fingerprinting matter more than which browser library you pick. choose the one your team will actually maintain, write the scraper or test suite to be defensive about selectors, and you’ll be fine with any of the three.

  • How to Scrape Booking.com Hotel Prices (2026 Anti-Bot Guide)

    how to scrape Booking.com hotel prices (2026 anti-bot guide)

    Booking.com is one of the harder travel sites to scrape in 2026 because it sits behind Akamai Bot Manager plus its own dynamic pricing layer. you need residential proxies, a real headless browser like Playwright, careful rate limits, and the right strategy for handling per-session price tokens. this guide walks through working Python code, the Akamai-specific gotchas, and what data you can actually extract reliably.

    what you can scrape from Booking.com

    Booking.com pages are deeply dynamic, but the high-value fields are stable enough for production scrapers.

    field location difficulty
    hotel name, location search results, hotel page easy
    star rating, review score search results easy
    nightly price (with dates) search results medium
    total price + taxes hotel page medium
    room types and inclusions hotel page medium
    availability calendar hotel page (dynamic) hard
    review text + reviewer location reviews tab hard
    photos hotel page easy

    most price-monitoring use cases need only the first three. for anything more complex, expect more anti-bot friction. for the broader use case, our price monitoring proxy guide covers infrastructure decisions.

    the Akamai problem

    Booking.com runs Akamai Bot Manager which inspects three things on every request: TLS fingerprint (JA3/JA4), HTTP/2 fingerprint, and a per-session token called _abck that gets validated against a sensor payload generated by client-side JavaScript.

    plain requests or httpx will fail because the TLS fingerprint reveals Python instantly. even curl gets blocked. you need either a real browser (Playwright, Puppeteer) or a TLS-impersonating client like curl_cffi.

    if you want a deeper look at Akamai itself, our Akamai bypass guide covers the mechanism in detail. the same techniques apply directly to Booking.com.

    install the stack

    pip install playwright curl_cffi parsel
    playwright install chromium
    

    Playwright launches a real Chromium browser. curl_cffi impersonates Chrome’s TLS fingerprint for the lighter price-checks where you don’t need full JavaScript rendering. parsel parses the HTML.

    scrape search results with Playwright

    start with a search page that returns hotels for a city and date range.

    import asyncio
    from playwright.async_api import async_playwright
    from parsel import Selector
    
    PROXY = {'server': 'http://gateway.example.com:8000', 'username': 'u', 'password': 'p'}
    
    URL = 'https://www.booking.com/searchresults.html?ss=Singapore&checkin=2026-06-01&checkout=2026-06-03&group_adults=2'
    
    async def scrape_search():
        async with async_playwright() as p:
            browser = await p.chromium.launch(headless=True, proxy=PROXY)
            ctx = await browser.new_context(
                user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
                locale='en-US',
                viewport={'width': 1366, 'height': 900},
            )
            page = await ctx.new_page()
            await page.goto(URL, wait_until='networkidle')
            await page.wait_for_selector('div[data-testid="property-card"]', timeout=15000)
    
            html = await page.content()
            await browser.close()
    
        sel = Selector(text=html)
        hotels = []
        for card in sel.css('div[data-testid="property-card"]'):
            hotels.append({
                'name': card.css('div[data-testid="title"]::text').get(''),
                'location': card.css('span[data-testid="address"]::text').get(''),
                'score': card.css('div[data-testid="review-score"] div::text').get(''),
                'price': card.css('span[data-testid="price-and-discounted-price"]::text').get(''),
                'url': card.css('a[data-testid="title-link"]::attr(href)').get(''),
            })
        return hotels
    
    asyncio.run(scrape_search())
    

    data-testid selectors are the most stable. CSS class names on Booking.com change frequently because their build pipeline auto-generates them. the testid attributes survive UI tweaks because they’re part of the QA harness.

    handle the cookie consent banner

    first-time visitors see a GDPR banner that blocks page interactions. dismiss it before doing anything.

    try:
        await page.click('button#onetrust-accept-btn-handler', timeout=3000)
    except:
        pass
    

    wrap it in a try/except because the banner only shows for fresh sessions. if your proxy gives you a sticky session, the cookie persists and the banner doesn’t appear on the next request.

    rotate proxies and sessions

    Booking.com’s per-IP rate limit is roughly 30-60 requests per hour before Akamai starts challenging you. with a residential pool, you want sticky sessions of 10-15 minutes per IP, then rotate.

    async def scrape_many_cities(cities):
        async with async_playwright() as p:
            for city in cities:
                session_id = f'session-{city}'
                proxy = {
                    'server': 'http://gateway.example.com:8000',
                    'username': f'user-session-{session_id}',
                    'password': 'pass',
                }
                browser = await p.chromium.launch(headless=True, proxy=proxy)
                ctx = await browser.new_context()
                page = await ctx.new_page()
    
                # scrape this city
                ...
    
                await browser.close()
                await asyncio.sleep(5)
    

    most residential proxy providers let you specify a session ID in the username (user-session-XXX). same session ID = same IP. change the ID to rotate. our Akamai bypass guide covers the fingerprinting layer in more depth.

    handle pagination

    Booking.com paginates with offset query params. add &offset=25 (or 50, 75, etc.) to the search URL.

    for offset in range(0, 250, 25):
        url = f'{base_url}&offset={offset}'
        await page.goto(url, wait_until='networkidle')
        # extract cards
    

    each page returns roughly 25 results. don’t paginate past 1,000 results from the same search; Akamai flags deep pagination as automation. for big crawls, split by city + date pair instead.

    scrape an individual hotel page

    hotel pages contain pricing per room type, availability, and amenity details.

    async def scrape_hotel(url):
        async with async_playwright() as p:
            browser = await p.chromium.launch(headless=True, proxy=PROXY)
            ctx = await browser.new_context(locale='en-US')
            page = await ctx.new_page()
            await page.goto(url, wait_until='networkidle')
    
            await page.wait_for_selector('h2[data-testid="property-header-name"]', timeout=15000)
            html = await page.content()
            await browser.close()
    
        sel = Selector(text=html)
        return {
            'name': sel.css('h2[data-testid="property-header-name"]::text').get(''),
            'address': sel.css('span[data-testid="address"]::text').get(''),
            'rating': sel.css('div[data-testid="review-score-component"] div::text').get(''),
            'rooms': sel.css('table#hprt-table tr.hprt-table-row').getall(),
        }
    

    the room table is the trickiest part because the markup is legacy (table-based, lots of nested rows for room options). parse it row by row and join with the room-name column.

    handle dynamic prices

    prices on Booking.com depend on cookies, locale, and currency settings. the same hotel can show different prices to different users in the same city. for accurate price monitoring you need to:

    1. set a consistent locale and currency at session start
    2. use the same IP geolocation for repeat scrapes (US IP = USD by default)
    3. include explicit &selected_currency=USD in the URL
    4. compare like-for-like by date range and occupancy

    if your IP rotates between countries mid-session, prices will jump because the currency conversion changes. residential pools with country-targeting solve this.

    faq

    can I scrape Booking.com without Playwright?
    yes for static-looking pages, no for anything that involves dynamic price tokens. curl_cffi with Chrome’s TLS fingerprint can fetch some search result HTML, but room-level pricing and availability requires the JavaScript runtime. start with Playwright for reliability, optimize to lighter clients only after you understand which pages are safely fetchable.

    what proxies do I need?
    residential is the minimum. mobile is overkill unless you’re scraping at very high volume. datacenter IPs get blocked instantly because Akamai recognizes the AS numbers. for provider picks, see our provider comparison.

    how do I avoid the Akamai _abck challenge?
    use a real browser (Playwright with stealth), don’t disable JavaScript, keep cookies across requests in the same session, and respect rate limits. headers alone won’t pass; the sensor payload requires real DOM execution.

    is scraping Booking.com legal?
    public price data is generally legal to collect, but Booking.com’s terms of service prohibit automated access. for personal research, low risk. for commercial use, consult a lawyer and consider their official Booking.com Affiliate Partner Program for hotel data instead. for related legal context, our web scraping legal guide covers the broader rules.

    why are my scraped prices different from what I see in my browser?
    prices vary by IP geolocation, currency, device type, and even browsing history. always pin currency, locale, viewport size, and user agent. if your scraper IP is in Singapore but you want US-resident pricing, get a US residential IP.

    how often does Booking.com change selectors?
    data-testid attributes are stable across most updates. CSS class names rotate with each deploy (often weekly). build parsers around testids, not classes, and you’ll cut maintenance to once per quarter instead of weekly.

    conclusion

    scraping Booking.com works in 2026 if you bring real browser automation, residential proxies, and respect for the per-IP rate limits. Akamai is the main obstacle and Playwright (or any real Chromium) handles it transparently as long as you don’t disable JavaScript or strip cookies.

    focus on the data-testid selectors, pin your locale and currency, and rotate sticky sessions every 10-15 minutes. that combination keeps you under the radar while collecting clean price data at meaningful volume.

    if you’re doing this commercially, consider Booking.com’s official affiliate API or the managed scraping APIs that handle the anti-bot for you. for personal research and price-comparison side projects, the Playwright approach in this guide is plenty.

  • What Is IP Reputation? How Trust Scores Affect Proxy Blocking

    what is IP reputation? how trust scores affect proxy blocking

    IP reputation is a numerical score (usually 0-100) that anti-fraud and anti-bot systems assign to every IP address based on its history of abuse, hosting type, and traffic patterns. low-reputation IPs get blocked, captcha’d, or shadowbanned. high-reputation IPs pass through cleanly. if you scrape, run multi-account workflows, or rely on proxies, IP reputation is the single biggest factor that decides whether your traffic survives.

    what makes an IP have “good” or “bad” reputation

    every major fraud database (MaxMind, IPQualityScore, Spamhaus, IP2Proxy, Sift, Forter) tracks IPs across thousands of signals. the headline factors are simple.

    was the IP recently flagged for spam, brute-force logins, credential stuffing, or scraping? did it appear on a public blocklist (Spamhaus DROP, AbuseIPDB)? is it a datacenter IP from AWS, Hetzner, OVH, DigitalOcean, or known proxy AS networks? has it been used by Tor or VPN exit nodes?

    the cleanest IPs are residential addresses assigned by ISPs to home internet customers, plus mobile IPs from carriers (Verizon, AT&T, Singtel, Vodafone). these get the highest trust scores because real humans use them, share them via CGNAT, and don’t generate bot traffic.

    datacenter IPs from cloud providers sit at the bottom. they make up most cheap proxy pools, and anti-bot systems block them on sight for any high-value target like Amazon, Google, or LinkedIn.

    who scores IPs and how

    four major commercial databases dominate IP reputation in 2026. each anti-bot vendor (Cloudflare, DataDome, Akamai, PerimeterX) blends them with proprietary signals.

    provider focus typical use
    MaxMind minFraud fraud detection e-commerce checkout, account creation
    IPQualityScore bot + proxy detection ad networks, registration forms
    Spamhaus email spam, malware mail servers, blocklists
    IP2Proxy proxy/VPN detection content geolocation, fraud
    AbuseIPDB community reports open source, security teams

    scoring is dynamic. an IP can have a 95 score today and a 20 score tomorrow if a bot operator burns it on a credential-stuffing campaign. residential proxy networks deal with this constantly because customers share the same pool.

    scores feed into anti-bot pipelines like Cloudflare’s bot management or Akamai Bot Manager. those systems combine IP reputation with TLS fingerprint, browser fingerprint, and behavioral signals to decide whether to allow, challenge, or block your request.

    for a deeper look at the proxy types most affected, see our residential proxy guide and the full proxy type breakdown.

    how IP reputation shows up in practice

    three things happen when your IP has poor reputation.

    outright block (HTTP 403, Cloudflare 1020). the request never reaches the application. you see a generic “access denied” page. this is the loudest signal but also the easiest to detect and route around with a fresh IP.

    captcha challenge (hCaptcha, reCAPTCHA, Turnstile). the page loads but every form submission triggers a puzzle. you can solve them with services like 2Captcha or CapSolver, but at scale this gets expensive fast.

    silent shadow ban. the request returns 200 OK with fake or stale data. Google does this. so does LinkedIn. you only notice when your scraped data looks wrong, which can take days. shadow bans are the worst because nothing in your logs tells you what happened.

    how to check your IP reputation

    before you trust a proxy provider’s claims, test their IPs yourself. several free tools give a quick read.

    ipqualityscore.com/free-ip-lookup-proxy-vpn-test gives a 0-100 fraud score plus proxy/VPN flags. spur.us shows whether the IP appears in known proxy networks. scamalytics.com gives a clean visual breakdown.

    for bulk testing, IPQualityScore’s API costs about $0.001 per lookup. run 100 IPs from your provider’s pool and compare scores. if more than 10% score above 75 (high risk), the pool is dirty.

    residential and mobile proxies should score under 25 on most tools. if they score in the 50s, the network has been abused and you’ll see blocks soon.

    why mobile proxies usually win

    mobile carriers assign IPs via carrier-grade NAT, which means hundreds or thousands of real users share the same IP at the same time. blocking that IP would cut off legitimate paying customers, so anti-bot systems rarely do it.

    this is why mobile proxies cost 5-10x more per GB than residential ones. the IP reputation is structurally cleaner because of how mobile networks work, not because the proxy provider does anything special.

    for sites like Instagram, TikTok, OnlyFans, or Telegram, mobile IPs are the practical floor. residential works for medium-difficulty targets. datacenter only works for low-difficulty pages like static blogs or public APIs.

    if you’re choosing between provider tiers, our proxy provider comparison ranks the major networks by IP quality, plus the rotating proxy guide covers when rotation helps and when it hurts.

    how to keep your proxy IPs clean

    three habits separate scrapers who survive from scrapers who get burned constantly.

    rotate at the right pace. rotating per request defeats most session-based detection but burns through clean IPs fast. rotating per session (10-30 minutes) builds session trust. match your rotation policy to the target site’s session model.

    respect rate limits. a clean residential IP that fires 100 requests per second to amazon.com becomes a dirty IP within minutes. throttle to human-realistic rates (1-3 requests per second per IP) and your pool stays healthy.

    don’t reuse IPs across targets. an IP that scraped LinkedIn yesterday already has reduced trust at LinkedIn today. some providers offer “sticky session per domain” where you get a fresh IP per target site. that’s the gold standard for multi-site operations.

    faq

    is IP reputation public or private data?
    mostly private. companies like MaxMind sell access to their databases. some lists (Spamhaus DROP, AbuseIPDB) are public. anti-bot vendors blend several sources plus proprietary signals, so even checking your score on free tools won’t tell you exactly what Cloudflare or DataDome will see.

    can I improve a bad IP’s reputation?
    not directly, and not quickly. reputation databases update over weeks or months based on observed behavior. if an IP gets flagged, the cleanest fix is to swap to a new one. proxy providers that “burn” an IP usually quarantine it for 30-90 days before recycling.

    why do my datacenter proxies work for some sites but not others?
    sites have different sensitivity. a static blog cares only about volume. Cloudflare-protected sites filter on IP type before anything else. e-commerce checkout flows weight reputation heavily because fraud is expensive. match proxy type to site difficulty, not the other way around.

    is a 0 score better than a 100 score?
    depends on the tool. on most fraud databases, 0 means low risk and 100 means high risk. on quality-of-IP tools it can be the opposite. always read the legend. IPQualityScore uses 0-100 where higher is worse. spur.us flags risk categories rather than a numeric score.

    do residential proxies always have clean IPs?
    no. residential proxy pools share IPs across thousands of customers, so a single bad actor can burn an IP for everyone using that pool. premium providers actively monitor and quarantine flagged IPs. budget providers don’t, which is why their pools degrade fast.

    conclusion

    IP reputation decides whether your proxy traffic looks human or fraudulent to the systems guarding modern websites. it blends abuse history, network type, and live behavior into a score that determines whether you get blocked, challenged, or allowed.

    the practical takeaway is simple. for tough targets, use mobile or premium residential IPs from a provider that monitors pool health. test reputation before you commit. throttle requests to human pace. rotate sessions, not requests, where session trust matters. these four habits beat 90% of cheap proxy buyers who treat all IPs as interchangeable.

    reputation isn’t something you can fake. you either bring clean IPs to the fight, or you spend your day debugging why your scraper sees captchas on every page.

  • How to Scrape LinkedIn Data Without Getting Banned (2026)

    how to scrape linkedin data without getting banned (2026)

    scraping linkedin without bans in 2026 comes down to four things: residential or mobile proxies (never datacenter), aged accounts with established activity, slow request rates (under 80 actions per day per account), and either a managed scraping api or playwright with anti-detection. linkedin actively detects automation. one ip + one fresh account + 200 requests in an hour = ban within 24 hours. this guide covers the legal context, the technical setup, and how to recover when accounts get restricted.

    we cover legality first, then the proxy stack, account discipline, browser automation, managed api alternatives, and a 2026 ban-recovery playbook.

    is linkedin scraping legal in 2026?

    scraping public linkedin data is generally legal in the us under hiq v linkedin (2022) and follow-on rulings. the courts have repeatedly held that scraping public web data is not a violation of the computer fraud and abuse act.

    scraping linkedin still violates linkedin’s terms of service. tos violations are not criminal but they give linkedin grounds to ban accounts and pursue civil action against commercial scrapers in some cases.

    eu and uk law is stricter. gdpr requires a lawful basis (consent, contract, or legitimate interest) for processing personal data. scraped linkedin data falls under gdpr if it includes eu data subjects. document your lawful basis before processing, and respect data subject rights including erasure requests.

    read linkedin’s user agreement for the current commercial-use restrictions. for a deeper read on the legal landscape around lead-gen scraping see our b2b lead generation proxies guide.

    what gets you banned in 2026

    linkedin’s anti-bot stack flags four signals.

    ip pattern. datacenter ips trigger immediately. shared residential ips with known scraper traffic also flag fast. mobile carrier ips have the longest leash.

    session pattern. login from a new ip with no warm-up history is suspicious. 50 profile views in 10 minutes is a classic bot signal. clicking through every profile from a search result without scrolling looks robotic.

    browser fingerprint. headless chrome without anti-detection patches is detected within minutes. residential proxy + plain selenium = ban in under an hour.

    account age and activity. brand new accounts with zero connections and a thin profile that suddenly perform 500 actions trip every alarm. aged accounts with real history get more leniency.

    beat all four and bans become rare. miss any one and accounts cycle through faster than you can warm them.

    the proxy stack

    mobile proxies are the safest tier. linkedin sees thousands of users behind each carrier-grade nat ip, so individual scraping signals are diluted. expect to pay $50 to $150 per port per month.

    residential proxies are the value pick. session-rotating residential pools work for most scraping at $4 to $7 per gb. choose providers with sticky sessions of 10+ minutes so a single profile-view session does not change ip mid-flow.

    datacenter proxies are unusable for linkedin in 2026. even premium isp proxies (which are residential-issued datacenter ips) get blocked within a few requests.

    assign one proxy per linkedin account. never share an ip across multiple accounts. linkedin’s session correlation flags shared ips fast.

    account discipline

    aged accounts are non-negotiable in 2026. linkedin treats accounts under 6 months old with no activity as bots by default. for production scraping you need accounts with at least 100 connections, a complete profile, posted content from real timestamps, and a normal usage history.

    three options for account supply.

    option 1: warm your own. spend 30 to 60 days on each account: login, scroll, accept connections, post once a week, like a few posts daily. boring but the accounts last.

    option 2: buy aged accounts. resellers sell 1-year-old accounts with 500+ connections for $50 to $200. quality varies wildly. budget for replacement.

    option 3: managed scraping apis. let bright data, apify, or proxycurl handle the account problem entirely. you pay per query, they handle bans on their side. cleanest for production.

    never run more than 80 to 120 actions per account per day. one action = one profile view, one search, or one connection request. above that, ban risk spikes hard.

    browser automation: playwright with anti-detection

    for self-managed scraping, playwright with anti-detection patches is the baseline.

    from playwright.sync_api import sync_playwright
    import time
    import random
    
    PROXY = {
        "server": "http://proxy.example.com:8080",
        "username": "user-session-abc123",
        "password": "pass",
    }
    
    def scrape_profile(profile_url, session_cookie):
        with sync_playwright() as p:
            browser = p.chromium.launch(
                headless=True,
                proxy=PROXY,
                args=[
                    "--disable-blink-features=AutomationControlled",
                    "--no-sandbox",
                ],
            )
            context = browser.new_context(
                user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                           "AppleWebKit/537.36 (KHTML, like Gecko) "
                           "Chrome/127.0.0.0 Safari/537.36",
                viewport={"width": 1920, "height": 1080},
                locale="en-US",
                timezone_id="America/New_York",
            )
            context.add_cookies([{
                "name": "li_at",
                "value": session_cookie,
                "domain": ".linkedin.com",
                "path": "/",
            }])
    
            page = context.new_page()
            page.goto(profile_url, wait_until="networkidle")
            time.sleep(random.uniform(2, 5))
    
            page.mouse.wheel(0, 600)
            time.sleep(random.uniform(1, 3))
            page.mouse.wheel(0, 800)
            time.sleep(random.uniform(2, 4))
    
            name = page.locator("h1").inner_text()
            headline = page.locator(".text-body-medium.break-words").first.inner_text()
    
            browser.close()
            return {"name": name, "headline": headline, "url": profile_url}
    

    the --disable-blink-features=AutomationControlled flag removes the most obvious headless tell. sleeps and mouse-wheel events simulate human pacing. timezone, locale, and user-agent match a typical us desktop user.

    for stronger anti-detection, use playwright-stealth or a real antidetect browser like adspower or gologin. plain playwright is detectable by sophisticated fingerprinting.

    for the broader python scraping context see our web scraping with python guide.

    sticky sessions across the scrape session

    linkedin tracks ip across a session. switching ip mid-session looks like account hijacking and triggers a security challenge.

    def session_username(account_id):
        """build a sticky username for residential providers that support it."""
        return f"user-session-{account_id}"
    
    def proxy_for_account(account_id):
        return {
            "server": "http://proxy.example.com:8080",
            "username": session_username(account_id),
            "password": "pass",
        }
    

    most residential providers (smartproxy, oxylabs, soax) support session usernames that pin a single residential ip for 10 to 30 minutes. use the same session id for the duration of the linkedin scrape, then rotate when the session expires naturally.

    rate limits in practice

    based on 6 months of data across 30 aged accounts running through residential proxies in 2026, here is what stayed unbanned:

    • profile views: under 80 per day per account
    • searches: under 25 per day per account
    • connection requests: under 15 per day per account (lifetime cap of 100 per week)
    • messages to connections: under 50 per day per account
    • session length: 30 to 90 minutes per session, 1 to 2 sessions per day
    • gap between sessions: at least 4 hours

    push past these and ban rates spike. stay below them and accounts last 6 to 12 months on average before any restriction.

    managed scraping apis: the easier path

    self-managed linkedin scraping is a job. you maintain account warming, proxy rotation, anti-detection patches, and ban recovery. for many teams the time cost beats the api cost.

    managed options in 2026:

    bright data linkedin dataset. pre-scraped public profiles. updated continuously. you query by url or company. roughly $0.001 to $0.01 per record depending on volume. no scraping risk on your side.

    apify linkedin scraper actors. pay per actor run. simpler than building your own; still subject to linkedin’s anti-bot. 2026 prices: roughly $1 to $3 per 1,000 results.

    proxycurl. linkedin profile, company, and job api. enterprise-friendly with response-time slas. $0.10 to $0.30 per profile lookup at typical volumes.

    phantombuster. no-code linkedin automation. covers scraping plus connection requests and messaging. see our breakdown in outscraper vs phantombuster vs hunter.io.

    for production teams, the managed apis are the right choice unless you need volume that exceeds their rate limits or you are scraping data they do not offer.

    what to do when an account gets restricted

    linkedin restricts accounts in stages: warning, partial restriction (no search, no messages), full restriction (login redirects to verification), then permanent ban.

    at warning stage: stop all automation for 7 to 14 days. log in manually from a regular browser on the same proxy. do normal user activities (scroll, like 1 to 2 posts, accept 1 connection). most accounts recover.

    at partial restriction: same playbook plus complete identity verification if linkedin asks (selfie, government id). if you skip verification, the account moves to full restriction. for accounts you bought, this is usually game over.

    at full restriction: usually unrecoverable without verification. for managed-api stacks, this is on the api provider, not you.

    at permanent ban: replace the account. log the proxy + account combo so you do not reuse the proxy for the next account.

    ethical and security notes

    if you scrape eu data subjects, you must respect erasure requests. publish a privacy policy that lists linkedin as a data source and provides a removal email. process removals within 30 days.

    never scrape data behind a login that requires special permission (closed groups, private messages, premium-only fields). that crosses into the cfaa unauthorized-access territory in the us and is a clear gdpr violation in the eu.

    cold email or cold dm using scraped data still requires lawful basis in the eu and uk and a clear opt-out everywhere. a working email is a tool, not a license.

    faq

    can i scrape public linkedin profiles legally?

    in the us, public profile data scraping is generally legal under hiq v linkedin, but it violates linkedin’s tos. in the eu and uk, gdpr requires a lawful basis even for public data when it identifies a person. always document your basis and offer opt-out.

    what proxies should i use for linkedin scraping?

    mobile proxies are safest. residential proxies with sticky sessions of 10+ minutes are the value pick. datacenter and isp proxies are blocked instantly in 2026. budget $5 to $7 per gb for residential or $50+ per port per month for mobile.

    how many requests per day before linkedin bans?

    aged accounts on residential proxies tolerate roughly 80 profile views, 25 searches, and 15 connection requests per day. fresh accounts on datacenter ips tolerate maybe 20 to 50 requests before banning.

    is selenium or playwright better for linkedin scraping?

    playwright is the better default in 2026. its anti-detection options are richer, the api is cleaner, and it handles modern js rendering more reliably. selenium still works but requires more patches to avoid headless detection.

    do i need a paid linkedin sales nav account to scrape effectively?

    not strictly. public profile scraping works without a paid account. sales nav unlocks deeper search filters and lead lists, which is useful for outbound. paid accounts also tolerate slightly higher rate limits before triggering anti-bot.

    should i use a managed linkedin api or build my own scraper?

    for under 5,000 profiles per month, managed apis (bright data, apify, proxycurl) are usually cheaper than the engineering plus account management cost. for higher volume or unique fields not in the public datasets, build your own. budget for warming aged accounts, residential proxies, and ongoing maintenance.

    the bottom line

    linkedin scraping in 2026 is harder than 2022 because linkedin’s anti-bot stack got better. but it is also more accessible because managed datasets cover most common use cases at a per-record price that beats diy.

    self-managed approach: aged accounts, residential or mobile proxies (one per account), playwright with anti-detection, conservative rate limits. expect to replace 10 to 20 percent of accounts every quarter.

    managed approach: pay $0.001 to $0.30 per record depending on freshness and depth. zero ban exposure. faster time-to-data.

    for most teams in 2026 the managed approach wins on total cost. for teams scraping at very high volume or extracting fields managed apis do not surface, the diy stack still has a place. either way, document your gdpr basis and respect opt-outs. it is the difference between a sustainable lead-gen channel and a pile of legal exposure.