Web Search
The Responses API can answer questions grounded in live web content and return inline citations back to the source. You enable web access by adding a web_search tool to a request; the model decides when to search, and the answer comes back with url_citation annotations pointing at the pages it used.
Search is agentic: the model chooses whether and when to search, rather than the server always searching. A turn may search once, several times, follow up by reading a full page, or not search at all, and citations only appear when the model actually grounds its answer in retrieved results.
Two capabilities are exposed from a single web_search tool:
-
Search the web: runs a web search and returns citable results (title, URL, snippet).
-
Read a web page: fetches the full content of one public URL as markdown when a search snippet is not enough. This grounds the answer and the page itself becomes citable.
Web content is backed by LinkUp (the web search service). The LinkUp API key is server-owned: unlike file search, no per-request user authorization is forwarded. Search queries and fetched page content therefore leave the cluster; see Data Flows.
How It Works
-
The client adds one
web_searchtool totools[], optionally setting the searchdepthand domainfilters. -
During generation the model may search the web or fetch a page, as many times as it needs.
-
Each call runs server-side against LinkUp and returns numbered, citable sources to the model.
-
The model writes inline
[1],[2]markers where it uses a source. -
The response carries a
web_search_calloutput item (the search + its results) andurl_citationannotations on the answer text, each mapping a marker to its source page.
Searches that find nothing, or turns where the model chooses not to search, simply produce no citations, the request still succeeds.
Sending a Request
Add a single tool of type web_search to tools[]. Set stream: true for SSE.
curl -X POST "$BASE_URL/v1/responses" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3-32b-tool",
"input": "What are the latest developments in AI regulation?",
"tools": [
{
"type": "web_search",
"depth": "standard",
"filters": {
"allowed_domains": ["europa.eu", "whitehouse.gov"],
"blocked_domains": ["reddit.com"]
}
}
]
}'
Tool fields:
| Field | Type | Description |
|---|---|---|
|
|
Required. |
|
|
Optional, default |
|
object |
Optional. |
Notes:
-
When the model calls
web_search, it provides aquerystring argument; when it callsfetch_url, aurlstring argument. -
One tool entry enables both searching and page reading.
-
web_searchcan be combined withfile_searchin the same request, citation numbers[n]stay globally unique across web and document sources. -
Graceful degradation: if web search is unavailable, the request still answers, the
web_search_callitem is persisted withstatus: "failed"and the model answers from its own knowledge. No error is surfaced.
The Response
A grounded answer returns two kinds of output:
-
A
web_search_calloutput item, the search and its results (one per search the model ran). -
An assistant
messagewhoseoutput_textcarriesurl_citationannotations, one per[n]marker the model wrote.
web_search_call item
{
"type": "web_search_call",
"id": "ws_...",
"status": "completed",
"action": { "type": "search", "query": "latest AI regulation developments" },
"results": [
{
"title": "EU AI Act enters into force",
"url": "https://europa.eu/...",
"snippet": "matched result text",
"citation_index": 1
}
]
}
action records how the model invoked the tool. On failure, status is "failed" and results is null.
url_citation annotation
{
"type": "url_citation",
"start_index": 42,
"end_index": 45,
"title": "EU AI Act enters into force",
"url": "https://europa.eu/...",
"snippet": "the cited result text, for hover/preview"
}
The marker [n] in the answer maps to source number n. start_index/end_index are the marker’s character offsets in the text. Unlike file-search citations there is no sherlock block, url is a plain public web URL. Citation numbers stay stable and de-duplicated across multiple searches within one answer, the same URL keeps the same [n].
Streaming events
For a streamed web_search turn the notable events, in order, are:
-
response.output_item.added/response.web_search_call.in_progress/.searching/.completed/response.output_item.done: theweb_search_calllifecycle (repeated if the model searches more than once;.completedis omitted when the search failed). -
response.output_text.delta…, the answer text. -
response.output_text.annotation.added: one per[n]marker, carrying aurl_citation(emitted beforeresponse.output_text.done). -
response.completed, then[DONE].
Reading a web page is transparent: it grounds the answer and makes the page citable, but emits no output item of its own.
Multi-Turn
The web_search tool must be sent on each turn where web access should be available. Citations are computed per turn: a follow-up that doesn’t search produces no citations. Already-cited URLs keep their [n] within a single answer, and web_search_call items from earlier turns are not re-sent to the model.
On reload there is no need to replay the stream, the web_search_call results and the url_citation annotations are persisted on the stored response and returned by the conversation/response retrieval endpoints.
Configuration
Web search requires explicit deployment opt-in, coherent LinkUp configuration, and the agentic loop (which executes the hosted tools).
| Variable | Default | Description |
|---|---|---|
|
|
Must be |
|
- |
LinkUp API key required when hosted web search is enabled. |
|
LinkUp API base URL. |
|
|
|
Maximum search hits returned per search and exposed as citable sources. |
|
|
Whether page reads render JavaScript before extracting content. |
|
|
Safety cap on fetched page text fed to the model. |
|
|
Per-call timeout for LinkUp requests (seconds). |
|
|
Must be |
Web search is active only when WEB_SEARCH_ENABLED=true, the API key and a non-blank base URL are configured, and the agentic loop is on. Otherwise a web_search tool on a request is ignored and the turn proceeds as a normal completion.