cd /news/ai-agents/show-hn-ember-lightweight-headless-b… · home topics ai-agents article
[ARTICLE · art-52456] src=github.com ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Show HN: Ember – Lightweight headless browser for AI agents (17MB idle)

Ember, a lightweight open-source headless browser for AI agents, launches at just 17 MB idle, significantly smaller than alternatives like Chromium-based tools. It requires no Docker or API keys, supporting scraping, search, crawling, and interactive browser control via a single pip install. The tool aims to make web automation accessible on low-resource devices like VPS, laptops, or Raspberry Pis.

read6 min views1 publishedJul 9, 2026
Show HN: Ember – Lightweight headless browser for AI agents (17MB idle)
Image: source
  ███████╗███╗   ███╗██████╗ ███████╗██████╗ 
  ██╔════╝████╗ ████║██╔══██╗██╔════╝██╔══██╗
  █████╗  ██╔████╔██║██████╔╝█████╗  ██████╔╝
  ██╔══╝  ██║╚██╔╝██║██╔══██╗██╔══╝  ██╔══██╗
  ███████╗██║ ╚═╝ ██║██████╔╝███████╗██║  ██║
  ╚══════╝╚═╝     ╚═╝╚═════╝ ╚══════╝╚═╝  ╚═╝

Open source, lightweight headless browser for AI agents.

pip install ember-browser

No Docker. No API key to start.

Most web tools for agents ship with Chromium (~281 MB) or require Docker just to get started. We needed something an agent could use on a VPS, a laptop, or a Raspberry Pi without thinking about it.

ember runs at ~17 MB idle. It decides whether a page needs a browser — you just pass it a URL.

ember Crawl4AI Firecrawl OSS Playwright
Setup pip install
pip install
Docker + Redis + Node pip + browser install
Package size ~54 MB ~200–350 MB Thin client only ~47 MB
Browser binary Lightpanda ~12 MB Chromium ~281 MB Chromium ~281 MB Chromium ~281 MB
Docker required No No Yes No
API key required No No No No
MCP server Yes No Yes Yes
Search built-in Yes No Yes No
Zero-infra self-host Yes Yes No Yes
pip install ember-browser
ember version                  # verify install

ember                          # start the interactive session
ember url https://example.com  # or run a one-shot command
ember serve                    # start the REST API

ember

with no arguments opens a persistent session. Commands and a save guide are shown on startup — no need to type help

first.

  ███████╗███╗   ███╗██████╗ ███████╗██████╗
  ██╔════╝████╗ ████║██╔══██╗██╔════╝██╔══██╗
  █████╗  ██╔████╔██║██████╔╝█████╗  ██████╔╝
  ██╔══╝  ██║╚██╔╝██║██╔══██╗██╔══╝  ██╔══██╗
  ███████╗██║ ╚═╝ ██║██████╔╝███████╗██║  ██║
  ╚══════╝╚═╝     ╚═╝╚═════╝ ╚══════╝╚═╝  ╚═╝

  v0.1.0  lightweight headless browser for AI agents

  url        <url>              scrape a page to markdown
  search     <query>            web search
  crawl      <url>              crawl a whole website
  map        <url>              discover all URLs on a site
  interact   <url>              control a browser with natural language
  extract    <url>              pull structured data with an LLM
  batch      <urls.txt>         scrape many URLs concurrently

  ─── saving results ───────────────────────────────────────────
  one result   url example.com -o page.md
  everything   output ./research/  then all results auto-save
  last result  save page.md        after any command

ember › url andausman.com
ember › save page.md

ember › output ./research/       # auto-save everything from here
ember/research › search "python asyncio" -n 10
ember/research › crawl docs.example.com
ember/research › output clear    # stop auto-saving
ember › quit

Every command works standalone too:

ember url https://example.com                         # scrape a page
ember search "AI agents python" -n 10                 # web search
ember crawl https://docs.example.com --max-pages 20   # crawl a site
ember map https://example.com                         # discover all URLs
ember interact https://amazon.com \
  --prompt "find a mechanical keyboard under $100"
ember extract https://example.com/pricing \
  --prompt "list all plans and prices as JSON"

All commands accept -o

to save that run:

ember url https://example.com -o page.md
ember search "python" -o results.json
ember crawl https://docs.example.com -o ./pages/   # one .md per page
ember map https://example.com -o urls.txt
ember extract https://example.com -o data.json

Set a default save directory so you never need -o

:

ember config --save-dir ./research/    # persists across sessions
ember config                           # show current settings
ember config --save-dir ""             # clear it

Or use an environment variable for the current shell:

EMBER_SAVE_DIR=./out ember url https://example.com

In a session, the three ways to save:

ember › url example.com -o page.md     # save just this run
ember › save page.md                   # save the last result
ember › output ./research/             # auto-save all results from now on
ember batch urls.txt                      # 5 concurrent by default
ember batch urls.txt -c 20 -o ./pages/   # 20 parallel, save to dir
python
from emb.scrape import scrape_url, scrape_markdown
from emb.search import search
from emb.crawl import crawl
from emb.map import map_url

result = scrape_url("https://example.com")
print(result.markdown)   # full page content as markdown
print(result.title)      # page title
print(result.success)    # True / False

md = scrape_markdown("https://example.com")

result = crawl("https://docs.example.com", max_pages=20, max_depth=3)
for page in result.pages:
    print(page.url, len(page.markdown))

result = map_url("https://example.com", max_links=100)
print(result.links)   # list[str]

results = search("python asyncio tutorial", limit=5)
for r in results:
    print(r.title, r.url)

from emb.interact import interact

result = interact("https://example.com", prompt="click the login button")
print(result.content)   # what the agent did / saw

from emb.agent import extract

data = extract("https://example.com/pricing", prompt="list all plans and prices")
print(data)   # dict
python
import asyncio
from emb.scrape import scrape_url_async

async def main():
    results = await asyncio.gather(
        scrape_url_async("https://example.com"),
        scrape_url_async("https://httpbin.org/get"),
    )
    for r in results:
        print(r.url, r.success)

asyncio.run(main())
ember serve               # http://127.0.0.1:51251
ember serve --port 8080   # custom port

EMBER_API_KEY=your-secret ember serve   # require auth
curl -X POST http://localhost:51251/scrape \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-secret" \
  -d '{"url": "https://example.com"}'

curl -X POST http://localhost:51251/search \
  -H "Content-Type: application/json" \
  -d '{"query": "AI agents", "limit": 5}'

curl -X POST http://localhost:51251/crawl \
  -H "Content-Type: application/json" \
  -d '{"url": "https://docs.example.com", "max_pages": 10}'

Endpoints: /scrape

/search

/crawl

/map

/interact

/extract

/agent

/health

Add to your Hermes config, OpenClaw config, Mercury config, or any MCP-compatible host:

{
  "mcpServers": {
    "ember": {
      "command": "ember",
      "args": ["mcp"]
    }
  }
}

Works with Hermes, OpenClaw, Mercury, and any MCP-compatible host.

Available tools: scrape

, search_web

, crawl_site

, map_site

, batch_scrape

, interact_page

, extract_data

.

Once connected, your agent can use ember tools directly in conversation:

User: Summarise the latest posts on Hacker News

Agent: [calls scrape("https://news.ycombinator.com")]
       → returns full page markdown with titles, scores, links

Agent: Here are today's top stories on Hacker News: ...
User: Find 5 articles about AI agents and scrape each one

Agent: [calls search_web("AI agents 2025", limit=5)]
       → returns list of {title, url, description}

Agent: [calls batch_scrape(["url1", "url2", ...])]
       → returns markdown for each page

Agent: Here's a summary across all 5 articles: ...

Not every page needs a browser. ember knows the difference.

Tier 1 — trafilatura handles ~89% of the web: blogs, news, documentation, docs sites, GitHub. Pure HTTP, no browser process, no memory overhead.

Tier 2 — Lightpanda handles JavaScript-heavy pages, SPAs, and interactive content. It's a real browser engine written in Zig, built for machines rather than humans — 20 MB total. ember downloads and caches it automatically on first use, and only falls back to it when tier 1 produces thin content.

Most requests never reach the browser.

State RAM
Idle ~17 MB
Scraping a static page ~20 MB
Running the browser ~140 MB

Firecrawl needs 4–8 GB in Docker. Crawl4AI imports at 171 MB before scraping anything. ember fits where your agent already runs.

Variable Default Description
EMBER_SAVE_DIR
(none)
Default directory for saved results. Overrides ember config --save-dir for the current shell.
EMBER_API_KEY
(none)
Enables API key auth on the REST server (X-API-Key header).
EMBER_PORT
51251
Default port for ember serve . Overridden by --port flag.
EMBER_INTERACT_PROVIDER
openai
LLM provider for interact (openai , anthropic , ollama , etc.).
EMBER_LLM_API_KEY
(none)
API key for LLM-powered extraction.
EMBER_LLM_BASE_URL
https://api.openai.com/v1
LLM API endpoint for extraction.
EMBER_LLM_MODEL
gpt-4o-mini
Model used by extract .
EMBER_LIGHTPANDA_PATH
(auto)
Path to a custom Lightpanda binary. Skips auto-download if set.

MIT — open source forever.

── more in #ai-agents 4 stories · sorted by recency
── more on @ember 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-ember-lightw…] indexed:0 read:6min 2026-07-09 ·