# Web Search

> Let the assistant search the web through your own SearXNG instance — off by default, each search shown to you before it is sent, results treated as untrusted.

Source: https://docs.docgraph.app/ai/web-search/

Web search lets the [chat assistant](https://docs.docgraph.app/ai/chat/) look things up on the web when your notes don't have the answer — current events, library versions, anything outside the vault. It is the **only way the assistant can look things up online**, and it is designed so you stay in control of exactly when that happens:

- **Off by default.** Until you enable it, the assistant cannot search the web at all.
- **You see every query first.** Each search shows you the exact query text in a confirmation card before anything leaves the machine. Nothing is sent until you choose **Send search**. If you would rather not be asked each time, **Allow in this chat** stops the prompts for the rest of that one conversation — it never carries over to another chat and ends when DocGraph quits.
- **Results are untrusted input.** Whatever comes back is fenced and marked as web content the assistant may summarize or cite, but must never follow as instructions.
- **No DocGraph-hosted service, no API key.** DocGraph never routes your queries through any server of ours — you point it at your own search backend.

## Requirements

Web search needs one thing: a [SearXNG](https://docs.searxng.org/) instance it can query.

SearXNG is a free, open-source metasearch engine that queries the big search engines for you and returns the results as JSON. DocGraph talks only to *your* SearXNG — never to Google, Bing, or anyone else directly. Running it on your own machine means your search queries never leave it in a form tied to you.

The recommended setup — a local instance — runs SearXNG in **[Docker](https://www.docker.com/)**, so for that path Docker is a requirement too. If you'd rather not install Docker, the alternatives are a [non-Docker SearXNG installation](https://docs.searxng.org/admin/installation.html) or pointing DocGraph at an instance you already run elsewhere (a home server, your LAN); either way, DocGraph itself only needs the address. A public server from [searx.space](https://searx.space) also works, but every search then passes through a stranger's machine, and public servers are often throttled or refuse automated searches. A loopback (`127.0.0.1`) instance is the recommended setup: the query never leaves your machine, and the privacy badge stays green.

## Set it up for me

Open **Settings → AI → Web search**. If no server is set and a SearXNG is already answering on this computer (on port `8888` or `8080`), the status reads **SearXNG is already running on this machine** with its address: click **Use it** to fill in the **Server address** and turn web search on. The check only looks at this computer. If a server you already set stops answering and another local SearXNG is found, the status offers **Use that one**.

Otherwise, click **Don't have a server? Set one up on this machine**. The panel checks Docker first and shows what is missing:

- **Docker isn't installed** — **Download Docker Desktop** (or **Or OrbStack, a lighter option for Mac**), install and open it, wait until it says the engine is running, then **Check again**.
- **Docker is installed but not running** — **Open Docker Desktop**. The page notices when the engine has started.
- **Docker is running** — click **Set it up for me**.

**Set it up for me** runs a fixed Docker command you asked for with that click, and shows four steps with a running clock: **Download SearXNG** (first time only, about 200 MB), **Start it**, **Wait for it to answer**, and **Run a test search**. When the test passes, DocGraph fills in the **Server address** as `http://127.0.0.1:8888` and turns on **Enable web search**.

What it creates, so you know what is on your machine:

- A container named **`docgraph-searxng`**, from the image `searxng/searxng`, restarted automatically after a reboot (`--restart unless-stopped`).
- Published on **`127.0.0.1:8888` only** — no other computer can reach it.
- A config file at **`~/.docgraph/searxng/settings.yml`**. DocGraph writes it once and never overwrites it, so your edits are kept.

The config turns on the JSON output DocGraph reads, and it **spreads searches over ten engines**: Bing, Yahoo, Startpage, Mojeek, Presearch, DuckDuckGo, Brave, Google, Qwant and Wikipedia. That is deliberate: search engines answer an unattended server with CAPTCHAs, rate limits and suspensions, and *which* ones do changes from week to week. With a single engine, one refusal means a server that looks healthy and returns zero results; with several, the others keep answering. Engines that refuse are skipped, so they cost no time.

### Set it up yourself instead

Under **Set it up yourself instead**:

1. Make sure Docker is running.
2. Click **Copy terminal command** and paste it into Terminal. It writes the same `settings.yml` and starts the same `docgraph-searxng` container on this machine only.
3. Paste `http://127.0.0.1:8888` into **Server address** and click **Test**.

Use that command rather than a plain `docker run searxng/searxng`: the stock image keeps the default engines, and its JSON output is off, so searches fail or return nothing.

If you run SearXNG some other way, the two things it must have are the JSON format and engines that answer:

```yaml
search:
  formats:
    - html
    - json
```

For engines, click **Copy working settings** (it appears when a test finds your server's engines refusing, returning nothing, or down to one) and paste the result over your server's `settings.yml`, then restart it. For the server DocGraph set up, restart with `docker restart docgraph-searxng`.

## Configuration

Everything lives in **Settings → AI → Web search**. A status line at the top answers "does web search work right now, and if not, what do I do?" and always reflects the last **Test**.

| Setting | What it does | Default |
| --- | --- | --- |
| **Enable web search** | Turns the `web_search` tool on for the assistant. | Off |
| **Server address** | Your SearXNG's base address, e.g. `http://127.0.0.1:8888`. Empty means web search stays off even when enabled. A pasted results-page link is tidied to the server's address, and the value is saved, when you leave the field. | Empty |
| **Test** | Sends one real search through the server and reports how many results came back, which engines answered, which refused, and how long it took. It warns when only one engine answered, since searches then depend on it alone. The status line names the problem when it fails. | — |
| **Local server only** | Hard guard: refuse any server that isn't on this machine, so a search can never leave it regardless of what the address says. | Off |
| **Language** | The language results are searched in: server default, any language, or one of 18 named languages. | Server default |
| **SafeSearch** | Filter explicit results: server default, **Off**, **Moderate** or **Strict**. | Server default |
| **Published within** | Only pages from the past day, week, month or year. **Any time** turns it off. If the test finds your server's engines can't filter by date, the status says so and suggests **Any time**; in chat, such a search is retried without the date filter. | Any time |
| **Results per search** | How many results the assistant reads: 3, 5, 8 or 10. More gives it more to work with and makes answers slower. | 5 |

**Recent searches** lists the searches the assistant ran, with result counts. They are kept in memory until DocGraph quits, never saved to disk; **Clear** empties the list, and **See every request in Network activity** opens the [Activity log](https://docs.docgraph.app/privacy/activity/). The log lists only searches sent to a server off this computer; a search to a SearXNG server on this computer isn't recorded there.

## How it behaves in chat

With web search enabled, the assistant gains a `web_search` tool. When it decides a question needs the web, you see a confirmation card with the verbatim query:

| Button | Effect |
| --- | --- |
| **Send search** | Runs this one search. |
| **Not now** | Declines; the assistant carries on without it. |
| **Allow in this chat** | Runs this search and stops asking for web searches in this conversation. A banner reads *Web searches in this chat are sent without asking*, with **Ask again** to undo it. Other chats still ask, and it ends when DocGraph quits. **Approve all this session** for other changes never covers web searches. |

Results are capped at **Results per search** (five unless you changed it), each reduced to a title, URL, and short snippet. If your server's engines ignore **Published within**, DocGraph retries the search without the date filter rather than coming back empty.

Start a message with **Search the web:** (or *search the web for*, *search online*, *web search*, *google …*) to make sure it searches. Such a message is never answered as a list of matching notes. If the model answers without searching, DocGraph runs the search for the rest of your message itself, once per message. The usual card still asks first, and when web search is off you get the offer to turn it on.

Each web result is cited in the answer as a link named by its site, such as `nodejs.org`. Hover it for the full address; click it to open it in your browser. When none of your notes matched, the line under the answer says the answer came from web search.

When the assistant answers a question about DocGraph itself from the built-in user guide, it doesn't offer web search for that question.

When web search is **disabled**, the assistant doesn't silently give up on questions it can't answer from your notes — it may *offer* to search, showing the query it would run. The card reads **Enable & search** and **Not now**; approving it is the only way the setting flips on, and the assistant (or anything it read) can never enable it by itself. If no server address is configured yet, the offer instead points you to Settings.

## What happens to the privacy badge

DocGraph's title bar always shows the [privacy badge](https://docs.docgraph.app/privacy/overview/): **100% local** while nothing is leaving your machine. Enabling web search doesn't change it by itself — but the moment a search actually goes to an **off-machine** server, the badge flips to an amber **External** for as long as the request is in flight, and its tooltip names exactly what is connecting and where. When the response arrives, it returns to green.

*[Screenshot: The privacy badge in its two states: the green "100% local" pill, and the amber "External" pill shown while a web search is in flight.]*

This is the deal you're making when you activate web search: your approved query — which the assistant writes, and which may quote your notes — travels to the search server you configured. The badge makes that moment visible instead of silent, and the network log keeps a record of it whenever the server is off this computer.

If your SearXNG runs on `127.0.0.1`, the badge **stays green** even during a search — the query never leaves the machine, so there is no egress to report. That's the recommended setup, and turning on **Local server only** makes it a hard guarantee.

## Privacy guarantees

- **The query is egress, and treated like it.** A search against a non-local server is inspected by the [egress check](https://docs.docgraph.app/privacy/overview/) ("When content is about to leave this machine") before it's sent — the query is written by the model and can quote your notes. A loopback server skips the check, because nothing is leaving. A server that isn't on this machine must use `https`.
- **The network ledger records every search sent off this computer**, including the full query text. If a query quoted your notes, that quote is in the log — something to know if you share log files. Searches to a SearXNG server on this computer (loopback) are not recorded, because nothing leaves the machine.
- **A loopback server keeps the privacy badge green**; an external one flags the request for its duration.
- **Results can't impersonate you or the app.** Web content is wrapped in a tamper-proof fence with structural markers neutralized, so a malicious page can't inject instructions that read as coming from you.
- **Not exposed over MCP.** A [connected external agent](https://docs.docgraph.app/ai/mcp/) never gets this tool — it has its own web access and its own policies.

## Troubleshooting

Run **Test** first: its status line names the problem and offers the fix.

- **Nothing is answering at …** — SearXNG isn't running. First make sure Docker Desktop (or OrbStack) itself is running; then `docker ps` should list `docgraph-searxng`, and `docker start docgraph-searxng` brings it back if not. (The restart policy makes this automatic after reboots.)
- **Your server has its JSON output turned off** — add `- json` under `formats:` in the server's `settings.yml` and restart it. This is the cause of a `403`.
- **Web search works, but only *one engine* answered** — the others are refusing your server. Searches still work, but will find nothing if that engine refuses too. Click **Copy working settings**, paste them over `settings.yml`, and restart the server.
- **Your server answered, but its search engines refused** (or **answered with no results**) — the engines are being blocked as automated traffic. Click **Copy working settings**, paste them over `settings.yml`, and restart the server.
- **That address isn't a SearXNG server** — use the server's base address, like `http://127.0.0.1:8888`, not a results page or another app's port.
- **Your server took too long to answer** — it may still be starting. Wait a moment and test again. If it keeps stalling, check that the container is healthy.
- **This server isn't on this machine** — **Local server only** is on but the address points off-machine. Point it at `127.0.0.1`, or turn the guard off.
- **DocGraph refused this address** — a server that isn't on this machine must use `https`.
- **Your server is limiting requests** — public servers throttle heavily. Running your own avoids this.
- **Enabled but nothing happens** — check the **Server address** isn't empty; an empty address keeps the tool unregistered even with the toggle on. **Test** confirms the whole path.
