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:
- Parses the decrypted HTTP request
- Logs to
globalTrafficBufferfor analysis - Forwards to the original destination using
tlsFetchwith 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-jsresponses into spec-compliant nativeResponseobjects
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=truein your environment - Use
tlsFetchfromopen-sse/utils/tlsClient.tsfor direct, fingerprinted HTTP requests that return nativeResponseobjects - Leverage
sessionScopeto isolate cookies and circuit state between logical sessions - Deploy TPROXY capture via
src/mitm/tproxy/tlsCapture.tswhen transparent interception and logging are required - Rely on automatic fallback to standard Node/Undici when TLS fingerprinting is disabled or
wreq-jsis 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →