[{"data":1,"prerenderedAt":618},["ShallowReactive",2],{"blog-\u002Fblog\u002Fsolving-captchas-2captcha-capsolver":3},{"id":4,"title":5,"body":6,"date":597,"description":598,"draft":599,"extension":600,"meta":601,"navigation":183,"path":602,"readingTime":603,"seo":604,"stem":605,"tags":606,"takeaways":611,"updated":616,"__hash__":617},"blog\u002Fblog\u002Fsolving-captchas-2captcha-capsolver.md","Solving CAPTCHAs in Your Scraper with 2Captcha and CapSolver",{"type":7,"value":8,"toc":587},"minimark",[9,13,17,22,25,28,44,47,51,54,140,143,147,155,333,337,340,389,400,404,407,516,520,523,557,561,564,568,583],[10,11,5],"h1",{"id":12},"solving-captchas-in-your-scraper-with-2captcha-and-capsolver",[14,15,16],"p",{},"CAPTCHAs are the wall most scrapers hit once a site decides it does not trust you. The good news is that almost every common CAPTCHA can be solved programmatically through a solving service. This guide shows how to integrate 2Captcha and CapSolver, when each one fits, and how to keep costs under control.",[18,19,21],"h2",{"id":20},"how-captcha-solving-services-work","How CAPTCHA solving services work",[14,23,24],{},"You do not solve the CAPTCHA yourself. Instead you send the challenge to a service, the service returns a token, and you inject that token into the page exactly as a real browser would after a human passed the test.",[14,26,27],{},"The flow is always the same:",[29,30,31,35,38,41],"ol",{},[32,33,34],"li",{},"Detect the CAPTCHA on the page and read its site key.",[32,36,37],{},"Send the site key and page URL to the solving service.",[32,39,40],{},"Poll until the service returns a solution token.",[32,42,43],{},"Inject the token into the hidden form field and submit.",[14,45,46],{},"The token, not the image, is what the target site validates. This is why solving services work even on invisible reCAPTCHA v3 where there is no puzzle to click.",[18,48,50],{"id":49},"_2captcha-vs-capsolver-which-to-pick","2Captcha vs CapSolver: which to pick",[14,52,53],{},"Both services cover the major CAPTCHA types. The practical differences matter more than the feature list.",[55,56,57,73],"table",{},[58,59,60],"thead",{},[61,62,63,67,70],"tr",{},[64,65,66],"th",{},"Factor",[64,68,69],{},"2Captcha",[64,71,72],{},"CapSolver",[74,75,76,88,98,109,118,129],"tbody",{},[61,77,78,82,85],{},[79,80,81],"td",{},"Speed",[79,83,84],{},"Human powered, slower",[79,86,87],{},"AI powered, faster",[61,89,90,93,96],{},[79,91,92],{},"reCAPTCHA v2",[79,94,95],{},"Reliable",[79,97,95],{},[61,99,100,103,106],{},[79,101,102],{},"reCAPTCHA v3",[79,104,105],{},"Supported",[79,107,108],{},"Strong",[61,110,111,114,116],{},[79,112,113],{},"Cloudflare Turnstile",[79,115,105],{},[79,117,108],{},[61,119,120,123,126],{},[79,121,122],{},"Pricing model",[79,124,125],{},"Per solve",[79,127,128],{},"Per solve, cheaper at volume",[61,130,131,134,137],{},[79,132,133],{},"Best for",[79,135,136],{},"Image and token tasks",[79,138,139],{},"High volume token tasks",[14,141,142],{},"Rule of thumb: start with CapSolver for speed on token based challenges, keep 2Captcha as a fallback for odd image puzzles and broad coverage.",[18,144,146],{"id":145},"solving-recaptcha-v2-with-2captcha","Solving reCAPTCHA v2 with 2Captcha",[14,148,149,150,154],{},"First find the site key in the page. It sits in the ",[151,152,153],"code",{},"data-sitekey"," attribute of the reCAPTCHA element. Then send it to the service.",[156,157,162],"pre",{"className":158,"code":159,"language":160,"meta":161,"style":161},"language-python shiki shiki-themes github-light github-dark","import time\nimport requests\n\nAPI_KEY = \"your_2captcha_key\"\n\ndef solve_recaptcha_v2(site_key: str, page_url: str) -> str:\n    # 1. Submit the task\n    r = requests.post(\"https:\u002F\u002F2captcha.com\u002Fin.php\", data={\n        \"key\": API_KEY,\n        \"method\": \"userrecaptcha\",\n        \"googlekey\": site_key,\n        \"pageurl\": page_url,\n        \"json\": 1,\n    }).json()\n    request_id = r[\"request\"]\n\n    # 2. Poll for the token\n    for _ in range(24):\n        time.sleep(5)\n        res = requests.get(\"https:\u002F\u002F2captcha.com\u002Fres.php\", params={\n            \"key\": API_KEY,\n            \"action\": \"get\",\n            \"id\": request_id,\n            \"json\": 1,\n        }).json()\n        if res[\"status\"] == 1:\n            return res[\"request\"]  # the g-recaptcha-response token\n    raise TimeoutError(\"CAPTCHA not solved in time\")\n","python","",[151,163,164,172,178,185,191,196,202,208,214,220,226,232,238,244,250,256,261,267,273,279,285,291,297,303,309,315,321,327],{"__ignoreMap":161},[165,166,169],"span",{"class":167,"line":168},"line",1,[165,170,171],{},"import time\n",[165,173,175],{"class":167,"line":174},2,[165,176,177],{},"import requests\n",[165,179,181],{"class":167,"line":180},3,[165,182,184],{"emptyLinePlaceholder":183},true,"\n",[165,186,188],{"class":167,"line":187},4,[165,189,190],{},"API_KEY = \"your_2captcha_key\"\n",[165,192,194],{"class":167,"line":193},5,[165,195,184],{"emptyLinePlaceholder":183},[165,197,199],{"class":167,"line":198},6,[165,200,201],{},"def solve_recaptcha_v2(site_key: str, page_url: str) -> str:\n",[165,203,205],{"class":167,"line":204},7,[165,206,207],{},"    # 1. Submit the task\n",[165,209,211],{"class":167,"line":210},8,[165,212,213],{},"    r = requests.post(\"https:\u002F\u002F2captcha.com\u002Fin.php\", data={\n",[165,215,217],{"class":167,"line":216},9,[165,218,219],{},"        \"key\": API_KEY,\n",[165,221,223],{"class":167,"line":222},10,[165,224,225],{},"        \"method\": \"userrecaptcha\",\n",[165,227,229],{"class":167,"line":228},11,[165,230,231],{},"        \"googlekey\": site_key,\n",[165,233,235],{"class":167,"line":234},12,[165,236,237],{},"        \"pageurl\": page_url,\n",[165,239,241],{"class":167,"line":240},13,[165,242,243],{},"        \"json\": 1,\n",[165,245,247],{"class":167,"line":246},14,[165,248,249],{},"    }).json()\n",[165,251,253],{"class":167,"line":252},15,[165,254,255],{},"    request_id = r[\"request\"]\n",[165,257,259],{"class":167,"line":258},16,[165,260,184],{"emptyLinePlaceholder":183},[165,262,264],{"class":167,"line":263},17,[165,265,266],{},"    # 2. Poll for the token\n",[165,268,270],{"class":167,"line":269},18,[165,271,272],{},"    for _ in range(24):\n",[165,274,276],{"class":167,"line":275},19,[165,277,278],{},"        time.sleep(5)\n",[165,280,282],{"class":167,"line":281},20,[165,283,284],{},"        res = requests.get(\"https:\u002F\u002F2captcha.com\u002Fres.php\", params={\n",[165,286,288],{"class":167,"line":287},21,[165,289,290],{},"            \"key\": API_KEY,\n",[165,292,294],{"class":167,"line":293},22,[165,295,296],{},"            \"action\": \"get\",\n",[165,298,300],{"class":167,"line":299},23,[165,301,302],{},"            \"id\": request_id,\n",[165,304,306],{"class":167,"line":305},24,[165,307,308],{},"            \"json\": 1,\n",[165,310,312],{"class":167,"line":311},25,[165,313,314],{},"        }).json()\n",[165,316,318],{"class":167,"line":317},26,[165,319,320],{},"        if res[\"status\"] == 1:\n",[165,322,324],{"class":167,"line":323},27,[165,325,326],{},"            return res[\"request\"]  # the g-recaptcha-response token\n",[165,328,330],{"class":167,"line":329},28,[165,331,332],{},"    raise TimeoutError(\"CAPTCHA not solved in time\")\n",[18,334,336],{"id":335},"injecting-the-token-with-playwright","Injecting the token with Playwright",[14,338,339],{},"The token is useless until it is placed in the page and the form is submitted. Inject it into the hidden textarea reCAPTCHA expects.",[156,341,343],{"className":158,"code":342,"language":160,"meta":161,"style":161},"token = solve_recaptcha_v2(site_key, page_url)\n\nawait page.evaluate(\n    \"\"\"(token) => {\n        document.querySelector('#g-recaptcha-response').value = token;\n    }\"\"\",\n    token,\n)\nawait page.click(\"button[type=submit]\")\n",[151,344,345,350,354,359,364,369,374,379,384],{"__ignoreMap":161},[165,346,347],{"class":167,"line":168},[165,348,349],{},"token = solve_recaptcha_v2(site_key, page_url)\n",[165,351,352],{"class":167,"line":174},[165,353,184],{"emptyLinePlaceholder":183},[165,355,356],{"class":167,"line":180},[165,357,358],{},"await page.evaluate(\n",[165,360,361],{"class":167,"line":187},[165,362,363],{},"    \"\"\"(token) => {\n",[165,365,366],{"class":167,"line":193},[165,367,368],{},"        document.querySelector('#g-recaptcha-response').value = token;\n",[165,370,371],{"class":167,"line":198},[165,372,373],{},"    }\"\"\",\n",[165,375,376],{"class":167,"line":204},[165,377,378],{},"    token,\n",[165,380,381],{"class":167,"line":210},[165,382,383],{},")\n",[165,385,386],{"class":167,"line":216},[165,387,388],{},"await page.click(\"button[type=submit]\")\n",[14,390,391,392,395,396,399],{},"For reCAPTCHA v3 there is no checkbox. The token goes into whatever field the site reads, often a hidden input the site script populates, and you usually pass a ",[151,393,394],{},"min_score"," and ",[151,397,398],{},"action"," to the solver so the returned token matches what the site expects.",[18,401,403],{"id":402},"solving-cloudflare-turnstile-with-capsolver","Solving Cloudflare Turnstile with CapSolver",[14,405,406],{},"Turnstile is increasingly common and CapSolver handles it well. The pattern is identical, only the task type changes.",[156,408,410],{"className":158,"code":409,"language":160,"meta":161,"style":161},"import requests\n\nCAPSOLVER_KEY = \"your_capsolver_key\"\n\ndef solve_turnstile(site_key: str, page_url: str) -> str:\n    create = requests.post(\"https:\u002F\u002Fapi.capsolver.com\u002FcreateTask\", json={\n        \"clientKey\": CAPSOLVER_KEY,\n        \"task\": {\n            \"type\": \"AntiTurnstileTaskProxyLess\",\n            \"websiteURL\": page_url,\n            \"websiteKey\": site_key,\n        },\n    }).json()\n    task_id = create[\"taskId\"]\n\n    while True:\n        res = requests.post(\"https:\u002F\u002Fapi.capsolver.com\u002FgetTaskResult\", json={\n            \"clientKey\": CAPSOLVER_KEY,\n            \"taskId\": task_id,\n        }).json()\n        if res[\"status\"] == \"ready\":\n            return res[\"solution\"][\"token\"]\n",[151,411,412,416,420,425,429,434,439,444,449,454,459,464,469,473,478,482,487,492,497,502,506,511],{"__ignoreMap":161},[165,413,414],{"class":167,"line":168},[165,415,177],{},[165,417,418],{"class":167,"line":174},[165,419,184],{"emptyLinePlaceholder":183},[165,421,422],{"class":167,"line":180},[165,423,424],{},"CAPSOLVER_KEY = \"your_capsolver_key\"\n",[165,426,427],{"class":167,"line":187},[165,428,184],{"emptyLinePlaceholder":183},[165,430,431],{"class":167,"line":193},[165,432,433],{},"def solve_turnstile(site_key: str, page_url: str) -> str:\n",[165,435,436],{"class":167,"line":198},[165,437,438],{},"    create = requests.post(\"https:\u002F\u002Fapi.capsolver.com\u002FcreateTask\", json={\n",[165,440,441],{"class":167,"line":204},[165,442,443],{},"        \"clientKey\": CAPSOLVER_KEY,\n",[165,445,446],{"class":167,"line":210},[165,447,448],{},"        \"task\": {\n",[165,450,451],{"class":167,"line":216},[165,452,453],{},"            \"type\": \"AntiTurnstileTaskProxyLess\",\n",[165,455,456],{"class":167,"line":222},[165,457,458],{},"            \"websiteURL\": page_url,\n",[165,460,461],{"class":167,"line":228},[165,462,463],{},"            \"websiteKey\": site_key,\n",[165,465,466],{"class":167,"line":234},[165,467,468],{},"        },\n",[165,470,471],{"class":167,"line":240},[165,472,249],{},[165,474,475],{"class":167,"line":246},[165,476,477],{},"    task_id = create[\"taskId\"]\n",[165,479,480],{"class":167,"line":252},[165,481,184],{"emptyLinePlaceholder":183},[165,483,484],{"class":167,"line":258},[165,485,486],{},"    while True:\n",[165,488,489],{"class":167,"line":263},[165,490,491],{},"        res = requests.post(\"https:\u002F\u002Fapi.capsolver.com\u002FgetTaskResult\", json={\n",[165,493,494],{"class":167,"line":269},[165,495,496],{},"            \"clientKey\": CAPSOLVER_KEY,\n",[165,498,499],{"class":167,"line":275},[165,500,501],{},"            \"taskId\": task_id,\n",[165,503,504],{"class":167,"line":281},[165,505,314],{},[165,507,508],{"class":167,"line":287},[165,509,510],{},"        if res[\"status\"] == \"ready\":\n",[165,512,513],{"class":167,"line":293},[165,514,515],{},"            return res[\"solution\"][\"token\"]\n",[18,517,519],{"id":518},"keeping-costs-under-control","Keeping costs under control",[14,521,522],{},"Solving services charge per solve, and on a large job the bill adds up fast. The cheapest CAPTCHA is the one you never trigger.",[524,525,526,539,545,551],"ul",{},[32,527,528,532,533,538],{},[529,530,531],"strong",{},"Reduce triggers first."," A clean residential IP and a realistic browser fingerprint mean fewer CAPTCHAs in the first place. Solving is the fallback, not the strategy. See my guide on ",[534,535,537],"a",{"href":536},"\u002Fblog\u002Fbypass-cloudflare-web-scraping","bypassing Cloudflare"," for the stealth side.",[32,540,541,544],{},[529,542,543],{},"Cache sessions."," Once you pass a challenge, reuse the cookies. Do not solve a fresh CAPTCHA on every request.",[32,546,547,550],{},[529,548,549],{},"Solve only when blocked."," Detect the CAPTCHA and call the service only if it actually appears, rather than pre solving on every page.",[32,552,553,556],{},[529,554,555],{},"Set a budget cap."," Track solves per run and stop the job if the count spikes, which usually means your fingerprint or proxy went bad.",[18,558,560],{"id":559},"when-solving-services-are-not-enough","When solving services are not enough",[14,562,563],{},"Some sites layer behavioral analysis on top of the CAPTCHA. A valid token from a session that never moved a mouse or scrolled can still be rejected. In those cases you need the full stealth stack: residential proxies, a patched browser fingerprint, and human like interaction timing, with the solver as one piece rather than the whole answer.",[18,565,567],{"id":566},"need-captchas-handled-in-your-scraping-project","Need CAPTCHAs handled in your scraping project?",[14,569,570,571,577,578,582],{},"I build scraping systems that combine stealth, proxy rotation, and CAPTCHA solving so they keep running on protected sites. If you have a project that keeps hitting CAPTCHAs, ",[534,572,576],{"href":573,"rel":574},"https:\u002F\u002Fwww.upwork.com\u002Ffreelancers\u002Fphanvuong2",[575],"nofollow","hire me on Upwork"," or reach out through the ",[534,579,581],{"href":580},"\u002F#contact","contact form",". I reply within 24 hours with a scope and quote.",[584,585,586],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":161,"searchDepth":174,"depth":174,"links":588},[589,590,591,592,593,594,595,596],{"id":20,"depth":174,"text":21},{"id":49,"depth":174,"text":50},{"id":145,"depth":174,"text":146},{"id":335,"depth":174,"text":336},{"id":402,"depth":174,"text":403},{"id":518,"depth":174,"text":519},{"id":559,"depth":174,"text":560},{"id":566,"depth":174,"text":567},"2026-06-08","A practical guide to integrating CAPTCHA solving services into a Python scraper. Covers reCAPTCHA v2 and v3, hCaptcha, Cloudflare Turnstile, token injection, and cost control.",false,"md",{},"\u002Fblog\u002Fsolving-captchas-2captcha-capsolver","8 min read",{"title":5,"description":598},"blog\u002Fsolving-captchas-2captcha-capsolver",[607,608,160,609,610],"captcha","web scraping","automation","anti-bot",[612,613,614,615],"Solving services return a token you inject; you do not solve the puzzle yourself.","CapSolver is fast for token challenges; 2Captcha gives broad coverage as a fallback.","The cheapest CAPTCHA is one you never trigger, so reduce triggers with clean IPs and fingerprints first.","Cache sessions and solve only when actually blocked to keep costs down.",null,"vHMGfU8-0OOVYAG-0hnOxPDnNwGpE_VU2mwP_M-vp1U",1781254278206]