Advanced Stealth Techniques
When basic stealth isn’t enough, these advanced techniques help you bypass the most sophisticated detection systems. This guide covers strategies for sites with enterprise-grade bot protection.
Understanding Advanced Detection
Modern detection uses multiple layers:
| Layer | Detection Method | Bypass Difficulty |
|---|---|---|
| Network | IP reputation, TLS fingerprint, ASN | Medium |
| Browser | Canvas, WebGL, audio fingerprint | Handled by GoLogin |
| Behavior | Mouse patterns, timing, scrolling | High |
| Context | Request patterns, session behavior | High |
| ML-Based | Pattern recognition, anomaly detection | Very High |
Behavioral Emulation
Human-Like Mouse Movement
Robotic mouse movement is a major detection vector:
import { GoLogin } from '@gologin/sdk';import puppeteer from 'puppeteer-core';
async function humanMove(page: any, targetX: number, targetY: number) { const mouse = page.mouse; const { x: startX, y: startY } = await page.evaluate(() => ({ x: window.mouseX || 0, y: window.mouseY || 0 }));
// Calculate bezier curve control points for natural movement const cp1x = startX + (targetX - startX) * 0.3 + (Math.random() - 0.5) * 100; const cp1y = startY + (targetY - startY) * 0.3 + (Math.random() - 0.5) * 100; const cp2x = startX + (targetX - startX) * 0.7 + (Math.random() - 0.5) * 50; const cp2y = startY + (targetY - startY) * 0.7 + (Math.random() - 0.5) * 50;
// Move along bezier curve with variable speed const steps = 20 + Math.floor(Math.random() * 10); for (let i = 0; i <= steps; i++) { const t = i / steps; const x = bezier(t, startX, cp1x, cp2x, targetX); const y = bezier(t, startY, cp1y, cp2y, targetY);
await mouse.move(x, y); await page.waitForTimeout(5 + Math.random() * 15); }}
function bezier(t: number, p0: number, p1: number, p2: number, p3: number) { const cX = 3 * (p1 - p0); const bX = 3 * (p2 - p1) - cX; const aX = p3 - p0 - cX - bX; return aX * t ** 3 + bX * t ** 2 + cX * t + p0;}Realistic Typing
Typing patterns are heavily analyzed:
async function humanType(page: any, selector: string, text: string) { await page.click(selector); await page.waitForTimeout(100 + Math.random() * 200);
for (const char of text) { // Variable delay between keystrokes const delay = getTypingDelay(char); await page.waitForTimeout(delay);
// Occasionally make and correct typos (optional) if (Math.random() < 0.02) { const typo = getAdjacentKey(char); await page.keyboard.type(typo); await page.waitForTimeout(100 + Math.random() * 300); await page.keyboard.press('Backspace'); await page.waitForTimeout(50 + Math.random() * 100); }
await page.keyboard.type(char); }}
function getTypingDelay(char: string): number { // Longer delays after punctuation and spaces if (['.', ',', '!', '?'].includes(char)) return 200 + Math.random() * 300; if (char === ' ') return 80 + Math.random() * 120;
// Normal character delay return 50 + Math.random() * 100;}Natural Scrolling
async function humanScroll(page: any, targetY: number) { const currentY = await page.evaluate(() => window.scrollY); const distance = targetY - currentY; const direction = distance > 0 ? 1 : -1; const steps = Math.abs(distance / 100);
for (let i = 0; i < steps; i++) { // Variable scroll amount with momentum simulation const scrollAmount = direction * (80 + Math.random() * 40); await page.mouse.wheel({ deltaY: scrollAmount });
// Decreasing delays simulate momentum const delay = Math.max(20, 100 - i * 5) + Math.random() * 30; await page.waitForTimeout(delay); }
// Small overshoot and correction (mimics touchpad behavior) if (Math.random() < 0.3) { await page.mouse.wheel({ deltaY: direction * 30 }); await page.waitForTimeout(200); await page.mouse.wheel({ deltaY: -direction * 30 }); }}Request Timing Patterns
Avoid Detection Patterns
class RequestThrottler { private lastRequestTime = 0; private requestCount = 0;
async waitForNextRequest(): Promise<void> { // Increase delay as session progresses const baseDelay = this.getBaseDelay();
// Add jitter const jitter = baseDelay * (0.3 + Math.random() * 0.4); const delay = baseDelay + jitter;
const elapsed = Date.now() - this.lastRequestTime; if (elapsed < delay) { await new Promise(r => setTimeout(r, delay - elapsed)); }
this.lastRequestTime = Date.now(); this.requestCount++; }
private getBaseDelay(): number { // Human-like browsing: fast at first, slows down if (this.requestCount < 5) return 500; if (this.requestCount < 20) return 1500; if (this.requestCount < 50) return 3000; return 5000; }}Session Patterns
Real users have predictable session patterns:
class SessionManager { async simulateRealSession(page: any, tasks: (() => Promise<void>)[]) { // Start with some idle time (reading) await page.waitForTimeout(2000 + Math.random() * 3000);
for (let i = 0; i < tasks.length; i++) { await tasks[i]();
// Vary behavior based on position in session if (i < tasks.length - 1) { // Read/think time between actions await page.waitForTimeout(1000 + Math.random() * 4000);
// Occasionally longer pauses (checking phone, etc.) if (Math.random() < 0.1) { await page.waitForTimeout(10000 + Math.random() * 20000); } } }
// Linger before leaving await page.waitForTimeout(1000 + Math.random() * 2000); }}Advanced Profile Configuration
Geographic Consistency
Ensure all settings match your proxy location:
import { GoLogin } from '@gologin/sdk';
const gologin = new GoLogin({ profileName: 'us-east-profile',
// All settings must match the proxy location proxy: { type: 'http', host: 'us-east.proxy.com', port: 8080, },
// Timezone matches proxy city timezone: 'America/New_York',
// Language matches region locale: 'en-US',
// Platform should be common for region platform: 'windows',
fingerprint: { navigator: { // Common US browser configuration languages: ['en-US', 'en'], }, screen: { // Common US resolution width: 1920, height: 1080, }, },});WebRTC Leak Prevention
WebRTC can expose your real IP:
const gologin = new GoLogin({ profileName: 'webrtc-protected',
// Disable WebRTC or use proxy for STUN fingerprint: { webrtc: { mode: 'proxy', // Options: 'disabled', 'proxy', 'real' }, },});Multi-Layer Proxy Strategy
Proxy Chains
For extra anonymity:
class ProxyChain { private proxies: ProxyConfig[]; private currentIndex = 0;
constructor(proxies: ProxyConfig[]) { this.proxies = proxies; }
// Rotate proxies per session getNext(): ProxyConfig { const proxy = this.proxies[this.currentIndex]; this.currentIndex = (this.currentIndex + 1) % this.proxies.length; return proxy; }
// Use different proxy types for different phases getForPhase(phase: 'warmup' | 'production'): ProxyConfig { if (phase === 'warmup') { // Use datacenter during warmup (cheaper) return this.proxies.find(p => p.type === 'datacenter')!; } // Use residential for production (more trusted) return this.proxies.find(p => p.type === 'residential')!; }}IP Reputation Management
class IPReputationTracker { private ipStats: Map<string, { successes: number; failures: number }> = new Map();
recordResult(ip: string, success: boolean) { const stats = this.ipStats.get(ip) || { successes: 0, failures: 0 }; if (success) stats.successes++; else stats.failures++; this.ipStats.set(ip, stats); }
getReputationScore(ip: string): number { const stats = this.ipStats.get(ip); if (!stats) return 0.5; // Unknown const total = stats.successes + stats.failures; return stats.successes / total; }
getBestIPs(count: number): string[] { return Array.from(this.ipStats.entries()) .sort((a, b) => this.getReputationScore(b[0]) - this.getReputationScore(a[0])) .slice(0, count) .map(([ip]) => ip); }}Handling Challenges
CAPTCHA Detection
async function detectCaptcha(page: any): Promise<boolean> { const indicators = [ 'iframe[src*="recaptcha"]', 'iframe[src*="hcaptcha"]', 'iframe[src*="captcha"]', '#captcha', '.captcha', '[data-captcha]', ];
for (const selector of indicators) { const element = await page.$(selector); if (element) return true; }
// Check for challenge pages const content = await page.content(); if (content.includes('challenge-running') || content.includes('captcha-solver')) { return true; }
return false;}Challenge Response Strategy
async function handleChallenge(page: any, options: { maxRetries: number; cooldownMs: number;}) { for (let attempt = 0; attempt < options.maxRetries; attempt++) { const hasCaptcha = await detectCaptcha(page);
if (!hasCaptcha) { return { success: true }; }
console.log(`Challenge detected, attempt ${attempt + 1}`);
// Options: // 1. Wait and retry (some challenges are temporary) // 2. Switch profile // 3. Switch proxy // 4. Use CAPTCHA service
await page.waitForTimeout(options.cooldownMs); await page.reload(); }
return { success: false, reason: 'challenge_persistent' };}Session Warming
Building Trust Over Time
async function warmProfile(page: any, config: { sites: string[]; actionsPerSite: number; daysToWarm: number;}) { // Simulate natural browsing over time for (let day = 0; day < config.daysToWarm; day++) { for (const site of config.sites) { await page.goto(site);
// Perform natural actions for (let i = 0; i < config.actionsPerSite; i++) { await humanScroll(page, Math.random() * 1000); await page.waitForTimeout(1000 + Math.random() * 3000);
// Click random links const links = await page.$$('a[href^="/"]'); if (links.length > 0) { const randomLink = links[Math.floor(Math.random() * links.length)]; await randomLink.click(); await page.waitForNavigation({ waitUntil: 'networkidle0' }); } }
// Realistic session end await page.waitForTimeout(5000 + Math.random() * 10000); }
// Wait between "days" (in real usage, actually wait a day) console.log(`Day ${day + 1} warming complete`); }}Monitoring and Adaptation
Detection Response
class DetectionMonitor { private consecutiveBlocks = 0; private totalRequests = 0; private blockedRequests = 0;
recordRequest(blocked: boolean) { this.totalRequests++; if (blocked) { this.blockedRequests++; this.consecutiveBlocks++; } else { this.consecutiveBlocks = 0; } }
getBlockRate(): number { return this.blockedRequests / this.totalRequests; }
shouldRotateProfile(): boolean { return this.consecutiveBlocks >= 3; }
shouldRotateProxy(): boolean { return this.consecutiveBlocks >= 2; }
shouldCooldown(): boolean { return this.getBlockRate() > 0.3; }
getRecommendedAction(): 'continue' | 'rotate_proxy' | 'rotate_profile' | 'cooldown' { if (this.shouldCooldown()) return 'cooldown'; if (this.shouldRotateProfile()) return 'rotate_profile'; if (this.shouldRotateProxy()) return 'rotate_proxy'; return 'continue'; }}Best Practices Summary
- Layer your defenses — Use GoLogin fingerprinting + behavioral emulation + smart request patterns
- Match everything — Proxy location, timezone, locale, and language must be consistent
- Act human — Variable timing, natural mouse movement, realistic typing
- Build trust — Warm profiles with organic activity before heavy automation
- Monitor and adapt — Track block rates and adjust strategy in real-time
- Rotate intelligently — Don’t rotate too fast or too slow
Next Steps
- Bypass Cloudflare Guide — Specific techniques for Cloudflare
- Proxy Rotation Guide — Optimize your proxy strategy
- Profile Management — Manage profiles at scale