Stealth

Stealth Overview

Rezo’s stealth module makes your HTTP requests indistinguishable from real browser traffic. Anti-bot systems like Cloudflare, Akamai, and DataDome identify automated clients by analyzing TLS fingerprints (JA3/JA4), HTTP/2 SETTINGS frames, header ordering, and client hints. RezoStealth controls all of these signals, presenting a consistent browser identity across every request.

How It Works

When you attach a RezoStealth instance to a Rezo client, it resolves a complete browser profile that governs:

  • TLS fingerprint — cipher suites, signature algorithms, ECDH curves, ALPN protocols, all in exact browser order
  • HTTP/2 SETTINGSHEADER_TABLE_SIZE, INITIAL_WINDOW_SIZE, MAX_CONCURRENT_STREAMS, and connection window size matching the target browser
  • Header ordering — headers sent in the exact order a real browser would send them
  • Client hintssec-ch-ua, sec-ch-ua-platform, sec-ch-ua-mobile for Chromium browsers
  • Sec-Fetch metadatasec-fetch-site, sec-fetch-mode, sec-fetch-user, sec-fetch-dest
  • Navigator properties — consistent platform, hardwareConcurrency, deviceMemory, maxTouchPoints

The RezoStealth Class

import { Rezo } from 'rezo';
import { RezoStealth } from 'rezo/stealth';

The constructor accepts an optional input that determines which browser profile to use:

// Auto-detect from the User-Agent header in your config
const stealth = new RezoStealth();

// Use a specific named profile
const stealth = new RezoStealth('chrome-131');

// Random profile from a browser family
const stealth = new RezoStealth({ family: 'chrome' });

// Random profile from a family with a specific platform
const stealth = new RezoStealth({ family: 'chrome', platform: 'windows' });

// Rotate to a fresh identity on every request
const stealth = new RezoStealth({ rotate: true });

// Rotate within a family
const stealth = new RezoStealth({ rotate: true, family: 'firefox' });

Modes of Operation

Exact Profile

Pass a profile name string to use a specific browser version:

const rezo = new Rezo({
  stealth: new RezoStealth('chrome-131')
});

const res = await rezo.get('https://example.com');
// All requests use Chrome 131 fingerprint, headers, and TLS settings

Family Random

Pass a family option to pick a random version within that browser family:

const rezo = new Rezo({
  stealth: new RezoStealth({ family: 'firefox' })
});
// Picks one of: firefox-115, firefox-121, firefox-128, firefox-133

Full Random

Omit profile and family to get a completely random browser profile:

const rezo = new Rezo({
  stealth: RezoStealth.random()
});
// Could be any of the 18 available profiles

Auto-Detect from User-Agent

Construct with no arguments. The stealth module parses your User-Agent header and selects the closest matching profile:

const rezo = new Rezo({
  stealth: new RezoStealth(),
  headers: {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
  }
});
// Detects Chrome 131 from the UA and uses chrome-131 profile

Rotate Per Request

Enable rotate: true to generate a fresh browser identity for every resolve() call. This is concurrency-safe — each request gets its own profile:

const rezo = new Rezo({
  stealth: new RezoStealth({ rotate: true })
});

// Request 1: might use safari-18.2 on macOS
await rezo.get('https://example.com/page1');

// Request 2: might use chrome-128 on Windows
await rezo.get('https://example.com/page2');

You can constrain rotation to a family:

const rezo = new Rezo({
  stealth: new RezoStealth({ rotate: true, family: 'chrome' })
});
// Every request picks a random Chrome version

Factory Methods

RezoStealth provides static factories for common configurations:

// Specific profile by name
const stealth = RezoStealth.from('safari-17.4');

// Random within a family
const stealth = RezoStealth.chrome();   // random Chrome profile
const stealth = RezoStealth.firefox();  // random Firefox profile
const stealth = RezoStealth.safari();   // random Safari profile
const stealth = RezoStealth.edge();     // random Edge profile

// Fully random from any browser
const stealth = RezoStealth.random();

// Auto-detect from a User-Agent string
const stealth = RezoStealth.fromUserAgent(
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15'
);
// Returns a Safari 18.2 stealth profile

Integration with Rezo

Pass the stealth instance in the Rezo constructor options:

import { Rezo } from 'rezo';
import { RezoStealth } from 'rezo/stealth';

const client = new Rezo({
  stealth: RezoStealth.chrome(),
  baseURL: 'https://protected-site.com'
});

// All requests now use Chrome TLS fingerprint, header order, client hints, etc.
const response = await client.get('/api/data');

Overriding Specific Values

Use RezoStealthOptions to selectively override parts of a profile while keeping the rest intact:

const rezo = new Rezo({
  stealth: new RezoStealth({
    profile: 'chrome-131',
    platform: 'macos',
    language: 'fr-FR,fr;q=0.9,en;q=0.8',
    headers: {
      'accept-language': 'fr-FR,fr;q=0.9'
    }
  })
});

Reading Resolved Values

After resolution, you can inspect the stealth profile:

const stealth = RezoStealth.chrome();

console.log(stealth.profileName);   // e.g. "chrome-128"
console.log(stealth.profile.family); // "chrome"
console.log(stealth.profile.engine); // "blink"

Runtime Considerations

Bun Runtime

Bun uses BoringSSL (the same TLS library as Chrome), which means it can produce a Chrome-like JA3/JA4 fingerprint natively. Stealth with Bun works against virtually all TLS fingerprinting systems.

Node.js Runtime

Node.js uses OpenSSL, which cannot produce a Chrome-like JA3/JA4 fingerprint regardless of cipher configuration. For production stealth against advanced anti-bot systems (Cloudflare, Akamai, DataDome), consider using curl-impersonate via the cURL adapter, which patches BoringSSL for Chrome-identical TLS behavior.

Stealth on Node.js still provides correct header ordering, client hints, HTTP/2 SETTINGS, and User-Agent management — it only falls short on the TLS fingerprint itself.