Skip to content

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:

LayerDetection MethodBypass Difficulty
NetworkIP reputation, TLS fingerprint, ASNMedium
BrowserCanvas, WebGL, audio fingerprintHandled by GoLogin
BehaviorMouse patterns, timing, scrollingHigh
ContextRequest patterns, session behaviorHigh
ML-BasedPattern recognition, anomaly detectionVery 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

  1. Layer your defenses — Use GoLogin fingerprinting + behavioral emulation + smart request patterns
  2. Match everything — Proxy location, timezone, locale, and language must be consistent
  3. Act human — Variable timing, natural mouse movement, realistic typing
  4. Build trust — Warm profiles with organic activity before heavy automation
  5. Monitor and adapt — Track block rates and adjust strategy in real-time
  6. Rotate intelligently — Don’t rotate too fast or too slow

Next Steps