npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tls-impersonate

v0.1.0

Published

TLS fingerprint control within Node.js's normal networking APIs

Readme

TLS Impersonate Build Status Available on NPM

Part of HTTP Toolkit: powerful tools for building, testing & debugging HTTP(S)

Reproduce arbitrary TLS ClientHello fingerprints (JA3/JA4) while using Node.js's normal networking APIs.

Servers and anti-bot systems increasingly fingerprint the exact shape of a TLS ClientHello - its cipher suites, extensions, supported groups and their ordering - to tell real browsers apart from other clients. Node.js sends its own recognisable fingerprint, and limited options to change it.

This library takes a target ClientHello specification and builds a standard tls.SecureContext which reproduces that fingerprint as closely as possible. The result plugs straight into tls.connect, https, or any Node API that accepts a secure context, and can perfectly match Chrome, Firefox, Safari, curl, and others on modern Node releases.

Installation

This requires Node >= 24.15.0, and >= 26.4.0 is strongly recommended as it's required to fully match browser fingerprints.

npm install tls-impersonate

This is a native module, but prebuilds are included for most platforms.

Usage

Pass a full ClientHello specification to impersonate(), then spread ...tlsOptions into your connection options:

import * as tls from 'node:tls';
import { impersonate } from 'tls-impersonate';

const { tlsOptions, unsupported } = impersonate({
    cipherSuites: [0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f, /* ... */],
    extensions: [
        { type: 0x0000 }, // server_name
        { type: 0x0017 }, // extended_master_secret
        { type: 0x0010 }, // ALPN
        // ...in wire order, including GREASE
    ],
    supportedGroups: [0x001d, 0x0017, 0x0018],
    signatureAlgorithms: [0x0403, 0x0804, 0x0401],
    alpnProtocols: ['h2', 'http/1.1']
});

const socket = tls.connect({
    host: 'testserver.host',
    port: 443,
    servername: 'testserver.host',
    ...tlsOptions
});

The options configured in TLS options are those supported by Node's built-in tls module and can be passed to any function which accepts these - this includes the built-in https module and anything else which passes options through to it.

impersonate() never throws for parts of the fingerprint it can't reproduce - it always produces the closest achievable ClientHello and reports any gaps in the unsupported array, so you can log or monitor them:

for (const gap of unsupported) {
    console.warn(`Could not reproduce ${gap.kind} ${gap.id}: ${gap.reason}`);
}

Impersonating a captured ClientHello

If you have a real ClientHello parsed with read-tls-client-hello, you can pass it straight in - no need to build a spec by hand:

import { impersonateFromClientHello } from 'tls-impersonate';
import { readTlsClientHello } from 'read-tls-client-hello';

const hello = await readTlsClientHello(capturedStream);
const { tlsOptions } = impersonateFromClientHello(hello);

const socket = tls.connect({
    host: 'testserver.host',
    port: 443,
    servername: 'testserver.host',
    ...tlsOptions
});

Security

By default, tls-impersonate will never reduce the security of TLS connections. It will not change the OpenSSL security level, and although it advertises some legacy features it will reject any connections that attempt to use them.

This works for almost all fingerprints, but not 100% of cases. If this is not sufficient (as reported by the unsupported result) you can pass securiry: 'insecure' to allow tls-impersonate to enable known-insecure configurations. This should be avoided unless absolutely necessary, and this isn't required to match the fingerprints of most clients (browsers, Android HTTP libraries, etc).

Feature detection

Impersonation depends on internals that are only present on supported modern Node runtimes. Check availability once at startup and fall back to Node's default TLS if it's missing:

import { isSupported } from 'tls-impersonate';

if (!isSupported()) {
    // Wrong Node version, unsupported platform, or the native addon failed to load.
}