Configuring TLS Fingerprint Stealth with OmniRoute: A Complete Guide

OmniRoute disguises outbound TLS handshakes to mimic real web browsers, bypassing bot-detection systems that inspect JA3/JA4 fingerprints by using the wreq-js library to generate Chrome-style TLS client hellos.

TLS fingerprint stealth is essential for avoiding detection by modern anti-bot systems. OmniRoute implements this capability through a transport layer that forges browser-like TLS handshakes, making automated requests indistinguishable from genuine user traffic. This article covers how to enable, configure, and deploy TLS fingerprinting in OmniRoute based on the actual source code implementation.

How TLS Fingerprint Stealth Works in OmniRoute

The stealth system operates through two complementary components that work together to mask automation signatures.

Core Components

Component Purpose Source Location
TLS fingerprint transport Generates Chrome-style TLS client hellos using wreq-js and forwards requests through the forged TLS stack open-sse/utils/tlsClient.ts
TPROXY capture (optional) Terminates inbound TLS, decrypts requests, logs traffic, then re-encrypts outbound traffic with the forged fingerprint src/mitm/tproxy/tlsCapture.ts

Both components remain disabled by default. Activation requires a single environment variable.

Enabling TLS Fingerprint Mode

Set the environment variable ENABLE_TLS_FINGERPRINT to true:

export ENABLE_TLS_FINGERPRINT=true

Or in a .env file:


# .env

ENABLE_TLS_FINGERPRINT=true

When enabled, the runtime attempts to require("wreq-js"). If the module is missing, OmniRoute prints a warning and silently disables TLS fingerprint transport, falling back to standard Node.js HTTP behavior.

Using the TLS-Aware Fetch Helper

The primary interface for TLS fingerprinted requests is tlsFetch from open-sse/utils/tlsClient.ts. This function wraps wreq-js sessions and returns native Response objects compatible with the standard Fetch API.

Basic Usage Pattern

import { tlsFetch } from "@/open-sse/utils/tlsClient";

const response = await tlsFetch("https://api.example.com/v1/data", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ query: "hello" }),
});

const data = await response.json();

Advanced Configuration Options

Option Description Implementation Detail
proxy HTTP/HTTPS proxy for the request Respects HTTPS_PROXY → HTTP_PROXY → ALL_PROXY precedence (lines 45-53)
sessionScope Isolates cookies and circuit-breaker state Creates separate wreq-js sessions per scope (line 76)
timeout Request timeout in milliseconds Defaults to getTlsClientTimeoutConfig() value (line 3)

Complete Example with Session Scoping

import { tlsFetch } from "@/open-sse/utils/tlsClient";

// Isolated session for account-specific state
const response = await tlsFetch("https://api.example.com/v1/data", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ query: "hello" }),
  proxy: "http://proxy.local:3128",
  sessionScope: "account-42", // Cookies and circuit state isolated to this account
});

The sessionScope parameter ensures that cookie jars and circuit-breaker state remain separated across different logical sessions, preventing cross-contamination between accounts or connection contexts.

Implementing TPROXY Capture for Transparent Interception

For deployments requiring full traffic inspection, the TPROXY capture layer in src/mitm/tproxy/tlsCapture.ts terminates TLS on the inbound side, logs decrypted traffic, then re-encrypts using the forged fingerprint.

Setting Up the Capture Server

import http from "node:http";
import { handleDecryptedRequest } from "@/src/mitm/tproxy/tlsCapture";

http.createServer((req, res) => {
  // `dest` provided by transparent listener (original destination)
  const dest = { 
    ip: "93.184.216.34", 
    port: 443, 
    sni: "api.example.com" 
  };
  
  handleDecryptedRequest(req, res, dest, {
    buffer: globalTrafficBuffer,
    forward: realForward,
    now: () => performance.now(),
    randomId: () => randomUUID(),
  });
}).listen(8080);

The handleDecryptedRequest function:

  1. Parses the decrypted HTTP request
  2. Logs to globalTrafficBuffer for analysis
  3. Forwards to the original destination using tlsFetch with the forged fingerprint

This creates a transparent proxy chain: inbound TLS terminates, traffic is inspected, then outbound TLS uses browser-like fingerprints to reach target servers.

Fallback Behavior When TLS Fingerprinting Is Disabled

When ENABLE_TLS_FINGERPRINT is unset or false, OmniRoute automatically falls back to the standard Node/Undici HTTP client stack:

process.env.ENABLE_TLS_FINGERPRINT = "false";

import { tlsFetch } from "@/open-sse/utils/tlsClient";

// Uses regular Node/Undici without TLS forgery
const response = await tlsFetch("https://example.org");

This fallback preserves original behavior and performance characteristics, ensuring no dependency on wreq-js for deployments that don't require stealth.

Key Implementation Details from Source Code

The tlsClient.ts file (lines 27-99) handles critical normalization tasks:

  • Header normalization: Ensures consistent header ordering and casing to match browser signatures
  • Error sanitization: Strips internal implementation details from error responses
  • Response adaptation: Converts wreq-js responses into spec-compliant native Response objects

Proxy resolution follows conventional precedence:

// Lines 45-53 in tlsClient.ts
const proxy = options.proxy 
  || process.env.HTTPS_PROXY 
  || process.env.HTTP_PROXY 
  || process.env.ALL_PROXY;

Timeout configuration merges with global fetch settings through getTlsClientTimeoutConfig(), ensuring consistent behavior across all HTTP operations in OmniRoute.

Service Layer Integration

For internal OmniRoute executors, open-sse/services/tlsClientProxy.ts exposes the TLS fingerprint transport as a reusable service. This abstraction allows multiple request paths to share the same wreq-js session management and fingerprint configuration without direct dependency on the lower-level tlsClient.ts module.

Essential Source Files Reference

File Purpose Direct Link
open-sse/utils/tlsClient.ts Core tlsFetch implementation, wreq-js integration, response adaptation View source
open-sse/services/tlsClientProxy.ts Service abstraction for executor consumption View source
src/mitm/tproxy/tlsCapture.ts TPROXY TLS termination and re-encryption View source
docs/reference/ENVIRONMENT.md Environment variable documentation View docs
docs/security/STEALTH_GUIDE.md Broader stealth technique coverage View docs

Summary

  • Enable TLS fingerprint stealth by setting ENABLE_TLS_FINGERPRINT=true in your environment
  • Use tlsFetch from open-sse/utils/tlsClient.ts for direct, fingerprinted HTTP requests that return native Response objects
  • Leverage sessionScope to isolate cookies and circuit state between logical sessions
  • Deploy TPROXY capture via src/mitm/tproxy/tlsCapture.ts when transparent interception and logging are required
  • Rely on automatic fallback to standard Node/Undici when TLS fingerprinting is disabled or wreq-js is unavailable

Frequently Asked Questions

What is a TLS fingerprint and why does it matter for bot detection?

A TLS fingerprint is a hash of the parameters in a TLS Client Hello message—cipher suites, extensions, and supported versions. Anti-bot systems like Cloudflare and DataDome use JA3/JA4 fingerprints to identify automated tools, which typically present different signatures than real browsers. OmniRoute's stealth mode forges Chrome-compatible fingerprints to evade these detection mechanisms.

Does OmniRoute require wreq-js as a runtime dependency?

No. wreq-js is loaded dynamically via require() only when ENABLE_TLS_FINGERPRINT=true. If the module is absent, OmniRoute prints a warning and continues with normal HTTP behavior. This optional dependency design keeps deployments lightweight when stealth features aren't needed.

Can I use TLS fingerprinting with rotating proxies?

Yes. The proxy option in tlsFetch accepts any HTTP/HTTPS proxy URL, and proxy configuration follows standard environment variable precedence. Combine with sessionScope to maintain separate cookie jars across different proxy endpoints, ensuring clean identity separation per connection.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →