Screenshot URLs from your terminal

Fast, minimal, built in Rust. Local or remote browsers. Tab pooling. Parallel execution.

cargo install hxn
hxn
$ hxn -u https://example.com -b $(which brave)

info: Bump dir hxnshots, created successfully
+----------+--------------------+
| URL      | https://example.com |
| Title    | Example Domain      |
| Status   | 200 OK              |
| Saved as | httpsexamplecom.png |
| Time     | 360ms               |
+----------+--------------------+
info: Screenshots taken and saved in directory hxnshots
01

Remote browsers

Connect to an already-running Chrome instance on another machine via CDP. No need to launch a browser locally.

02

Tab pooling

Reuse browser tabs across URLs instead of creating and destroying them. Pages reset between screenshots automatically.

03

Parallel execution

Run multiple tabs in parallel with configurable concurrency. Default 4, scale up to whatever your machine handles.

04

Flexible input

Single URL, file of URLs, or pipe from stdin. Works with any tool that outputs URLs.

05

Multiple formats

PNG, JPEG, WebP. Full page screenshots. NDJSON metadata output for automation and AI agents.

06

Runs everywhere

Linux, macOS, Windows, Termux. Single binary, no runtime dependencies beyond a Chromium browser.

Usage

Single URL
$ hxn -b $(which brave) -u https://example.com
From a file
$ hxn -b $(which brave) -f urls.txt
From stdin
$ cat urls.txt | hxn -b $(which brave) --stdin
Start headless Chrome on the remote machine
$ chromium --headless --remote-debugging-port=9222 --no-sandbox
# expose the port if Chrome only binds to localhost
$ socat TCP-LISTEN:9223,fork,reuseaddr,bind=0.0.0.0 TCP:127.0.0.1:9222 &
Connect via auto-discovery
$ hxn --remote-host 192.168.1.42:9223 -f urls.txt
Connect via WebSocket URL
$ hxn --remote-url ws://192.168.1.42:9223/devtools/browser/<uuid> -u https://example.com
Parallel tabs
$ hxn -b $(which brave) -f urls.txt --tabs 8
Custom pool size
$ hxn -b $(which brave) -f urls.txt --pool-size 16
With ports
$ hxn -b $(which brave) -f urls.txt --ports 8080,8081
NDJSON output
$ hxn -b $(which brave) -f urls.txt --json
Silent mode
$ hxn -b $(which brave) -f urls.txt --silent
Screenshot format
$ hxn -b $(which brave) -u https://example.com --screenshot-type jpeg
Full page
$ hxn -b $(which brave) -u https://example.com --fullpage
Proxy
$ hxn -b $(which brave) -u https://example.com --proxy socks5://127.0.0.1:9050
Random user agent
$ hxn -b $(which brave) -f urls.txt --user-agent "random"
Run JavaScript before screenshot
$ hxn -b $(which brave) -u https://example.com \
    --javascript "document.querySelector('.banner')?.remove()"
Custom viewport + timeout
$ hxn -b $(which brave) -f urls.txt -x 1920 -y 1080 --timeout 200 --delay 5

Benchmarks

vs gowitness, measured with hyperfine on GitHub Actions

Benchmark hxn gowitness
Single URL 360ms 3.99s 11x faster
5 URLs, 4 tabs 1.81s 26.29s 14x faster
5 URLs, 8 tabs 1.70s 14.67s 8x faster

Install

Cargo

cargo install hxn

Binstall

cargo binstall hxn

Nix

nix profile install nixpkgs#haylxon