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

js-tls-fetcher

v0.1.0

Published

HTTPS requests with a chosen TLS fingerprint (named browser profile or raw JA3) through an optional proxy. Real Chrome/Firefox/Safari JA3/JA4 + HTTP/2 fingerprints via a Go (uTLS/tls-client) helper process.

Downloads

25

Readme

js-tls-fetcher

CI

A request handler that performs HTTPS requests with a chosen TLS fingerprint — a named browser profile or a raw JA3 string — through an optional proxy (http/https/socks5, with auth). Real Chrome/Firefox/Safari TLS and HTTP/2 fingerprints, driven by bogdanfinn/tls-client (uTLS under the hood).

Ships three ways to use it:

  1. Go libraryfetcher package.
  2. Go CLIcmd/fetch, rotates fingerprints + proxies over a target.
  3. Node packagenode/, a JS API that runs requests through a Go helper process (the working, real-fingerprint way to use this from Node).

Purpose

Servers increasingly identify clients by how they speak TLS and HTTP/2 — the byte shape of the TLS ClientHello (JA3/JA4) and the HTTP/2 preamble — not just by the User-Agent header. tls-fetcher makes a request that is consistent all the way down: TLS fingerprint, HTTP/2 fingerprint, and headers all match a chosen real browser (or a raw JA3 you supply), optionally through a proxy. Use it as the request engine for fingerprint-aware endpoints, or to test the fingerprint defenses of a service you run.

Documentation

  • CLAUDE.md — orientation + commands + gotchas (also for Claude Code).
  • docs/ARCHITECTURE.md — design, data flow, the three fingerprints, why-not-WASM, and how the fingerprints were verified.

Why a Go subprocess for Node (and not WASM)

TLS fingerprinting works by opening a raw TCP socket and writing a hand-crafted TLS ClientHello. A WASM sandbox — both js/wasm and Node's WASI — has no raw sockets; any network call is forced through the host's fetch, which uses Node/V8's own TLS stack and fixes the JA3 to Node's fingerprint. So Go→WASM can run, but it cannot impersonate — the feature is impossible there.

The working pattern (also how CycleTLS and node-tls-client operate) is to keep the Go code as a native binary and have Node talk to it. This package does that over newline-delimited JSON on stdio: one long-lived Go process, many concurrent requests correlated by id. Pure Go, no CGO — cross-compiles to darwin/arm64, linux, windows.

Install

# From GitHub (works today, no registry needed):
npm install github:Elalitareq/js-tls-fetcher

# Pin to a release tag (recommended for servers):
npm install github:Elalitareq/js-tls-fetcher#v0.1.0

# From npm, once a v-tag has been published:
npm install js-tls-fetcher

On install, a postinstall step obtains the native Go helper for your platform:

  1. builds it with go build if a Go toolchain is present, else
  2. downloads the prebuilt binary for your OS/arch from this repo's Releases.

It never hard-fails the install. If both routes fail (no Go and no matching release asset), run npm run build manually or drop a binary into node_modules/js-tls-fetcher/node/bin/. Supported: darwin/linux/windows on x64 or arm64.

Node quick start

import { TlsClient } from "js-tls-fetcher";

const client = new TlsClient();                 // spawns the Go helper

// named browser profile
const a = await client.request({
  url: "https://tls.peet.ws/api/all",
  profile: "chrome_146",
  proxy: "http://user:pass@host:port",          // optional
});
console.log(a.status, a.json());

// raw JA3 (custom fingerprint) + POST
const b = await client.request({
  url: "https://example.com/api",
  method: "POST",
  ja3: "771,4865-4866-4867-49195-49199,0-23-65281-10-11-16-5-13-43-51-45-18,29-23-24,0",
  userAgent: "Mozilla/5.0 ...",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ hello: "world" }),
});
console.log(b.status, b.text());

client.close();

Response object: { status, proto, headers, ms, ok, error, body(Buffer), text(), json() }.

npm test runs an end-to-end test (Node → Go → local echo server): named profile, raw JA3, POST body, custom headers, and 25 correlated concurrent requests.

Distribution note

The helper is a native binary, so ship one per platform (or go build on install). Cross-build examples:

GOOS=darwin  GOARCH=arm64 CGO_ENABLED=0 go build -o node/bin/tlsfetch-server        ./cmd/server
GOOS=linux   GOARCH=amd64 CGO_ENABLED=0 go build -o node/bin/tlsfetch-server        ./cmd/server
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o node/bin/tlsfetch-server.exe    ./cmd/server

Go library

import "tls-fetcher/fetcher"

h := fetcher.New(30, false) // timeout seconds, followRedirect
res := h.Do(fetcher.Job{
    URL:   "https://example.com",
    Proxy: "socks5://host:1080",              // optional
    FP:    fetcher.Fingerprint{Profile: "chrome_146", UserAgent: "..."},
    // or FP: fetcher.Fingerprint{JA3: "771,4865-...", UserAgent: "..."},
})
fmt.Println(res.Status, res.Proto, len(res.Body), res.Err)

Clients are cached per (fingerprint + proxy) so repeated jobs reuse connections.

Named profiles: chrome_120/131/133/144/146, firefox_132/135/148, safari_16, safari_ios_17_0/18_0/18_5/26_0. A raw JA3 overrides the profile; JA3 fields it can't encode (sig-algs, versions, key-share curves, ALPN/ALPS, ECH, cert-compression) are filled with modern-Chrome-like defaults — edit customProfileFromJA3 if you feed non-Chrome JA3s and need exact parity.

Go CLI — rotate fingerprints + proxies

Feed the fingerprint files from the companion generators straight in (each line has ja3/profile + user_agent):

go run ./cmd/fetch -url https://tls.peet.ws/api/all \
  -fingerprints chrome_fingerprints.jsonl \
  -proxies proxies.txt \
  -n 100 -c 20 -rotate random -out results.jsonl

proxies.txt is one proxy per line (http://user:pass@host:port, socks5://host:1080). Single-shot mode: -profile chrome_146 -proxy ... or -ja3 "771,..." -proxy ....

Important: keep this module isolated

Do not add refraction-networking/utls to this module. Two uTLS forks in one module can bump shared deps and make tls-client's fork silently fall back to a plain TLS 1.2 handshake. The JA3-generator tools live in their own module for exactly this reason.