Piggy vs Other Scraping Tools β
How Nothing Browser Piggy compares to other browser automation and scraping libraries.
Quick Comparison β
| Feature | Piggy | Puppeteer | Playwright | Selenium | curl_cffi |
|---|---|---|---|---|---|
| Communication | Socket (Unix/Windows pipes) | CDP | CDP | WebDriver | HTTP |
| Language | TypeScript/Bun | JavaScript/Node.js | JS/TS/Python/Java/.NET | Multiple | Python |
| TLS Fingerprint | β Real BoringSSL | β Real BoringSSL | β Real BoringSSL | β Real BoringSSL | β οΈ Patched |
| navigator.webdriver | β Undefined | β True (leaks) | β True (leaks) | β True (leaks) | N/A |
| Built-in fingerprint spoofing | β Yes | β Plugin needed | β Plugin needed | β Plugin needed | β Yes |
| Network capture | β Built-in | β Manual | β Manual | β Manual | β No |
| WebSocket capture | β Built-in | β Manual | β Manual | β Manual | β No |
| One-click export | β Python/cURL | β No | β No | β No | β No |
| Built-in API server | β Yes | β No | β No | β No | β No |
| Session persistence | β Built-in | β Manual | β Manual | β Manual | β No |
| Human mode | β Built-in | β Manual | β Manual | β Manual | β No |
| Cloudflare bypass | β Passes | β οΈ Often blocked | β οΈ Often blocked | β οΈ Often blocked | β Passes |
| Lines of code to scrape | ~20 | 80-200 | 80-200 | 100-250 | ~50 |
How Piggy Communicates β
Unlike Puppeteer/Playwright (which use Chrome DevTools Protocol over WebSocket), Piggy uses direct socket communication:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Code β
β (Bun/TypeScript) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β Socket Connection
β (Unix domain socket / Windows pipe)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Nothing Browser Binary β
β (Qt6 WebEngine + C++) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββSocket Paths β
| Platform | Socket Path |
|---|---|
| Linux/macOS | /tmp/piggy (Unix domain socket) |
| Windows | \\.\pipe\piggy (Named pipe) |
Why Socket Instead of CDP? β
| Aspect | Socket (Piggy) | CDP (Puppeteer/Playwright) |
|---|---|---|
| Protocol | Custom, lightweight | Chrome DevTools Protocol |
| Overhead | Minimal | Higher |
| Latency | Lower | Higher |
| Custom commands | β Easy to add | β Limited by CDP spec |
| Binary size | Smaller | Larger |
| Control | Full | Limited to CDP |
Detailed Comparison β
TLS Fingerprint β
| Tool | TLS Library | JA3 Status | Cloudflare |
|---|---|---|---|
| Piggy | BoringSSL (real Chrome) | β Chrome-identical | β Passes |
| Puppeteer | BoringSSL (real Chrome) | β Chrome-identical | β οΈ JS leaks |
| Playwright | BoringSSL (real Chrome) | β Chrome-identical | β οΈ JS leaks |
| Selenium | BoringSSL (real Chrome) | β Chrome-identical | β οΈ webdriver flag |
| curl_cffi | BoringSSL (patched) | β Chrome-identical | β Passes |
| Python requests | OpenSSL | β Python JA3 | β Blocked |
JavaScript Detection β
| Tool | navigator.webdriver | chrome.runtime | DocumentCreation injection |
|---|---|---|---|
| Piggy | β undefined | β Present | β Yes |
| Puppeteer | β true | β Absent | β οΈ Partial (CDP) |
| Playwright | β true | β Absent | β οΈ Partial (CDP) |
| Selenium | β true | β Absent | β No |
| curl_cffi | N/A | N/A | N/A |
Communication Overhead β
ts
// Piggy - direct socket command
socket.write(JSON.stringify({ cmd: "navigate", payload: { url } }) + "\n");
// Puppeteer - CDP over WebSocket
ws.send(JSON.stringify({
id: 123,
method: "Page.navigate",
params: { url }
}));When to Use What β
| Use Case | Recommended Tool |
|---|---|
| Quick scraping with anti-detection | Piggy |
| Testing web apps | Playwright |
| Simple Chrome automation | Puppeteer |
| Cross-browser testing | Playwright |
| Python-only stack | curl_cffi |
| API reverse engineering | Piggy |
| Production scraping pipeline | Piggy |
| Browser extension testing | Puppeteer |
Version Compatibility β
Important: Library vs Binary Versions β
Piggy consists of two parts:
- Node/Bun library (
nothing-browsernpm package) - Nothing Browser binary (downloaded separately)
These versions are independent and can be mixed.
How It Works β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Project β
βββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ€
β Node/Bun Library β Nothing Browser Binary β
β (npm package) β (downloaded separately) β
β β β
β β’ API surface β β’ Browser engine β
β β’ exposeFunction logic β β’ TLS fingerprint β
β β’ TypeScript types β β’ Network capture β
β β’ Socket client β β’ Socket server β
βββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββ
β
β Socket Connection
βΌ
βββββββββββββββββββββββ
β /tmp/piggy β
β (Unix socket) β
βββββββββββββββββββββββFeature Rollout Order β
When a new feature is added:
- First added to binary (C++ layer with socket handler)
- Then added to library (TypeScript layer with socket client)
- Then documented
Timeline:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΊ
Binary v0.2.0 Library v0.6.0
(adds new feature) (exposes new feature)
(new socket command) (new method in library)
β β
βΌ βΌ
Binary ready Library ready
but not exposed with new APIIf You Update Library Without Binary β
ts
// You updated library to v0.6.0 but binary is still v0.1.0
await piggy.launch(); // OK - works
// New function that requires binary v0.2.0+
await piggy.site.newFunction();
// β TypeError: piggy.site.newFunction is not a functionError message:
TypeError: piggy.site.newFunction is not a function
The library is trying to send a socket command that the binary doesn't understand.
Either update the binary or don't use this new function.This happens because:
- Library sends a new socket command to binary
- Old binary doesn't recognize that command
- Library throws "not a function" error
Solutions β
| Solution | When to Use |
|---|---|
| Update binary | You need the new feature |
| Don't use new function | You don't need it |
| Downgrade library | You want to stay stable |
Compatible Version Examples β
bash
# These combinations all work fine:
Library v0.5.0 + Binary v0.1.0 β
(old binary, old socket commands)
Library v0.5.0 + Binary v0.2.0 β
(new binary, same socket commands)
Library v0.6.0 + Binary v0.1.0 β οΈ (new socket commands unavailable)
Library v0.6.0 + Binary v0.2.0 β
(new socket commands available)Backward Compatibility Promise β
- β We never delete socket commands without announcement
- β Old library continues to work with newer binaries
- β You can stick with an old library (e.g., v0.0.7) and a newer binary (e.g., v0.1.10)
- β Even 15 versions ahead, old library + new binary works
- β Old socket commands remain supported in new binaries
Upgrade Policy β
ts
// Safe to upgrade library if:
// 1. You don't use new functions
// 2. You also upgrade binary
// Also safe to stay on old library:
// - It will continue working
// - We don't break existing APIs
// - All old socket commands still workMulti-Language Support (Coming Soon) β
Piggy's socket-based communication means any language that can connect to Unix domain sockets or Windows named pipes can use it:
| Language | Status | Target Release |
|---|---|---|
| TypeScript/Bun | β Available now | v0.1.0 |
| Python | π¨ In development | v0.7.0 |
| Go | π Planned | v0.8.0 |
| Java | π Planned | v0.9.0 |
| Rust | π Planned | v1.0.0 |
| C#/.NET | π Planned | v1.0.0 |
| Ruby | π Planned | v1.0.0 |
| C++ | π Planned | v1.0.0 |
Python Example (Coming Soon) β
python
# Future Python version - connects to /tmp/piggy socket
from nothing_browser import piggy
await piggy.launch()
await piggy.register("site", "https://example.com")
await piggy.site.navigate()
data = await piggy.site.evaluate("() => ({ title: document.title })")
print(data)Go Example (Coming Soon) β
go
// Future Go version - connects to /tmp/piggy socket
package main
import "github.com/nothing-browser/piggy"
func main() {
piggy.Launch()
site := piggy.Register("site", "https://example.com")
site.Navigate()
title := site.Title()
fmt.Println(title)
}Why Socket Communication Matters for Multi-Language β
All language versions communicate via socket (Unix domain socket / Windows named pipe), which means:
- β Same features across all languages
- β Same performance across all languages
- β Same anti-detection across all languages
- β Binary is language-agnostic
- β Any language with socket support can implement a client
- β No HTTP/WebSocket overhead like CDP-based tools
Socket Protocol β
json
// Command format (library β binary)
{
"id": "123",
"cmd": "navigate",
"payload": { "url": "https://example.com", "tabId": "default" }
}
// Response format (binary β library)
{
"id": "123",
"ok": true,
"data": { "title": "Example Domain" }
}
// Event format (binary β library, unsolicited)
{
"type": "event",
"event": "navigate",
"tabId": "default",
"url": "https://example.com"
}Summary β
| Aspect | Piggy |
|---|---|
| Communication | Socket (Unix/Windows pipes) - faster than CDP |
| Easiest to use | β Yes |
| Best anti-detection | β Yes |
| Fastest setup | β Yes |
| Most features built-in | β Yes |
| Multi-language | π¨ Coming soon (via socket protocol) |
| Production ready | β Yes |
Nothing Ecosystem Β· Ernest Tech House Β· Kenya Β· 2026