WebGraph

Configuration

Every WEBGRAPH_* environment variable with its default, meaning and when to set it; the one frontend variable; and GET /api/config.

Every setting the engine has is a named constant in packages/engine/src/webgraph/config.py, with a comment saying what it does. Most are changed by editing that file or by passing a config object to a call. The "Deployment" section at the bottom of the file is the exception: each of those DEPLOY_* constants has an environment variable named beside it, read once at process start by Settings.from_env() in webgraph/settings.py. Two more variables are read by fetch/guard.py. Nothing has to be set for local development.

The variables

variabledefaultmeaningwhen to set it
WEBGRAPH_MAX_PAGES0 (none); 50 in the imageHard ceiling on pages per crawl, whatever a client asks. A request of 0 means "until the frontier is exhausted", so on a capped host it clamps down to the cap (_effective_max_pages).Any shared or public host. Unbounded is the engine's default and a six-hour run is one URL away.
WEBGRAPH_MAX_CONCURRENCY0 (none); 4 in the imageCeiling on parallel fetches within one crawl. The API's request model allows up to 12 and defaults to 6.Any host with fewer cores than the request allows.
WEBGRAPH_MAX_CONCURRENT_CRAWLS3; 2 in the imageWhole-site crawls the API runs at once; the rest wait for a slot and are told so (Waiting for a crawl slot).Size to CPU and memory: each crawl holds up to concurrency browsers.
WEBGRAPH_MAX_CONCURRENT_RENDERS2Browser pages open at once for single-page requests (/api/text with render: true).Rarely; the crawl route is bounded separately.
WEBGRAPH_MAX_BROWSERS6; 4 in the imageLive Chromium instances process-wide, ~150 MB resident each. A thread that cannot get a slot launches a private short-lived browser rather than blocking.Always, to the memory budget: six suits 16 GB, four suits a 4 GiB container.
WEBGRAPH_CHROMIUM_ARGSempty; --no-sandbox --disable-dev-shm-usage --disable-gpu in the imageExtra Chromium flags, shell-split.Containers. Chromium's sandbox needs kernel capabilities a container is not granted, and the default 64 MB /dev/shm crashes the renderer on a heavy page. On a developer machine leave it empty.
WEBGRAPH_ALLOWED_ORIGINSthe dev frontend (http://localhost:3000, http://127.0.0.1:3000)Browser origins the API answers, comma-separated.Always, in production, to the frontend's origin. Never *: this service fetches arbitrary URLs on the caller's behalf, and an open CORS policy hands every page on the internet a proxy inside your network.
WEBGRAPH_PUBLIC_BASE_URLemptyThe address a visitor reaches this deployment at (https://api.example.org), for the responses that have to name their own address -- a feed's self-link, so far. Empty means "take it from the request". Any trailing slash is dropped.Behind any reverse proxy, and always in the one-origin deployment: the web app proxies /api/* over Docker's internal network, so the request the API sees says api:8080 and a feed published from it tells subscribers to poll a hostname that exists only inside the compose network.
WEBGRAPH_BLOCK_PRIVATE_HOSTSon in the API (configure_from_env(default=True)); off in the library and CLIRefuse loopback, private, link-local and network-internal addresses, on every redirect hop.Set =1 in the image so the posture is visible in docker inspect.
WEBGRAPH_ALLOW_PRIVATE_HOSTSunsetOpt out of the guard. Wins when both are set.Pointing a local API at a site on localhost. Never on a public host.
WEBGRAPH_TRACE_DIRthe system temp directoryWhere the API writes one trace file per run, under webgraph-runs/.When traces should survive a restart or be collected. Unset, "a server that fills a disk with them by default has replaced one problem with another."
WEBGRAPH_TRACEunsetA single trace file for library and CLI runs.Diagnosing a CLI run.
WEBGRAPH_GRAPH_DIR~/.cache/webgraph/graphs ($XDG_CACHE_HOME honoured); /tmp/webgraph-graphs in the imageWhere finished site graphs are written so a restart does not discard minutes of crawling; pruned to the newest 32.A persistent volume, if the graph must outlive the instance. On a scale-to-zero host it is a cache, not storage.
WEBGRAPH_CONTACTemptyName contact@example.com, sent as <contact> webgraph/0.1 only to a site that refuses undeclared automated clients and says so (sec.gov). Empty: such a site is refused and the refusal names this setting.If you want sec.gov-style sites read, and are willing to be named. Never a disguise; the client is still called webgraph.
WEBGRAPH_KGunset (off)Serve WebGraph: the /api/graph/* routes and webgraph kg. Off, every one of them answers 404 naming this variable.Only when you want the knowledge-graph preview; it is behind a flag until its benchmark passes.
WEBGRAPH_KG_DIR~/.cache/webgraph/kgWhere per-site knowledge graphs (SQLite files, with the model cache) are kept.A persistent volume: the cache is what makes a rebuild free.
WEBGRAPH_LLM_*unsetThe default model provider for WebGraph -- PROVIDER, BASE_URL, MODEL, ANSWER_MODEL, API_KEY / API_KEY_ENV, JSON_MODE, CONCURRENCY, PRICE_IN / PRICE_OUT; see providers. A request may override any of them.A self-hosted deployment that owns a key or runs Ollama. Never set a key on a shared host that also accepts requests from strangers.
PORT8080 in the imageThe port uvicorn binds.Cloud Run and most container hosts inject it.

Zero means no cap

For every MAX_* cap, 0 means none. The image sets them because "a shared host cannot let one caller crawl a site until its frontier is exhausted" (Dockerfile).

The frontend's one variable

NEXT_PUBLIC_API_BASE — the API's URL, inlined into the bundle at build time, not read at runtime. A build without it keeps the http://127.0.0.1:8000 default and then asks each visitor's own machine for the API; changing it later needs a redeploy. apps/web/lib/api.ts detects this specific mistake and says so in its error, because the symptom is otherwise indistinguishable from a backend that is down.

What a request may override

Per-run knobs are not environment variables. /api/site/stream accepts max_pages, concurrency, complete, and three option objects — crawl (max_depth, strict_domain, common_crawl, seed_from_common_crawl, within_path, include_paths, exclude_paths, delay_seconds, verify_inventory, follow_links, discovery_limit, sitemap_limit, respect_robots, remove_chrome, main_content), fetch and renderOptions — each applied on top of config.py's defaults and then clamped by the host's caps. The run header frame of every stream reports the values actually applied.

GET /api/config

Returns three things, so the settings page and the file never disagree:

  • settings — every constant in config.py with its value, its comment (parsed from the source, not declared twice) and its section.
  • overridable — which of them a request may change, by request field: crawl, fetch, renderOptions.
  • caps — this host's max_pages, max_concurrency, max_concurrent_renders, max_concurrent_crawls from the environment; 0 means none.

GET /api/health is the shorter check: render_available, max_concurrent_renders, private_hosts_blocked and max_pages. The last two are there because a deployment with the guard off and no cap "looks perfectly healthy".

One origin for web and API

Set NEXT_PUBLIC_API_BASE=/ when building the web app and WEBGRAPH_API_PROXY=http://127.0.0.1:8000 for both the build and next start. The page then calls /api/... on its own origin and the web server forwards those requests to the API. One host serves everything, so a single tunnel or domain is enough and CORS never applies; the API's WEBGRAPH_ALLOWED_ORIGINS is only needed when browsers call it directly.

NEXT_PUBLIC_API_BASE=/ WEBGRAPH_API_PROXY=http://127.0.0.1:8000 pnpm web:build
WEBGRAPH_API_PROXY=http://127.0.0.1:8000 pnpm --filter @webgraph/web start

The public origin

Set NEXT_PUBLIC_SITE_URL (build time) to the origin the site is served from, e.g. https://webgraph.example. It becomes metadataBase: the absolute URL in og:image and twitter:image that link previews (Discord, Slack, X, iMessage) fetch. Unset, it is http://localhost:3000 and previews show no picture.