← back to blog

Handling reCAPTCHA v3 in scrapers without dropping IP reputation

Handling reCAPTCHA v3 in scrapers without dropping IP reputation

reCAPTCHA v3 is the one that catches people off guard. v2 at least shows you a puzzle, tells you it doesn’t trust you, gives you a chance to prove yourself. v3 is invisible. it runs silently in the background, scores every visit on a 0.0 to 1.0 scale, and hands that score to the site operator to act on however they see fit. what most scraper operators don’t realise until they’ve burned through a proxy pool is that the signals feeding that score aren’t stateless. Google’s risk analysis builds a picture of each IP over time. hammer a site with tokens that score 0.1, and you’re not just failing that request. you’re training a negative profile for that IP that persists across sessions and, depending on the site’s configuration, potentially across domains.

the practical consequence is that the naive approach, buy a batch of residential proxies, run your scraper, rotate IPs when you hit blocks, doesn’t work the way it did three years ago. you can be rotating correctly at the HTTP layer and still watch your success rate crater over the course of a day because the underlying IP reputation is degrading faster than you’re rotating. I’ve seen this happen on e-commerce price monitoring jobs where the proxy pool looked healthy by every standard metric but the site’s CAPTCHA scoring was quietly classifying 80% of requests as bot traffic within 48 hours of starting a campaign.

this article is for people who already have a scraping operation running and are trying to understand what’s going wrong, or who are architecting something new and want to avoid the most expensive mistakes. I’m going to go through how v3 actually works under the hood, what the reputation signals are, and what you can do operationally to stay in a usable score range without either burning budget on unnecessary CAPTCHA solvers or poisoning your proxy pool.

background and prior art

reCAPTCHA has gone through three meaningfully different architectures since Google acquired it from Carnegie Mellon in 2009. v1 used distorted text that humans could read and bots mostly couldn’t. v2 introduced the “I’m not a robot” checkbox plus image challenges as a fallback, with Google’s JavaScript running behavioral heuristics to decide whether the checkbox alone was sufficient. v3, launched publicly in October 2018, dropped the challenge entirely. the reCAPTCHA v3 developer documentation describes it as returning “a score for each request without user friction,” with 1.0 being very likely a good interaction and 0.0 being very likely a bot.

the shift matters because it moves the friction from the user to the site operator. under v2, a bot either solved the challenge or didn’t. under v3, the site gets a probability score and decides what to do with it. some operators use a threshold of 0.5 and block anything below. others use it as a signal to add friction, show a v2 challenge as a secondary gate, or flag the session for review without blocking it outright. this variability is actually useful for scrapers if you understand it, because a score of 0.4 might not block you on one site while 0.6 might trigger a secondary challenge on another. the adversarial game shifted from binary pass/fail to continuous score management.

the prior literature on CAPTCHA circumvention focused heavily on ML-based image recognition for v2 challenges, tools like CapMonster and 2captcha built their early businesses on this. v3 made image recognition irrelevant for the primary challenge, which is why the ecosystem pivoted toward browser automation for score generation and token harvesting, and why IP reputation became the critical variable instead of solve rate.

the core mechanism

when a page loads with reCAPTCHA v3 enabled, Google’s JavaScript (api.js) starts collecting behavioral signals from the client: mouse movement patterns, keystroke timing, scroll behavior, device fingerprint attributes, and the browsing history associated with the origin IP. these signals are sent to Google’s backend, which applies a risk model and returns a token. that token is a signed JWT containing the score, the action name the site specified, the site key, and a timestamp.

the token has a two-minute validity window. this is documented in the reCAPTCHA FAQ: “the response token from reCAPTCHA is only valid for two minutes.” if your scraper generates a token and then takes longer than 120 seconds to submit it to the site’s backend, the verification will fail on the server side. this is a common failure mode in high-latency scraping pipelines where token generation is decoupled from form submission.

critically, each token is single-use. the verification endpoint at https://www.google.com/recaptcha/api/siteverify will only return a valid response once per token. subsequent calls with the same token return a timeout-or-duplicate error code. scrapers that try to cache and reuse tokens, which I’ve seen in codebases that treat the token as a session credential, will fail silently in ways that are hard to debug because the initial request looks valid.

the reputation component is where it gets more nuanced. the score Google assigns to a token is influenced by the history associated with three identifiers: the IP address, the Google account cookies present in the browser (if any), and the device fingerprint. of these, IP history is the most operationally significant for scrapers because it’s the one most directly under your control. an IP that has generated many low-scoring tokens in recent history will generate lower-scoring tokens on subsequent requests, even for genuinely human-like interactions. the effect isn’t permanent but the decay period is long enough, measured in days not hours, that rotating an IP after it’s been poisoned doesn’t immediately help if you’re rotating back to it.

the mechanism for score influence is behavioral signal aggregation. Google’s model isn’t looking at individual requests in isolation; it’s looking at the distribution of signals across all requests associated with an IP over a trailing window. a residential IP that has been used exclusively for scraping with Playwright in headless mode will have a very different signal distribution than one used by a real household. the specific features that feed the model aren’t published, but the academic and practitioner literature broadly agrees on the major categories: WebGL fingerprint consistency, canvas rendering characteristics, navigator object anomalies (missing plugins, headless-specific values), timing patterns in event dispatch, and the absence of expected browser storage from prior Google sessions.

worked examples

example 1: price monitoring on an electronics retailer

a client I worked with was running price monitoring on roughly 40,000 SKUs across a mid-tier electronics retailer. they were using a datacenter proxy pool from a budget provider, around 500 IPs in the US. initial success rate was 94% in the first hour. by hour 6 it had dropped to 31%. by the next morning they were getting sub-10% completion.

the proxies weren’t being blocked at the network layer. the site was returning 200 responses. the issue was that the v3 score on every request had dropped below the site’s threshold, and the server-side logic was returning empty product data instead of real prices, a silent failure that took them a while to identify.

the fix involved three changes. first, switching from datacenter to residential proxies through a provider with genuine residential coverage. second, adding a pre-warming step where each IP loaded the site’s homepage and spent 8-15 seconds simulating scroll and click events before hitting any product pages. third, implementing a cooldown policy where any IP that triggered an empty-response pattern was retired for 24 hours rather than immediately recycled.

after the changes, they sustained above 88% completion over 72 hours. cost went up about 4x on the proxy side, but the data quality justified it.

example 2: job board lead aggregation

a small lead gen operation was scraping job postings from a board that had v3 on its search endpoint. they were using Playwright in headless mode with a residential proxy pool of about 200 IPs. the scores were coming back around 0.3 consistently, just below the site’s 0.4 threshold.

the problem was browser fingerprint consistency, specifically the headless detection vectors. running Playwright with headless: true exposes several navigator properties that the reCAPTCHA script checks. navigator.webdriver being true is the obvious one, and most practitioners patch it. but there are subtler ones: the plugins array is empty in headless Chrome, navigator.languages often returns only one language, and the chrome object in window has a different structure than in a real browser install.

switching to headless: 'new' in Playwright (available from Playwright 1.34 onwards) and adding a stealth plugin to normalize these properties pushed scores from 0.3 to around 0.6-0.7. the relevant changes in code look like this:

const { chromium } = require('playwright-extra');
const stealth = require('puppeteer-extra-plugin-stealth');

chromium.use(stealth());

const browser = await chromium.launch({
  headless: 'new',
  args: [
    '--disable-blink-features=AutomationControlled',
    '--no-sandbox',
    '--disable-setuid-sandbox'
  ]
});

const context = await browser.newContext({
  userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...',
  locale: 'en-US',
  timezoneId: 'America/New_York',
  viewport: { width: 1366, height: 768 }
});

the locale and timezone settings matter more than most people expect. a request claiming to come from a US residential IP but with a browser configured for en-GB locale is a signal mismatch that the model picks up.

example 3: review site aggregation with CAPTCHA solving fallback

a third case involved aggregating reviews from a hospitality site that had a more aggressive v3 setup, blocking anything below 0.6 and showing a v2 challenge for scores between 0.6 and 0.75. the volume was too high for full browser automation on every request, around 500,000 pages per day, so the architecture used a hybrid approach.

the primary path used Playwright to generate v3 tokens for a subset of requests, which warmed the IP reputation. the remaining requests used pre-generated tokens fed from the primary path, submitted within the 2-minute window. when a request hit the v2 fallback, it was routed to a CAPTCHA solving service.

2captcha charges approximately $2.99 per 1,000 reCAPTCHA v3 token solves as of Q1 2026 (their pricing page lists this as “reCAPTCHA v3” under enterprise plans). anti-captcha.com is priced similarly. at 500,000 pages per day, solving every request through a third-party service would cost around $1,500 per day. the hybrid approach reduced the solver call rate to about 12% of requests, bringing daily CAPTCHA solving costs to around $180. the rest were handled through token sharing from the browser automation layer.

edge cases and failure modes

token TTL violations in async pipelines

the most common silent failure I see in scraping codebases is token expiry. when token generation happens in one async worker and form submission happens in another, and the queue depth is variable, you will periodically have tokens sitting in the queue for longer than 2 minutes. the verification endpoint returns a success on the token format check but fails with timeout-or-duplicate, which many sites translate into a generic form error or simply ignore, returning a 200 with no data.

the fix is to timestamp tokens at generation and discard any that are older than 90 seconds before submission (not 120, to give yourself margin for network latency). generate a fresh token for anything that would have expired.

IP pool contamination from shared residential providers

residential proxy providers pool IPs from multiple customers. if another customer on the same provider is running aggressive scraping against the same target site, the shared IPs can have degraded reputations before you even start. this is more common with budget residential providers that don’t segment their pools effectively.

the tell is when you see consistently low scores from the first request on a fresh IP, with no warm-up period required to see the degradation. if scores are already at 0.2 on the first request, the IP came to you pre-poisoned.

mitigation: use providers that offer dedicated residential pools (BrightData’s “dedicated” residential tier, Oxylabs’ shared vs. dedicated distinction), or implement an IP health check at acquisition time where you load a neutral page (not your target), check the v3 score, and discard IPs that score below 0.5 before putting them in your active rotation.

action parameter mismatches

reCAPTCHA v3 requires a site to specify an action parameter when executing the token request, something like grecaptcha.execute(SITE_KEY, {action: 'login'}). the token embeds this action name, and the server-side verification can check that the action in the token matches what it expected. sites that validate the action parameter will reject tokens generated with the wrong action name even if the score is fine.

when you’re reverse-engineering a site’s v3 integration, you need to find the grecaptcha.execute calls and capture the exact action string being passed. it’s usually findable in the page’s JavaScript. using a generic action name like submit when the site expects checkout will give you consistent verification failures that look identical to low-score rejections.

score threshold changes without notice

site operators can change their v3 score thresholds at any time through the reCAPTCHA admin console. a scraper that was working fine at a score of 0.5 can suddenly start failing if the operator raises their threshold to 0.7. there’s no external signal that this happened.

if you see a success rate drop that isn’t correlated with any changes on your end, and your proxy health metrics look normal, threshold change is the first thing to investigate. the diagnostic is to check your token scores via an intercepted response (you can log the token and decode it, the score is in the payload) and see if the scores themselves changed or if the same scores are now failing.

headless browser fingerprint drift over time

browser fingerprints are partly based on the state of the browser instance. a Playwright browser that has been running for 8 hours with no storage, no cookies, no cached resources, and no browsing history looks very different from one that has been used normally. the reCAPTCHA script evaluates some of these storage and history signals.

the practical fix is to warm browser contexts before use: load a handful of neutral pages, let cookies and storage accumulate, simulate idle time between requests. some teams go further and pre-build browser state snapshots, a browser context that has been “lived in” for a few hours, and restore from snapshot for each new scraping session rather than starting cold.

what we learned in production

running scrapers against v3-protected sites for the past two years, the most important shift in my thinking has been treating IP reputation as a resource to be budgeted, not a binary good/bad state. every request you make with a given IP costs some amount of reputation if the behavioral signals are imperfect. the question isn’t “is this IP blocked?” it’s “how many requests can I make with this IP before the cumulative score degradation makes it unusable, and what does it cost to refresh that IP versus buying more IPs?”

at current residential proxy pricing, you’re typically paying $4-12 per GB depending on provider and plan structure. a Playwright-driven request to a typical e-commerce product page might consume 2-4 MB including subresources. that puts the proxy cost at $0.008-$0.048 per page before you account for failures. if you’re seeing 30% failure rates from score degradation and you’re not rotating fast enough, you’re effectively paying full price for 70% coverage while burning the IPs faster. the math usually favors more aggressive rotation with a larger pool over trying to squeeze every request out of fewer IPs.

the other production lesson is that CAPTCHA solving services are not a drop-in solution for v3 the way they were for v2. services like 2captcha and CapSolver can generate valid tokens, but those tokens carry the reputation of whatever infrastructure the solver uses to generate them. if the solver is using a shared pool of browser instances that hundreds of customers are also using to hit the same sites, the scores from that pool can be just as degraded as a burned datacenter proxy. I’ve tested CapSolver’s v3 token generation against three major retail sites and seen scores range from 0.3 to 0.8 depending on the site, with no direct control over what drives the variance. for high-volume operations where score consistency matters, generating your own tokens through controlled browser automation with vetted residential proxies gives you more reliable results than outsourcing token generation to a solver.

for anyone building multi-account or farming operations that involve CAPTCHA as part of a broader detection stack, the fingerprinting overlap with antidetect browser setup is significant. the same browser attribute normalization that helps with reCAPTCHA v3 scoring is foundational to the antidetect workflows covered at antidetectreview.org, and the IP reputation management principles apply directly to airdrop farming contexts at airdropfarming.org.

for more context on proxy pool architecture decisions that affect CAPTCHA scoring, the proxyscraping.org blog has related material on residential proxy selection and rotation strategies. a working understanding of how browser fingerprinting interacts with proxy configuration is essential context for what’s described above, and the specifics of residential proxy pool sizing for scraping operations get into the rotation economics in more detail.

references and further reading

  1. reCAPTCHA v3 developer documentation, Google Developers. the primary reference for score mechanics, action parameters, and the server-side verification endpoint. the section on score interpretation is the most practically relevant for operators.

  2. reCAPTCHA FAQ, Google Developers. covers token validity windows, duplicate token errors, and common integration mistakes. the two-minute TTL and single-use constraint are documented here.

  3. OWASP Web Security Testing Guide, section on client-side testing, OWASP Foundation. useful background on JavaScript-based detection mechanisms and what browser properties security analysis typically examines, which overlaps substantially with what CAPTCHA risk models evaluate.

  4. Playwright documentation: browser contexts, Playwright. the official reference for context isolation, state management, and the configuration options that affect browser fingerprint consistency, including locale, timezone, and viewport settings.

Written by Xavier Fok

disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-05-19.

need infra for this today?