Aturannya pendek: pakai sticky session kalau satu alur menyentuh lebih dari satu halaman (login, checkout, form bertingkat), dan rotating session kalau tiap request berdiri sendiri (daftar produk, pemantauan harga).
Gejala salah pilih khas: task ke in.php sukses, res.php mengembalikan token valid, tetapi form menjawab "verifikasi gagal". Penyebabnya bukan solver, melainkan IP yang berganti antara solve dan submit.
Cara kerja kedua mode sesi
STICKY SESSION:
Request 1 ──▶ IP: 192.168.1.50 ──▶ site.com/login
Request 2 ──▶ IP: 192.168.1.50 ──▶ site.com/dashboard
Request 3 ──▶ IP: 192.168.1.50 ──▶ site.com/account
(Same IP for all requests in the session window)
ROTATING SESSION:
Request 1 ──▶ IP: 192.168.1.50 ──▶ site.com/page1
Request 2 ──▶ IP: 10.0.0.77 ──▶ site.com/page2
Request 3 ──▶ IP: 172.16.5.22 ──▶ site.com/page3
(Different IP per request)
Intinya satu: apakah IP Anda bertahan sepanjang jendela sesi, atau diganti tiap request.
Matriks keputusan: mode mana untuk alur kerja apa
Kalau hanya sempat membaca satu tabel, baca ini.
| Alur kerja | Mode | Alasan |
|---|---|---|
| Login / pendaftaran | Sticky | Token terikat pada IP peminta |
| Checkout / pembayaran | Sticky | Cookie sesi butuh IP konsisten |
| Form ber-CAPTCHA | Sticky | Pengikatan token–IP |
| Pengambilan banyak halaman | Rotating | Beban tersebar ke banyak IP |
| Hasil mesin pencari | Rotating | Rate limiting per IP |
| Pemantauan harga | Rotating | Request saling independen |
Faktor pembeda yang menentukan
- IP per request: sticky menahan satu IP 1–30 menit, rotating mengganti tiap request.
- Frekuensi tantangan: sticky lebih tenang di alur multi-langkah, rotating lebih tenang di halaman tunggal.
- Validitas token: sticky lebih aman; rotating berisiko IP tidak cocok saat submit.
- Risiko IP terblokir: lebih tinggi pada sticky karena request menumpuk di satu alamat.
Kecepatan dan biaya jaringan praktis setara.
Kapan sticky session wajib dipakai
Tanda alur Anda menuntut sticky session:
- Ada cookie atau header autentikasi yang harus bertahan antar-request.
- Tantangan muncul di satu halaman, tokennya dipakai di halaman berikutnya.
- Server menolak dengan pesan sesi tidak valid meski kredensial benar.
Alur multi-langkah dan pengikatan token ke IP
CAPTCHA memvalidasi token terhadap IP peminta. Begitu IP berubah antara pembuatan token dan pengiriman form, server berhak menolaknya — jadi muat halaman, selesaikan tantangan, dan kirim form pada satu IP.
import requests
import time
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
# Sticky session: same IP for the entire login flow
STICKY_PROXY = {
"http": "http://user-session-abc123:pass@proxy.example.com:5000",
"https": "http://user-session-abc123:pass@proxy.example.com:5000",
}
session = requests.Session()
session.proxies = STICKY_PROXY
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
})
def login_with_captcha(url, sitekey, username, password):
"""Full login flow — MUST use same IP throughout."""
# Step 1: Load login page (IP: 192.168.1.50)
session.get(url)
# Step 2: Solve CAPTCHA (solved against IP: 192.168.1.50)
token = solve_recaptcha(sitekey, url)
# Step 3: Submit login (MUST be IP: 192.168.1.50)
resp = session.post(url, data={
"username": username,
"password": password,
"g-recaptcha-response": token,
})
return resp.status_code == 200
def solve_recaptcha(sitekey, pageurl):
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
"key": CAPTCHAAI_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
data = result.json()
if data["request"] != "CAPCHA_NOT_READY":
return data["request"]
raise TimeoutError("CAPTCHA solve timeout")
Kenapa konsistensi IP menentukan hasil
Sticky session:
1. Browser loads page → IP: 5.5.5.5
2. CAPTCHA solved → Token bound to session
3. Form submitted → IP: 5.5.5.5 ✅ Token accepted
Rotating session:
1. Browser loads page → IP: 5.5.5.5
2. CAPTCHA solved → Token bound to session
3. Form submitted → IP: 9.9.9.9 ❌ Token may be rejected
Aturan praktisnya: satu alur bisnis, satu session ID.
Berapa lama TTL sticky sebaiknya disetel
- 1 menit — form singkat; berisiko kedaluwarsa di tengah alur.
- 5 menit — login plus aksi lanjutan; keseimbangan paling aman.
- 10 menit — alur multi-halaman kompleks; risiko sedang.
- 30–60 menit — operasi akun panjang; risiko tertinggi.
Setel TTL sekitar dua kali perkiraan waktu alur. Untuk worker di AWS ap-southeast-1 (Singapura) atau ap-southeast-3 (Jakarta), sisakan margin latensi: TTL 5 menit yang longgar di laptop bisa terlalu ketat di produksi.
Kapan rotating session lebih menguntungkan
Pengambilan banyak halaman independen
Setiap halaman berdiri sendiri, tanpa cookie yang perlu dijaga. Rotasi menyebarkan request ke kumpulan IP lebih besar sehingga hitungan per IP rendah.
import concurrent.futures
ROTATING_PROXY = {
"http": "http://user:pass@rotating.proxy.example.com:5000",
"https": "http://user:pass@rotating.proxy.example.com:5000",
}
def scrape_page(url):
"""Each request gets a fresh IP automatically."""
resp = requests.get(
url,
proxies=ROTATING_PROXY,
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"},
timeout=30,
)
if resp.status_code == 200:
return url, resp.text
return url, None
urls = [f"https://example.com/products?page={i}" for i in range(1, 501)]
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as pool:
results = list(pool.map(scrape_page, urls))
success = sum(1 for _, html in results if html)
print(f"Scraped: {success}/{len(urls)}")
Pengambilan hasil mesin pencari
Mesin pencari menghitung volume kueri per IP. Rotasi mencegah hitungan menumpuk di satu alamat:
def scrape_search(query, pages=10):
results = []
for page in range(pages):
# Each request → new IP
resp = requests.get(
"https://search-engine.example.com/search",
params={"q": query, "start": page * 10},
proxies=ROTATING_PROXY,
timeout=20,
)
results.append(resp.text)
time.sleep(2)
return results
Catatan kepatuhan di Indonesia: UU Pelindungan Data Pribadi (UU 27/2022) menjadikan pemilihan target pengambilan data keputusan hukum, bukan sekadar teknis. Ambil hanya data publik yang boleh Anda proses.
Pendekatan hibrid dalam satu pipeline
Kebanyakan pipeline produksi memakai keduanya: sticky untuk bagian ber-state, rotating untuk sisanya.
class HybridProxyManager:
"""Sticky for multi-step flows, rotating for single requests."""
def __init__(self, provider_host, username, password, port=5000):
self.host = provider_host
self.username = username
self.password = password
self.port = port
def get_rotating_proxy(self):
return {
"http": f"http://{self.username}:{self.password}@{self.host}:{self.port}",
"https": f"http://{self.username}:{self.password}@{self.host}:{self.port}",
}
def get_sticky_proxy(self, session_id, duration_min=10):
sticky_user = f"{self.username}-session-{session_id}-ttl-{duration_min}"
return {
"http": f"http://{sticky_user}:{self.password}@{self.host}:{self.port}",
"https": f"http://{sticky_user}:{self.password}@{self.host}:{self.port}",
}
proxy_mgr = HybridProxyManager("proxy.example.com", "user", "pass")
def scrape_with_auto_strategy(url, needs_login=False):
if needs_login:
# Multi-step → sticky
import uuid
session_id = uuid.uuid4().hex[:8]
proxy = proxy_mgr.get_sticky_proxy(session_id)
else:
# Single page → rotating
proxy = proxy_mgr.get_rotating_proxy()
return requests.get(url, proxies=proxy, timeout=30)
Implementasi Node.js
Pola yang sama dengan axios, lewat satu helper pemilih mode:
const axios = require("axios");
const CAPTCHAAI_KEY = "YOUR_API_KEY";
const PROXY_HOST = "proxy.example.com";
const PROXY_PORT = 5000;
function getProxy(mode, sessionId = null) {
const user =
mode === "sticky" ? `user-session-${sessionId}` : "user";
return {
proxy: {
host: PROXY_HOST,
port: PROXY_PORT,
auth: { username: user, password: "pass" },
},
};
}
// Rotating: bulk scrape
async function scrapePages(urls) {
const results = [];
for (const url of urls) {
const config = getProxy("rotating");
const resp = await axios.get(url, { ...config, timeout: 30000 });
results.push({ url, data: resp.data });
}
return results;
}
// Sticky: login flow
async function loginFlow(loginUrl, sitekey, credentials) {
const sessionId = Date.now().toString(36);
const config = getProxy("sticky", sessionId);
// Step 1: Load page
await axios.get(loginUrl, config);
// Step 2: Solve CAPTCHA
const submitResp = await axios.post(
"https://ocr.captchaai.com/in.php",
null,
{
params: {
key: CAPTCHAAI_KEY,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: loginUrl,
json: 1,
},
}
);
const taskId = submitResp.data.request;
let token;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const res = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: CAPTCHAAI_KEY, action: "get", id: taskId, json: 1 },
});
if (res.data.request !== "CAPCHA_NOT_READY") {
token = res.data.request;
break;
}
}
// Step 3: Submit with same IP
return axios.post(
loginUrl,
{
...credentials,
"g-recaptcha-response": token,
},
config
);
}
Diagnosis cepat saat hasilnya meleset
Lima gejala berikut menutupi hampir semua kasus produksi.
| Gejala | Penyebab | Perbaikan |
|---|---|---|
| Token ditolak padahal solve berhasil | IP berganti antara solve dan submit | Pindah ke sticky |
| CAPTCHA sering muncul di halaman tunggal | Satu IP menyentuh terlalu banyak halaman | Pindah ke rotating |
| Cookie sesi hilang di tengah alur | Sticky kedaluwarsa | Perbesar TTL |
| Rotating terasa lambat | Overhead koneksi tiap IP | Aktifkan connection pooling |
| IP terblokir saat sticky aktif | Request menumpuk di IP tertandai | Perpendek TTL |
Urutan pemeriksaan yang efisien:
- Bandingkan IP keluar tepat sebelum solve dan tepat sebelum submit.
- Pastikan TTL sticky masih hidup saat form dikirim.
- Baru setelah keduanya bersih, curigai sitekey atau parameter task.
Biaya: yang sebenarnya berubah
Yang bergeser bukan tagihan jaringan, melainkan jumlah tantangan CAPTCHA yang muncul. Penagihan CaptchaAI berbasis thread, bukan per solve — dari BASIC ($15/bulan, 5 thread) sampai VIP-3 ($7,500/bulan, 5.000 thread). Mode yang keliru memperpanjang antrean thread sehingga throughput turun di paket yang sama. Bagi freelancer otomatisasi dan agensi pemantauan harga dengan anggaran tetap per proyek, membenahi mode sesi lebih murah daripada menaikkan paket.
Format session ID berbeda antar penyedia; pengaturannya dibahas terpisah untuk Bright Data, Smartproxy, dan Oxylabs.
Pertanyaan umum
Kenapa token saya valid tetapi form tetap ditolak?
Periksa apakah IP berubah antara solve dan submit: token dibuat untuk satu IP lalu dikirim dari IP lain. Kunci seluruh alur ke satu sticky session.
Berapa lama TTL sticky yang aman untuk alur login?
Mulai dari 5 menit. Naikkan hanya bila alur Anda benar-benar lebih panjang, karena TTL besar menumpuk request di satu IP.
Bisakah dua mode dipakai dalam satu proyek?
Bisa, dan itu pola yang disarankan: sticky untuk autentikasi, rotating untuk pengumpulan data, seperti HybridProxyManager di atas.
Tipe CAPTCHA apa saja yang bisa ditangani pada alur seperti ini?
- reCAPTCHA v2 dan v3, Cloudflare Turnstile, GeeTest v3.
- CaptchaFox (beta), Friendly Captcha (beta), Lemin (beta).
- hCaptcha dan FunCaptcha tidak didukung; GeeTest v4 berstatus segera hadir.
Bacaan lanjutan
Lanjutan yang paling sering dibutuhkan: rotasi egress jaringan yang diotorisasi, pengaruh kualitas jaringan pada tingkat keberhasilan solve, dan cara menjaga state sesi browser.
Cocokkan mode sesi dengan alur kerja Anda — ambil API key CaptchaAI dan ukur sendiri selisihnya.