DataDome Solving with Surfsky
Overview
DataDome is a bot protection system used by many e-commerce and high-traffic websites. Surfsky handles DataDome challenges in a few ways: automatic solving per request, auto-solve enabled for the session, or targeting a specific challenge type (audio or slider).
Watch the video below for a visual demonstration:
Quick Start
For most use cases, our simplified CAPTCHA solving approach handles DataDome automatically. See the CAPTCHA Solving Guide for full details.
Prerequisites
- Enable
anti_captchain your browser profile settings - Gemini API Key (only for audio challenges) - Get one from Google AI Studio
- Pass it when starting your browser. See API Reference for details
- Not required for slider challenges (
datadome_click)
- Use quality proxies to minimize DataDome challenges
Challenge Types
DataDome serves different challenge types depending on risk score, device, and site configuration. Surfsky supports all three:
| Type | What it is | Gemini key needed? |
|---|---|---|
datadome | Default pipeline (currently audio under the hood) | Yes |
datadome_audio | Audio challenge — listen and type the numbers | Yes |
datadome_click | Slider challenge — drag the puzzle to the target | No |
When to use which:
- Default (
datadome) — auto-picks the audio pipeline. Works on most DataDome pages as long as a Gemini API key is configured. datadome_click— use when the page serves a slider/puzzle challenge (you'll see asliderContainerelement inside the captcha iframe). No AI needed; the solver reads the slider/target positions and drags with human-like motion. Keep this in mind if you don't want to provision a Gemini key.datadome_audio— force the audio flow explicitly.
You can either pass the specific type to Captcha.solve / Captcha.autoSolve, or let detection pick for you by enabling both in auto_captcha_types.
Reducing challenges
DataDome is sensitive to automation patterns. A few things help:
- Use residential or mobile proxies — datacenter IPs get challenged more often.
- Rotate proxies every 3–5 requests for aggressive scraping.
- Add delays and use Human Emulation for mouse and keyboard.
- Reuse profiles that already passed a DataDome challenge — the cookies are good for 25+ follow-up requests.
Solving Methods
Method 1: Simple Manual Solving (Recommended)
Detect the challenge and solve it when it appears:
- Python
- JavaScript
import asyncio
from playwright.async_api import async_playwright
async def solve_datadome_simple():
async with async_playwright() as p:
# Connect to your Surfsky browser
browser = await p.chromium.connect_over_cdp("ws://your-browser-url")
page = await browser.new_page()
# Create CDP session
client = await page.context.new_cdp_session(page)
# Navigate to DataDome protected site
await page.goto("https://example.com/protected")
# Check if DataDome challenge appears
if await page.query_selector('iframe[src*="datadome"]'):
print("DataDome detected, solving...")
# Solve DataDome
response = await client.send("Captcha.solve", {"type": "datadome"})
if response.get("status") == "success":
print("✓ DataDome solved!")
# Page will reload automatically with solution
await page.wait_for_load_state("networkidle")
# Continue scraping
content = await page.content()
print("Page loaded successfully")
else:
print("✗ Failed to solve DataDome")
await browser.close()
asyncio.run(solve_datadome_simple())
const { chromium } = require('playwright');
async function solveDatadomeSimple() {
// Connect to your Surfsky browser
const browser = await chromium.connectOverCDP('ws://your-browser-url');
const page = await browser.newPage();
// Create CDP session
const client = await page.context().newCDPSession(page);
// Navigate to DataDome protected site
await page.goto('https://example.com/protected');
// Check if DataDome challenge appears
const datadomeFrame = await page.$('iframe[src*="datadome"]');
if (datadomeFrame) {
console.log('DataDome detected, solving...');
// Solve DataDome
const response = await client.send('Captcha.solve', { type: 'datadome' });
if (response.status === 'success') {
console.log('✓ DataDome solved!');
// Page will reload automatically with solution
await page.waitForLoadState('networkidle');
// Continue scraping
const content = await page.content();
console.log('Page loaded successfully');
} else {
console.log('✗ Failed to solve DataDome');
}
}
await browser.close();
}
solveDatadomeSimple().catch(console.error);
Method 2: Auto Solving
Let the browser automatically handle DataDome challenges:
- Python
- JavaScript
import asyncio
from playwright.async_api import async_playwright
async def solve_datadome_auto():
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp("ws://your-browser-url")
page = await browser.new_page()
client = await page.context.new_cdp_session(page)
# Enable auto-solving for DataDome
await client.send("Captcha.autoSolve", {"type": "datadome"})
print("Auto-solve activated - DataDome will be solved automatically")
# Navigate to any page - DataDome challenges will be handled automatically
await page.goto("https://example.com/protected")
# Continue with your scraping
# Any DataDome that appears will be solved in the background
await browser.close()
asyncio.run(solve_datadome_auto())
const { chromium } = require('playwright');
async function solveDatadomeAuto() {
const browser = await chromium.connectOverCDP('ws://your-browser-url');
const page = await browser.newPage();
const client = await page.context().newCDPSession(page);
// Enable auto-solving for DataDome
await client.send('Captcha.autoSolve', { type: 'datadome' });
console.log('Auto-solve activated - DataDome will be solved automatically');
// Navigate to any page - DataDome challenges will be handled automatically
await page.goto('https://example.com/protected');
// Continue with your scraping
// Any DataDome that appears will be solved in the background
await browser.close();
}
solveDatadomeAuto().catch(console.error);
Solving a Slider Challenge (no Gemini required)
If you only need to handle slider challenges, or want to avoid provisioning a Gemini API key, target the datadome_click type explicitly:
- Python
- JavaScript
# Detect and solve only the slider challenge
if await page.query_selector('iframe[src*="captcha-delivery.com"]'):
response = await client.send("Captcha.solve", {"type": "datadome_click"})
if response.get("status") == "success":
print("✓ Slider solved!")
# Or enable auto-solving for slider-only:
await client.send("Captcha.autoSolve", {"type": "datadome_click"})
// Detect and solve only the slider challenge
const captchaFrame = await page.$('iframe[src*="captcha-delivery.com"]');
if (captchaFrame) {
const response = await client.send('Captcha.solve', { type: 'datadome_click' });
if (response.status === 'success') {
console.log('✓ Slider solved!');
}
}
// Or enable auto-solving for slider-only:
await client.send('Captcha.autoSolve', { type: 'datadome_click' });
DataDome-Specific Tips
If you see t=bv in the DataDome URL, your IP is banned:
- Switch to a new proxy immediately
- Consider using a different proxy provider
- Reduce request frequency
datadome_click is a good fit when you want to avoid the Gemini dependency entirely and your target mostly serves slider puzzles.
Need Help?
For more details on CAPTCHA solving, see the CAPTCHA Solving Guide.
For advanced proxy management and error handling, check our API Reference.
Questions? Contact us at [email protected].