Your browser builds the circuit
tor-js runs the Tor client itself — the network only ever carries opaque, layered-encrypted bytes.
Bootstrap
The WASM client pulls a compressed directory snapshot and verifies the consensus — no multi-round-trip directory dance.
Build circuits
It negotiates keys and builds onion-encrypted circuits through guard, middle, and exit relays, entirely on your device.
fetch() through Tor
Call client.fetch(url) and get a standard Response back — TLS to the destination runs end-to-end inside the circuit.
Three lines to a Tor request
import { TorClient } from 'tor-js'; const client = new TorClient({ gateway: '198.51.100.7:12298:uEiAxk…9Qw', // ip:port:certhash }); const res = await client.fetch('https://check.torproject.org/api/ip'); console.log(await res.json()); // { IsTor: true, IP: "..." }
Real onion routing
Full Arti (the Tor Project's Rust client) compiled to WebAssembly — not a proxy or an approximation.
Crypto stays local
All circuit and TLS crypto runs in your process. The gateway relays encrypted bytes and learns nothing.
Fast bootstrap
A single zstd-compressed directory snapshot, decompressed client-side. Seconds, not round trips.
Browser & Node
The same API in both. Node opens TCP directly; browsers connect through a gateway.
Tiny surface
A ~24 kB wrapper plus the WASM. new TorClient(), fetch(), close().
Persistent state
Consensus and microdescriptors cache to IndexedDB or disk, so reconnects bootstrap faster.
The gateway is a blind relay
Browsers can't open raw TCP, so a small gateway relays bytes to Tor relays over KPS (WebRTC/QUIC). It never sees your traffic or destination.
Builds circuits, holds all keys, does all crypto
Forwards opaque encrypted bytes — CONNECT tunnels over KPS
Guard → middle → exit → the open internet
Run your own gateway from the tor-js-gateway crate — a single binary, one UDP port.