Full-stack web crawling engine with JavaScript rendering, Camoufox anti-detect browser, per-request proxy routing, and autonomous agent loops. Converts pages to clean markdown with a native Rust extraction engine. When standard crawling is blocked by Cloudflare, CAPTCHAs, or JavaScript walls, Ghost Protocol captures a screenshot and extracts content via vision AI (Claude, GPT-4o, or Ollama). Supports multi-provider LLM orchestration across OpenAI, Anthropic, and Ollama in a single session. Nodes coordinate over a gossip-based peer-to-peer mesh for distributed crawling.
Why Grub
We integrated features from every major crawler — then added what none of them have.
Self-Hosted Crawlers
Cloud / Managed Crawlers
Only Grub has Ghost Protocol — automatic vision-based fallback that screenshots blocked pages and extracts content via LLM when standard crawling fails. Prevention (Camoufox + proxy + stealth) handles 95% of blocks. Ghost Protocol handles the rest.
API Endpoints
Core Crawling
Agent (Mode B)
Job Management
Remote Cache
Session Management
Live Stream
Mesh
System
MCP Tools (grub-crawl.py)
The MCP bridge exposes all capabilities to any MCP-compatible host:
Three layers of anti-detection that stack together. Prevention stops blocks before they happen. Ghost Protocol handles them after.
Camoufox Engine
Pluggable anti-detect browser with C++-level fingerprint spoofing. No manual user-agent tricks — Camoufox generates realistic fingerprints per context at the browser level, including canvas, WebGL, fonts, and navigator properties.
Route crawl traffic through residential, datacenter, or custom proxy pools. Per-request override with env-based defaults. Full Playwright-compatible proxy config.
Opt-in playwright-stealth patches for Chromium (skipped for Camoufox where it's built-in). Blocks 20+ tracking/analytics domains (Google Analytics, DataDome, PerimeterX, etc.) to reduce fingerprint surface.
root@kitploit:~
STEALTH_ENABLED=true
BLOCK_TRACKING_DOMAINS=true
Ghost Protocol
When a crawl result signals an anti-bot block (Cloudflare challenge, CAPTCHA,
empty SPA shell), the agent can switch to cloak mode:
Take a full-page screenshot via Playwright
Send the image to a vision-capable LLM (Claude Sonnet or GPT-4o)
Extract content from the rendered pixels
Return extracted text with render_mode: "ghost" in the trace
This bypasses DOM-based anti-bot detection entirely.
Requires AGENT_GHOST_ENABLED=true. Auto-triggers on detected blocks when AGENT_GHOST_AUTO_TRIGGER=true.
Mesh
Agents talking to agents. Every Grub instance is both a worker and a coordinator. Local node offloads to cloud, cloud delegates to local. Tool calls cross the wire transparently.
Discovery — nodes join via seed peer list, then gossip (1-hop) to learn about others
Heartbeat — every 15s, nodes exchange load metrics. 3 missed = unhealthy. 2 min = removed
Routing — MeshDispatcher scores all nodes by load, locality, and affinity, then routes tool calls to the best node
1-hop max — Node A → B only, never A → B → C. Prevents routing loops
Local fallback — if remote execution fails, falls back to local Dispatcher
HMAC auth — all mesh traffic is signed with a shared secret (SHA-256, 60s TTL)
Run a 2-Node Mesh Locally
root@kitploit:~
# Docker Compose (recommended)
./deploy.sh mesh # Linux/Mac
./deploy.ps1 -Target mesh # Windows
# Verify
curl http://localhost:6792/mesh/peers # Node A sees Node B
curl http://localhost:6793/mesh/peers # Node B sees Node A
Connect Local to Cloud Run
root@kitploit:~
# Deploy to Cloud Run with mesh
./deploy.sh cloudrun latest --mesh-peer http://your-local-ip:6792 --mesh-secret mysecret
# Start local node
MESH_ENABLED=true MESH_SECRET=mysecret MESH_PEERS=https://your-cloud-run-url \
MESH_ADVERTISE_URL=http://your-local-ip:6792 \
uvicorn app.main:app --port 6792
# Add to .env
AGENT_ENABLED=true
OPENAI_API_KEY=sk-...
# or
ANTHROPIC_API_KEY=sk-ant-...
AGENT_PROVIDER=anthropic
Submit an Agent Task
root@kitploit:~
curl -X POST http://localhost:6792/api/agent/run \
-H "Content-Type: application/json" \
-d '{
"task": "Find the pricing page on example.com and extract plan details",
"max_steps": 10,
"allowed_domains": ["example.com"]
}'
Docker
root@kitploit:~
# Single node
./deploy.sh local # or ./deploy.ps1 -Target local
# 2-node mesh
./deploy.sh mesh # or ./deploy.ps1 -Target mesh
# Cloud Run
./deploy.sh cloudrun v1.0.0 # or ./deploy.ps1 -Target cloudrun -Tag v1.0.0
# Cloud Run + mesh (connect to local node)
./deploy.sh cloudrun v1.0.0 --mesh-peer http://your-ip:6792 --mesh-secret mykey
# Add to .env
AGENT_GHOST_ENABLED=true
curl -X POST http://localhost:6792/api/agent/ghost \
-H "Content-Type: application/json" \
-d '{"url": "https://blocked-site.com"}'
Live Browser Stream
root@kitploit:~
# Add to .env
BROWSER_STREAM_ENABLED=true
BROWSER_POOL_SIZE=2
# MJPEG (open in browser)
open "http://localhost:6792/stream/demo/mjpeg?url=https://example.com"
Do not summarize unless content_quality == "sufficient".
Prompt Injection Defense
quarantined=true means the extractor detected instruction-like text in extracted content that was not present in the page's visible rendered text (common in .sr-only/visually-hidden abuse).
When quarantined, content_quality is downgraded to minimal, policy_flags includes hidden_text_suspected and quarantined, and content/markdown outputs are blanked (fail-closed).
Combat arena — head-to-head benchmarks against Crawl4AI, Firecrawl (self-hosted), and Scrapy. All tests run on the same machine, same URLs, same conditions. Grub runs first as baseline, remaining adapters in randomized order with 10s delay between each to prevent rate-limiting bias.
Single-URL Speed (ms, lower is better)
Grub wins 4/5 single-URL speed races. Markdown conversion runs at 0-21ms via native Rust engine (grub_md).
Grub Phase Breakdown (server-side ms)
Navigation dominates; markdown conversion is sub-millisecond on most pages thanks to the Rust engine.