Cara Memecahkan CAPTCHA DataDome di Node.js dengan fetch

Untuk memecahkan CAPTCHA DataDome di Node.js, Anda membaca halaman blokir 403, membangun alamat challenge darinya, lalu mengirim alamat itu ke pemecah DataDome CapSkip dengan dataDome(), dan mengulangi permintaan Anda dengan cookie yang dikembalikan. Jawabannya adalah cookie, bukan token untuk formulir, dan dokumentasi CapSkip menyebut bahwa cookie itu biasanya hanya berfungsi dengan User-Agent dan alamat IP yang dipakai saat memperolehnya. Panduan ini menjalankan seluruh loop dengan SDK Node.js CapSkip dan fetch dalam sekitar 100 baris. CapSkip berjalan di PC Windows Anda sendiri tanpa biaya per pemecahan, jadi percobaan ulang tidak dikenai biaya pemecahan.
Apa yang Anda butuhkan
- CapSkip 3.2.0 atau lebih baru yang berjalan di PC Windows. Rilis itu menambahkan pemecahan DataDome untuk slider dan device check. Lihat panduan penyiapan untuk menjalankannya pertama kali.
- Node.js dan paket capskip versi 1.5.0 atau lebih baru. Versi sebelumnya tidak memiliki metode dataDome. Paket ini menyatakan Node.js 18 atau lebih baru. Saya hanya menjalankan kode di Node.js 24.22.0, dengan capskip 1.5.0 dan undici 8.12.3, jadi Node.js 18 tidak diuji di sini. Paket undici 8 menyatakan Node.js 22.19 atau lebih baru. Menurut engines yang mereka nyatakan, undici 7 memerlukan Node.js 20.18.1 atau lebih baru dan undici 6 memerlukan Node.js 18.17 atau lebih baru, jadi Node.js yang lebih lama memerlukan undici yang lebih lama. Saya tidak menjalankan keduanya.
- Command prompt tempat node dan npm berfungsi.
- Halaman milik Anda atau yang boleh Anda otomatisasi, di balik DataDome.
- Sebuah alamat untuk pemecah CAPTCHA. Dalam mode Local, CapSkip menjawab di 127.0.0.1 hanya untuk perangkat itu. Dalam mode Server, CapSkip mendengarkan di alamat jaringan atau IP publik Anda, sehingga skrip di PC lain, VPS, atau platform hosting dapat menjangkaunya melalui API. Keduanya diatur di pengaturan koneksi.
- Sebuah proxy sticky (proxy yang mempertahankan alamat IP yang sama) untuk setiap task setelah Anda melewati tahap pengujian. Cookie terikat pada alamat IP yang memperolehnya, seperti dijelaskan di Langkah 3.
Instal kedua paket dengan npm install capskip undici. Node.js sudah menyertakan fetch, tetapi tidak punya opsi proxy per permintaan. Paket undici menambahkannya lewat ProxyAgent, jadi kode juga mengimpor fetch dari undici. Memberikan ProxyAgent undici 8.12.3 ke fetch bawaan Node.js 24.22.0 gagal di lingkungan saya dengan error fetch failed, yang penyebabnya berbunyi invalid onRequestStart method (kode error UND_ERR_INVALID_ARG), karena Node.js itu menyertakan undici 7.29.1. Mengambil keduanya dari satu paket menghindari ketidakcocokan itu.
Cara pengujiannya: kode dijalankan terhadap tiga server mock (server pengganti yang dibuat khusus untuk pengujian) yang saya tulis, bukan terhadap situs DataDome sungguhan. Satu meniru pemeriksaan CapSkip yang tercantum di bagian DataDome pada Dokumentasi API, satu berperan sebagai situs terlindungi yang menyajikan halaman blokir 403 dan hanya menerima cookie yang diterbitkan CapSkip, dengan User-Agent yang dipakai saat cookie itu diterbitkan, dan satu lagi berperan sebagai forward proxy. SDK-nya adalah capskip 1.5.0 yang asli. Aplikasi CapSkip berjalan di PC saya, tetapi setiap skrip diarahkan ke mock, jadi aplikasi tidak memecahkan apa pun. Tidak ada hal di sini yang menunjukkan berapa lama pemecahan sungguhan berlangsung atau apa yang diterima situs DataDome yang aktif. Parsing halaman blokir hanya dicoba pada halaman yang meniru format di dokumentasi CapSkip. Jalur proxy diuji dengan proxy http yang meneruskan permintaan biasa ke situs http. Tunnel yang dibutuhkan situs https melalui proxy tidak diuji, begitu pula proxy https. Aturan tentang cookie berasal dari dokumentasi CapSkip. Sedangkan dokumentasi cookie milik DataDome sendiri menyatakan bahwa cookie datadome berlaku selama satu tahun dan memperingatkan agar Domain atau Path-nya tidak diubah. Dokumentasi itu tidak menyebut cookie tersebut terikat pada apa.
Langkah 1: baca halaman blokir dan bangun captcha_url
Letakkan blok ini dan tiga blok berikutnya dalam satu file bernama datadome-demo.js, sesuai urutan yang ditampilkan. Tidak ada yang berjalan sampai Langkah 4.
Ketika DataDome meragukan sebuah permintaan, situs menjawab dengan status 403, kadang 401, dan halaman HTML kecil sebagai ganti konten. Halaman itu berisi objek skrip bernama dd dan memuat challenge dalam iframe dari geo.captcha-delivery.com. Alamat iframe itulah yang dibutuhkan CapSkip, dan dokumentasi menyebutnya captchaUrl. Jika halaman sudah berisi iframe, Anda bisa mengambil src-nya apa adanya. Sebagian besar halaman blokir membangun iframe dengan skrip, jadi fungsi di bawah merakit alamat yang sama dari objek dd.
Nilai rt menentukan jalurnya. Huruf c berarti slider di bawah /captcha/, dan huruf i berarti device check di bawah /interstitial/. Nilai t juga penting: nilai fe menandai sebuah challenge, dan nilai bv berarti DataDome telah memblokir alamat IP yang mengambil halaman itu. Permintaan pertama dikirim dengan User-Agent Chrome biasa. String itu tidak pernah dikirim ke CapSkip, jadi versi Chrome-nya tidak harus cocok dengan apa pun. Saya tidak menguji apakah situs DataDome yang aktif memberikan challenge yang sama kepada User-Agent yang berbeda, jadi anggap bagian itu belum teruji.
Fungsi get membaca seluruh isi respons sebelum mengembalikannya, jadi tidak ada koneksi yang dibiarkan menunggu. Berikan alamat proxy dan fungsi ini mengirim permintaan melalui ProxyAgent milik undici, yang menerima proxy http atau https. Saya tidak mencoba proxy SOCKS.
// npm install capskip undici
const { fetch, ProxyAgent } = require("undici");
const PAGE_URL = "https://www.example.com/"; // a page behind DataDome
const BROWSER = { // for the first request only; the cookie comes with its own User-Agent
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
+ "(KHTML, like Gecko) Chrome/156.0.0.0 Safari/537.36",
};
const agents = new Map(); // one ProxyAgent per proxy, so sockets are reused
async function get(headers, proxyUrl) {
const options = { headers };
if (proxyUrl) {
if (!agents.has(proxyUrl)) agents.set(proxyUrl, new ProxyAgent(proxyUrl));
options.dispatcher = agents.get(proxyUrl);
}
const resp = await fetch(PAGE_URL, options);
return { status: resp.status, text: await resp.text(), setCookies: resp.headers.getSetCookie() };
}
// Build the challenge address from a DataDome block page, or null.
function captchaUrlFrom(page) {
if (![401, 403].includes(page.status)) return null;
const found = page.text.match(/var\s+dd\s*=\s*(\{[^}]*\})/);
if (!found) return null;
const dd = JSON.parse(found[1].replace(/'/g, "\""));
const path = dd.rt === "i" ? "interstitial" : "captcha";
const query = new URLSearchParams({ initialCid: dd.cid, hash: dd.hsh, cid: dd.cookie });
if (dd.t) query.set("t", dd.t); // fe is a challenge, bv means the address is banned
query.set("referer", PAGE_URL);
query.set("s", String(dd.s));
for (const key of ["e", "b"]) {
if (dd[key]) query.set(key, String(dd[key]));
}
query.set("dm", "cd");
return `https://${dd.host || "geo.captcha-delivery.com"}/${path}/?${query}`;
}Fungsi ini mengembalikan null untuk respons apa pun yang bukan halaman blokir, sehingga skrip dapat membedakan “tidak ada yang perlu dipecahkan” dari “sudah dipecahkan”. Halaman yang tidak berada di balik DataDome, seperti alamat placeholder di kode, hanya mencetak 200. Setiap halaman blokir adalah challenge baru. Pakai captchaUrl-nya segera, dan minta halaman lagi untuk task berikutnya alih-alih memakai ulang alamat lama.
Langkah 2: pecahkan dengan dataDome()
Metode SDK-nya adalah dataDome(captchaUrl, url, options), yang mengikuti urutan argumen 2Captcha. Dua yang pertama wajib. Di CapSkip, userAgent dan proxy bersifat opsional dan masuk ke objek options. Jika Anda tidak mengirim User-Agent, CapSkip memakai milik browsernya sendiri dan mengembalikannya sebagai userAgent di hasil. Jika Anda mengirimnya, harus Chrome untuk Windows dengan versi mayor yang sama dengan browser CapSkip, jadi tidak mengirimnya adalah pilihan yang mudah. Metode ini menunggu dengan timeout 300 detik yang lebih panjang, yang juga dipakai reCAPTCHA, karena CapSkip melewati challenge di browser sungguhan. Dokumentasi API menyebut pemecahan biasanya memakan 3 sampai 20 detik, dan saya tidak mengukur satu pun.
Proxy adalah proxy yang akan dipakai permintaan Anda berikutnya. Berikan jika skrip Anda keluar melalui proxy, dan jangan berikan apa pun jika permintaan keluar dari mesin yang menjalankan CapSkip. Jika CapSkip berada di server, mesin itu adalah server tersebut. Opsi yang dibiarkan undefined tidak dikirim, jadi proxyOption bisa mengembalikan undefined untuk kasus tanpa proxy.
const { CapSkip } = require("capskip");
// Local mode. In Server mode, use your server's address instead.
const solver = new CapSkip({ host: "127.0.0.1", port: 8080 });
function proxyOption(proxyUrl) {
if (!proxyUrl) return undefined; // your requests leave from the PC that runs CapSkip
const [scheme, rest] = proxyUrl.split("://");
return { type: scheme.toUpperCase(), uri: rest }; // e.g. HTTP, user:pass@ip:port
}
function solve(captchaUrl, proxyUrl) {
// No userAgent option: CapSkip uses its own browser's and reports it.
return solver.dataDome(captchaUrl, PAGE_URL, { proxy: proxyOption(proxyUrl) });
}Jika device check tidak bisa dipenuhi, DataDome beralih ke slider. Menurut dokumentasi CapSkip, satu panggilan yang sama mengikutinya ke sana, jadi Anda tidak memerlukan kode terpisah untuk kedua challenge itu.
Langkah 3: kirim cookie dengan User-Agent dan alamat IP-nya
Hasilnya adalah objek dengan empat field yang penting. Field code adalah cookie persis seperti yang diatur DataDome, lengkap dengan Max-Age, Domain, dan atribut lainnya, yang dibutuhkan cookie jar. Field cookie hanya berisi pasangan nama dan nilai datadome, yang dibutuhkan header Cookie. Field userAgent adalah User-Agent yang memperolehnya. Field proxy muncul hanya jika Anda tidak mengirim proxy dan CapSkip memecahkan melalui daftar proxy DataDome bawaannya sendiri. Dokumentasi CapSkip menyebut DataDome biasanya menolak cookie dari alamat IP lain atau dengan User-Agent lain, jadi kirim User-Agent yang sama setiap kali, dan ketika hasilnya menyebut sebuah proxy, kirim permintaan melalui proxy itu. Field proxy itu hanya berisi host dan port, tanpa skema dan tanpa login. Fungsi ini menambahkan http:// sehingga mengasumsikan proxy daftar yang tidak memerlukan login. Jika proxy daftar Anda memerlukannya, tulis sendiri di alamatnya, seperti http://user:pass@ diikuti host dan port.
DataDome juga bisa mengirim cookie pengganti pada respons berikutnya. Fungsi ini membaca baris Set-Cookie dan menyimpan yang terbaru, seperti yang dilakukan sebuah browser.
async function sendWithCookie(result, proxyUrl) {
// The cookie works only from the address and User-Agent that earned it.
let via = proxyUrl;
if (!via && result.proxy) {
via = `http://${result.proxy}`; // CapSkip solved through its own list
}
const headers = { "User-Agent": result.userAgent, Cookie: result.cookie };
const page = await get(headers, via);
for (const line of page.setCookies) { // DataDome may rotate the cookie
const fresh = line.match(/^datadome=([^;]+)/);
if (fresh) headers.Cookie = `datadome=${fresh[1]}`;
}
return { page, headers, via };
}Cookie diatur secara manual di header, jadi tidak ada yang mengelolanya untuk Anda. Itu disengaja: cara ini menjaga cookie, User-Agent, dan proxy tetap bersama di satu tempat. Teks setelah skema dikirim ke CapSkip persis seperti yang Anda tulis, jadi jaga agar login proxy bebas dari karakter yang memerlukan percent-encoding.
Langkah 4: contoh lengkap yang berfungsi
Blok terakhir menyatukan langkah-langkah menjadi satu alur dan menambahkan percobaan ulang. Simpan di akhir file datadome-demo.js yang sama dan jalankan dengan node datadome-demo.js. Setiap percobaan meminta halaman lagi, jadi tiap percobaan membawa challenge baru. Pemecahan yang gagal memunculkan ApiException dan loop mencoba lagi. Cookie yang tetap mendapat 403 juga membuat loop berputar lagi, dengan halaman blokir yang baru. Halaman yang menjawab 403 tanpa halaman blokir DataDome menghentikan loop dengan error, karena tidak ada yang perlu dipecahkan. Setiap percobaan ulang mengambil halaman blokir lain dari situs, jadi jaga agar jumlah percobaan tetap rendah.
const { ApiException } = require("capskip");
const PROXY_URL = null; // e.g. "http://user:[email protected]:8080"; null means no proxy
async function fetchProtected(proxyUrl) {
for (let attempt = 1; attempt <= 3; attempt += 1) {
const block = await get(BROWSER, proxyUrl); // a fresh block page, a fresh challenge
const captchaUrl = captchaUrlFrom(block);
if (captchaUrl === null) {
if (block.status >= 400) {
throw new Error(`HTTP ${block.status} without a DataDome block page`);
}
return { page: block, headers: BROWSER, via: proxyUrl }; // no block page here
}
let result;
try {
result = await solve(captchaUrl, proxyUrl);
} catch (err) {
if (!(err instanceof ApiException)) throw err;
if (err.message.includes("ERROR_PROXY_")) throw err; // the address is the problem
console.log(`attempt ${attempt}: ${err.message}`); // the next attempt gets a new page
continue;
}
const sent = await sendWithCookie(result, proxyUrl);
if (sent.page.status !== 200) {
console.log(`attempt ${attempt}: HTTP ${sent.page.status} with the cookie`);
continue;
}
return sent;
}
throw new Error("DataDome not passed in 3 attempts");
}
async function main() {
const { page, headers, via } = await fetchProtected(PROXY_URL);
console.log(page.status, page.text.slice(0, 40));
const again = await get(headers, via); // reuse the cookie while it lasts
console.log(again.status);
}
main().catch((err) => {
console.error(`${err.name}: ${err.message}`);
process.exitCode = 1;
});SDK menolak captchaUrl dengan t=bv sebelum mengirim apa pun, karena tidak ada pemecahan dari alamat itu yang bisa lolos. ValidationException itu bukan ApiException, jadi loop melemparnya ulang alih-alih mencoba lagi. Biarkan muncul: itu adalah sinyal untuk mengganti alamat dan mulai dari awal. Loop juga melempar ulang dua error yang berkaitan dengan alamat IP, ERROR_PROXY_BANNED dan ERROR_PROXY_CONNECT_REFUSED, karena dokumentasi CapSkip menyebut bahwa mengirim ulang melalui alamat IP yang sama akan gagal lagi. Pesan ApiException adalah teks balasan aplikasi, jadi loop mencocokkannya dengan includes() dan bukan dengan perbandingan persis. Jika Anda melihat salah satu error ini, ganti proxy sebelum menjalankan lagi. Pembahasan lengkapnya ada di panduan rotasi proxy.
Pada eksekusi mock, skrip berperilaku seperti ini di Node.js 24.22.0:
| Pengaturan mock | Yang dilakukan skrip |
|---|---|
| Halaman blokir slider, setiap pemecahan dijawab | Satu task, lalu status 200 dengan cookie, dan 200 lagi saat dipakai ulang |
| Halaman blokir device check | Kode yang sama berjalan: captchaUrl menunjuk ke /interstitial/ dan hasilnya sama |
| Dua pemecahan pertama ditolak | Dua baris percobaan, lalu status 200 pada task ketiga |
| Tiga pemecahan pertama ditolak | Tiga baris percobaan, lalu Error “DataDome not passed in 3 attempts” dan exit code 1 |
| Hasil menyebut sebuah proxy, seperti daftar milik CapSkip sendiri | Permintaan dengan cookie melewati proxy itu dan mendapat 200 |
| Proxy Anda sendiri diteruskan ke pemecahan | in.php menerima alamat proxy dan tipe HTTP, dan setiap permintaan melewati proxy |
| Halaman blokir dengan t=bv | ValidationException, dan mock CapSkip tidak melihat permintaan sama sekali |
| Pemecahan dipaksa gagal dengan ERROR_PROXY_BANNED di skrip | Loop melempar ulang error itu setelah satu task, tanpa percobaan kedua |
| Halaman 403 yang bukan halaman blokir DataDome | Error “HTTP 403 without a DataDome block page” dan exit code 1, tanpa permintaan ke CapSkip |
| Cookie dikirim dengan User-Agent yang berbeda | Situs mock menjawab 403 |
| Cookie diterbitkan melalui proxy, dikirim tanpa proxy | Situs mock menjawab 403, dan 200 ketika cookie yang sama dikirim melalui proxy |
Dua baris terakhir menguji aturan mock saya, yang mengikuti dokumentasi CapSkip. Keduanya bukan bukti tentang layanan yang sebenarnya.
Kesalahan umum
| Kesalahan | Penyebab | Perbaiki |
|---|---|---|
| ValidationException | captchaUrl yang bukan alamat challenge DataDome, halaman blokir dengan t=bv, pageurl yang bukan http atau https, atau userAgent yang bukan Chrome standar untuk Windows. Pesannya menyebut mana dari semua itu yang terjadi | Bangun ulang alamat dari halaman blokir yang baru, ganti alamat IP jika diblokir, dan hapus opsi userAgent |
| ApiException dengan pesan ERROR_WRONG_USERAGENT | User-Agent adalah Chrome untuk Windows, tetapi versi mayornya berbeda dari browser CapSkip. Mock memberikan ini untuk Chrome 120 | Jangan kirim userAgent dan pakai yang dilaporkan hasilnya |
| ApiException dengan ERROR_BAD_PARAMETERS | Aplikasi CapSkip yang sedang berjalan memberikan ini untuk alamat yang bukan alamat challenge, ketika saya mengirimnya secara manual. SDK menolak alamat seperti itu sebelum mengirim apa pun | Bangun ulang alamat dari halaman blokir yang baru |
| ApiException dengan ERROR_CAPTCHA_UNSOLVABLE | Challenge tidak berhasil dilewati | Minta halaman lagi dan kirim captchaUrl barunya |
| ApiException dengan ERROR_PROXY_BANNED | DataDome memblokir alamat IP selama pemecahan. Halaman blokir yang menyebut t=bv tertangkap lebih awal, sebagai ValidationException | Ganti proxy dan minta halaman lagi |
| ApiException dengan ERROR_PROXY_CONNECT_REFUSED | CapSkip melaporkannya ketika tidak bisa terhubung melalui proxy. Saya tidak mereproduksinya | Periksa alamat proxy, login, dan tipe, lalu jalankan skrip lagi |
| TimeoutException | CapSkip tidak memberi jawaban dalam waktu tunggu 300 detik. Ini bukan ApiException, jadi loop melemparnya ulang | Pastikan CapSkip berjalan dan memecahkan, lalu jalankan skrip lagi |
| NetworkException | CapSkip tidak berjalan, atau host atau port-nya salah. Port tanpa pendengar memberikan ECONNREFUSED dalam NetworkException, yang bukan ApiException | Jalankan CapSkip dan periksa pengaturan koneksi |
| Tetap 403 dengan cookie | Permintaan keluar dari alamat IP lain, memakai User-Agent lain, atau cookie sudah kedaluwarsa | Kirim userAgent dan proxy dari hasilnya setiap kali, atau jalankan loop lagi dengan halaman blokir yang baru |
Menjalankan solver di sebuah server
Skrip untuk CAPTCHA DataDome di Node.js memerlukan dua hal dari CapSkip: host dan port. Dalam mode Local itu adalah 127.0.0.1 dan PC Anda sendiri. Dalam mode Server, CapSkip mendengarkan di alamat jaringan atau IP publik Anda, sehingga skrip di PC lain, VPS, atau platform hosting dapat memanggilnya melalui API yang sama. Ubah host dan port di konstruktor CapSkip. IP publik statis disarankan untuk akses jarak jauh yang stabil. Mode Server tetap berjalan di hardware Anda sendiri dan tetap tanpa meteran. Mode Server memang membuka port untuk semua alamat, jadi tambahkan aturan blokir Windows Firewall untuk alamat yang tidak boleh menjangkaunya. Satu hal memang berubah: pemecahan berjalan di mesin itu, jadi cookie diperoleh dari alamat IP server. Kecuali Anda memberikan proxy, permintaan yang membawa cookie juga harus keluar dari server itu. Dengan proxy, berikan proxy yang sama untuk pemecahan dan untuk permintaan Anda. Lihat pengaturan koneksi untuk cara beralih mode.
FAQ
Apakah pemecah DataDome mengembalikan token?
Tidak. Pemecah ini mengembalikan cookie datadome. Anda mengirim cookie itu di header Cookie pada permintaan yang diblokir, bersama User-Agent yang sama. Tidak ada field formulir yang perlu diisi.
Apakah saya memerlukan proxy untuk DataDome?
Tidak untuk pengujian. Satu alamat IP sudah cukup untuk percobaan pertama. Menurut dokumentasi CapSkip, cookie hanya berfungsi dari alamat IP yang memperolehnya, jadi begitu Anda mengirim banyak permintaan, rencanakan satu proxy sticky per task dan berikan proxy yang sama itu untuk pemecahan dan untuk permintaan Anda. Proxy adalah satu-satunya bagian di panduan ini yang memerlukan library di luar SDK, karena fetch tidak punya opsi proxy per permintaan sendiri.
Apakah ini berfungsi untuk slider maupun device check?
Ya, lewat panggilan yang sama. captchaUrl untuk slider berada di bawah /captcha/ dan untuk device check di bawah /interstitial/. Dokumentasi CapSkip menyebut bahwa device check yang naik menjadi slider akan diikuti ke sana.
Bisakah saya memecahkan CAPTCHA DataDome di Node.js tanpa browser?
Skrip Anda tidak memerlukan browser. Skrip itu mengirim permintaan HTTP biasa ke CapSkip dan ke situs, dan CapSkip melewati challenge di browser sungguhan pada mesin tempat CapSkip berjalan, seperti yang dijelaskan dokumentasi SDK.
Bisakah platform hosting menjalankan ini terhadap CapSkip saya?
Bisa, lewat mode Server. Atur CapSkip untuk mendengarkan di jaringan atau IP publik Anda, arahkan konstruktor CapSkip ke host dan port itu, dan loop bekerja sama, dengan satu perubahan: pemecahan kini berjalan di server, jadi berikan proxy yang sama untuk pemecahan dan untuk permintaan Anda. Pemecah tetap berjalan di hardware Anda.
Versi singkatnya
Sebuah CAPTCHA DataDome di Node.js memerlukan empat langkah: baca halaman blokir, bangun captchaUrl, panggil dataDome(), dan ulangi permintaan dengan cookie, User-Agent, dan alamat IP yang terikat padanya. Pemecahan tidak dikenai biaya di mesin Anda sendiri, dan itulah yang Anda harapkan dari pemecah captcha tanpa batas saat situs yang dilindungi terus memberi Anda challenge baru, meskipun setiap percobaan ulang mengambil halaman blokir lain, jadi jaga agar jumlahnya tetap rendah. Untuk bagian SDK lainnya, lihat halaman pemecah CAPTCHA Node.js. Alur yang sama di Python ada di panduan DataDome Python.
