or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

captcha-solving.mdchallenge-handling.mdcore-scraper.mdindex.mdjavascript-interpreters.mdproxy-management.mdstealth-mode.mduser-agent.md

challenge-handling.mddocs/

0

# Challenge Handling

1

2

Comprehensive support for all Cloudflare challenge types including legacy v1, modern v2, advanced v3 JavaScript VM challenges, and Turnstile CAPTCHA alternatives. CloudScraper automatically detects and solves these challenges transparently.

3

4

## Capabilities

5

6

### Cloudflare v1 (Legacy) Challenges

7

8

Handler for legacy Cloudflare v1 challenges that use simple JavaScript validation and timing delays.

9

10

```python { .api }

11

class Cloudflare:

12

def __init__(self, cloudscraper):

13

"""Initialize v1 challenge handler."""

14

15

@staticmethod

16

def is_Challenge_Request(resp) -> bool:

17

"""

18

Detect if response contains a v1 challenge.

19

20

Parameters:

21

- resp: requests.Response object

22

23

Returns:

24

bool: True if v1 challenge detected

25

"""

26

27

@staticmethod

28

def is_IUAM_Challenge(resp) -> bool:

29

"""

30

Detect IUAM (I'm Under Attack Mode) challenge.

31

32

Parameters:

33

- resp: requests.Response object

34

35

Returns:

36

bool: True if IUAM challenge detected

37

"""

38

39

def Challenge_Response(self, resp, **kwargs):

40

"""

41

Handle v1 challenge solving.

42

43

Parameters:

44

- resp: requests.Response containing challenge

45

- **kwargs: request parameters

46

47

Returns:

48

requests.Response with solved challenge

49

50

Raises:

51

- CloudflareIUAMError: If challenge parameters cannot be extracted

52

- CloudflareSolveError: If challenge solving fails

53

"""

54

```

55

56

#### Usage Examples

57

58

```python

59

# v1 challenges are handled automatically

60

scraper = cloudscraper.create_scraper()

61

response = scraper.get('https://legacy-protected-site.com')

62

63

# Disable v1 handling if needed

64

scraper = cloudscraper.create_scraper(disableCloudflareV1=True)

65

66

# Manual v1 detection (normally not needed)

67

if cloudscraper.Cloudflare.is_Challenge_Request(response):

68

print("v1 challenge detected")

69

```

70

71

### Cloudflare v2 Challenges

72

73

Handler for modern Cloudflare v2 challenges that include JavaScript execution and CAPTCHA verification.

74

75

```python { .api }

76

class CloudflareV2:

77

def __init__(self, cloudscraper):

78

"""Initialize v2 challenge handler."""

79

80

@staticmethod

81

def is_V2_Challenge(resp) -> bool:

82

"""

83

Detect v2 JavaScript challenge.

84

85

Parameters:

86

- resp: requests.Response object

87

88

Returns:

89

bool: True if v2 JS challenge detected

90

"""

91

92

@staticmethod

93

def is_V2_Captcha_Challenge(resp) -> bool:

94

"""

95

Detect v2 CAPTCHA challenge.

96

97

Parameters:

98

- resp: requests.Response object

99

100

Returns:

101

bool: True if v2 CAPTCHA challenge detected

102

"""

103

104

def handle_V2_Challenge(self, resp, **kwargs):

105

"""

106

Handle v2 JavaScript challenge.

107

108

Parameters:

109

- resp: requests.Response containing challenge

110

- **kwargs: request parameters

111

112

Returns:

113

requests.Response with solved challenge

114

115

Raises:

116

- CloudflareChallengeError: If challenge cannot be solved

117

"""

118

119

def handle_V2_Captcha_Challenge(self, resp, **kwargs):

120

"""

121

Handle v2 CAPTCHA challenge.

122

123

Parameters:

124

- resp: requests.Response containing challenge

125

- **kwargs: request parameters

126

127

Returns:

128

requests.Response with solved challenge

129

130

Raises:

131

- CloudflareCaptchaError: If CAPTCHA cannot be solved

132

- CloudflareCaptchaProvider: If no CAPTCHA solver configured

133

"""

134

135

def extract_challenge_data(self, resp) -> dict:

136

"""

137

Extract v2 challenge parameters from response.

138

139

Parameters:

140

- resp: requests.Response containing challenge

141

142

Returns:

143

dict: Challenge parameters and JavaScript code

144

145

Raises:

146

- CloudflareChallengeError: If challenge data cannot be extracted

147

"""

148

149

def generate_challenge_payload(self, challenge_data, resp) -> dict:

150

"""

151

Generate payload for v2 challenge submission.

152

153

Parameters:

154

- challenge_data: dict, extracted challenge parameters

155

- resp: requests.Response, original challenge response

156

157

Returns:

158

dict: Challenge solution payload

159

"""

160

```

161

162

#### Usage Examples

163

164

```python

165

# v2 challenges handled automatically

166

scraper = cloudscraper.create_scraper()

167

response = scraper.get('https://v2-protected-site.com')

168

169

# With CAPTCHA solver for v2 CAPTCHA challenges

170

scraper = cloudscraper.create_scraper(

171

captcha={

172

'provider': '2captcha',

173

'api_key': 'your_api_key'

174

}

175

)

176

177

# Disable v2 handling

178

scraper = cloudscraper.create_scraper(disableCloudflareV2=True)

179

```

180

181

### Cloudflare v3 JavaScript VM Challenges

182

183

Handler for advanced Cloudflare v3 challenges that execute JavaScript in a virtual machine environment for enhanced security.

184

185

```python { .api }

186

class CloudflareV3:

187

def __init__(self, cloudscraper):

188

"""Initialize v3 challenge handler."""

189

190

@staticmethod

191

def is_V3_Challenge(resp) -> bool:

192

"""

193

Detect v3 JavaScript VM challenge.

194

195

Parameters:

196

- resp: requests.Response object

197

198

Returns:

199

bool: True if v3 challenge detected

200

"""

201

202

def extract_v3_challenge_data(self, resp) -> dict:

203

"""

204

Extract v3 challenge parameters from response.

205

206

Parameters:

207

- resp: requests.Response containing challenge

208

209

Returns:

210

dict: Challenge parameters and data

211

212

Raises:

213

- CloudflareV3Error: If challenge data cannot be extracted

214

"""

215

216

def handle_V3_Challenge(self, resp, **kwargs):

217

"""

218

Handle v3 JavaScript VM challenge.

219

220

Parameters:

221

- resp: requests.Response containing challenge

222

- **kwargs: request parameters

223

224

Returns:

225

requests.Response with solved challenge

226

227

Raises:

228

- CloudflareV3Error: If challenge cannot be solved

229

"""

230

231

def execute_vm_challenge(self, challenge_data, domain) -> str:

232

"""

233

Execute JavaScript VM challenge code.

234

235

Parameters:

236

- challenge_data: dict, extracted challenge parameters

237

- domain: str, target domain for challenge

238

239

Returns:

240

str: Challenge solution result

241

242

Raises:

243

- CloudflareV3Error: If VM execution fails

244

"""

245

246

def generate_fallback_response(self, challenge_data) -> str:

247

"""

248

Generate fallback response when VM execution fails.

249

250

Parameters:

251

- challenge_data: dict, challenge parameters

252

253

Returns:

254

str: Fallback challenge response

255

"""

256

257

def generate_v3_challenge_payload(self, challenge_data, resp, challenge_answer) -> dict:

258

"""

259

Generate payload for v3 challenge submission.

260

261

Parameters:

262

- challenge_data: dict, extracted challenge parameters

263

- resp: requests.Response, original challenge response

264

- challenge_answer: str, computed challenge solution

265

266

Returns:

267

dict: Challenge solution payload

268

"""

269

```

270

271

#### Usage Examples

272

273

```python

274

# v3 challenges handled automatically

275

scraper = cloudscraper.create_scraper()

276

response = scraper.get('https://v3-protected-site.com')

277

278

# Optimized for v3 challenges

279

scraper = cloudscraper.create_scraper(

280

interpreter='js2py', # Recommended for v3

281

delay=5, # Allow more time for complex challenges

282

debug=True # See v3 detection

283

)

284

285

# Disable v3 handling

286

scraper = cloudscraper.create_scraper(disableCloudflareV3=True)

287

```

288

289

### Cloudflare Turnstile Challenges

290

291

Handler for Cloudflare Turnstile challenges, which are CAPTCHA alternatives that provide user-friendly verification.

292

293

```python { .api }

294

class CloudflareTurnstile:

295

def __init__(self, cloudscraper):

296

"""Initialize Turnstile challenge handler."""

297

298

@staticmethod

299

def is_Turnstile_Challenge(resp) -> bool:

300

"""

301

Detect Turnstile challenge.

302

303

Parameters:

304

- resp: requests.Response object

305

306

Returns:

307

bool: True if Turnstile challenge detected

308

"""

309

310

def extract_turnstile_data(self, resp) -> dict:

311

"""

312

Extract Turnstile challenge parameters.

313

314

Parameters:

315

- resp: requests.Response containing challenge

316

317

Returns:

318

dict: Turnstile site key and parameters

319

320

Raises:

321

- CloudflareTurnstileError: If Turnstile data cannot be extracted

322

"""

323

324

def handle_Turnstile_Challenge(self, resp, **kwargs):

325

"""

326

Handle Turnstile challenge solving.

327

328

Parameters:

329

- resp: requests.Response containing challenge

330

- **kwargs: request parameters

331

332

Returns:

333

requests.Response with solved challenge

334

335

Raises:

336

- CloudflareTurnstileError: If Turnstile cannot be solved

337

- CloudflareCaptchaProvider: If no CAPTCHA solver configured

338

"""

339

```

340

341

#### Usage Examples

342

343

```python

344

# Turnstile challenges handled automatically with CAPTCHA solver

345

scraper = cloudscraper.create_scraper(

346

captcha={

347

'provider': '2captcha',

348

'api_key': 'your_api_key'

349

}

350

)

351

response = scraper.get('https://turnstile-protected-site.com')

352

353

# Different CAPTCHA providers work with Turnstile

354

providers = ['2captcha', 'anticaptcha', 'capsolver', 'capmonster']

355

for provider in providers:

356

scraper = cloudscraper.create_scraper(

357

captcha={'provider': provider, 'api_key': 'key'}

358

)

359

360

# Disable Turnstile handling

361

scraper = cloudscraper.create_scraper(disableTurnstile=True)

362

```

363

364

## Challenge Detection and Priority

365

366

CloudScraper automatically detects and handles challenges in priority order:

367

368

1. **Turnstile challenges** (highest priority)

369

2. **v3 JavaScript VM challenges**

370

3. **v2 JavaScript and CAPTCHA challenges**

371

4. **v1 legacy challenges** (lowest priority)

372

373

```python

374

# All challenge types enabled by default

375

scraper = cloudscraper.create_scraper()

376

377

# Selective challenge handling

378

scraper = cloudscraper.create_scraper(

379

disableCloudflareV1=True, # Skip legacy challenges

380

disableCloudflareV2=False, # Handle v2 challenges

381

disableCloudflareV3=False, # Handle v3 challenges

382

disableTurnstile=False # Handle Turnstile

383

)

384

```

385

386

## Challenge Solving Configuration

387

388

### JavaScript Interpreter Selection

389

390

Different interpreters work better with different challenge types:

391

392

```python

393

# Recommended interpreters by challenge type

394

interpreters = {

395

'v1': ['js2py', 'nodejs', 'native'],

396

'v2': ['js2py', 'nodejs', 'v8'],

397

'v3': ['js2py', 'nodejs'], # js2py recommended for v3

398

'turnstile': ['any'] # Uses CAPTCHA solver, not interpreter

399

}

400

401

# Configure interpreter

402

scraper = cloudscraper.create_scraper(interpreter='js2py')

403

```

404

405

### Challenge Timing

406

407

Configure delays and timeouts for challenge solving:

408

409

```python

410

# Custom challenge timing

411

scraper = cloudscraper.create_scraper(

412

delay=5, # Wait 5 seconds before submitting solution

413

solveDepth=3 # Maximum challenge solving attempts

414

)

415

```

416

417

### Debug Mode for Challenges

418

419

Enable debug output to see challenge detection and solving:

420

421

```python

422

scraper = cloudscraper.create_scraper(debug=True)

423

response = scraper.get('https://protected-site.com')

424

425

# Debug output shows:

426

# "Detected a Cloudflare v3 JavaScript VM challenge."

427

# "Solving challenge with js2py interpreter..."

428

# "Challenge solved successfully"

429

```

430

431

## Error Handling

432

433

Challenge handling can raise specific exceptions:

434

435

```python

436

try:

437

scraper = cloudscraper.create_scraper()

438

response = scraper.get('https://protected-site.com')

439

except cloudscraper.CloudflareLoopProtection:

440

print("Too many challenge attempts - infinite loop detected")

441

except cloudscraper.CloudflareV3Error:

442

print("v3 JavaScript VM challenge failed")

443

except cloudscraper.CloudflareTurnstileError:

444

print("Turnstile challenge failed")

445

except cloudscraper.CloudflareCaptchaProvider:

446

print("CAPTCHA challenge detected but no solver configured")

447

except cloudscraper.CloudflareSolveError:

448

print("General challenge solving error")

449

```

450

451

## Advanced Challenge Handling

452

453

### Custom Challenge Detection

454

455

For advanced users who need to detect challenges manually:

456

457

```python

458

response = scraper.get('https://example.com')

459

460

# Manual challenge detection

461

if cloudscraper.CloudflareTurnstile.is_Turnstile_Challenge(response):

462

print("Turnstile detected")

463

elif cloudscraper.CloudflareV3.is_V3_Challenge(response):

464

print("v3 challenge detected")

465

elif cloudscraper.CloudflareV2.is_V2_Challenge(response):

466

print("v2 JS challenge detected")

467

elif cloudscraper.CloudflareV2.is_V2_Captcha_Challenge(response):

468

print("v2 CAPTCHA challenge detected")

469

elif cloudscraper.Cloudflare.is_Challenge_Request(response):

470

print("v1 challenge detected")

471

```

472

473

### Challenge Hooks

474

475

Use request hooks to monitor challenge solving:

476

477

```python

478

def pre_challenge_hook(scraper, method, url, *args, **kwargs):

479

print(f"About to solve challenge for {url}")

480

return method, url, args, kwargs

481

482

def post_challenge_hook(scraper, response):

483

if response.status_code == 200:

484

print("Challenge solved successfully")

485

return response

486

487

scraper = cloudscraper.create_scraper(

488

requestPreHook=pre_challenge_hook,

489

requestPostHook=post_challenge_hook

490

)

491

```