WebSearch
WebSearch is one of WebAgent's typed APIs. You give it a batch of queries; it fetches results across search engines, deduplicates, reranks, optionally attaches summaries, and returns a structured list of hits.
Unlike DeepResearch: DeepResearch produces a written report and runs for a few minutes to tens of minutes; WebSearch produces a structured result list, blocking synchronously by default and returning in seconds. Use this when you want "hits" rather than a "report".
When to use it
- You want a batch of programmatically processable search results (title / url / snippet), not a written report.
- You want to run multiple queries in a single call and get a unified list deduplicated across engines.
- You need a response in seconds and can accept synchronous blocking.
When you want a written research report, use DeepResearch. When you want the agent to decide its own retrieval paths and operate across pages, use DoAnything.
Run a search
HTTP endpoint:
POST /v1/projects/{pid}/web_search/runs
Authorization: Bearer wa_...Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
queries | string[] | Yes | A batch of queries |
engines | string[] | No | Restrict the search engines; omit = the default engine set |
max_results_per_query | int | No | Maximum results to fetch per query; omit for the server default |
rerank | bool | No | Unified rerank of results across engines |
summarize | bool | No | Attach summaries to results; enabling it increases cost and latency |
freshness | string | No | Restrict the recency of results |
site_whitelist / site_blacklist | string[] | No | Restrict / exclude sites |
language | string | No | Preferred result language |
objective | string | No | A description of the retrieval intent, used for reranking and summarization |
For the full schema, see WebSearchRequest in the OpenAPI spec.
Example:
from web_agent.v1 import Client
async with Client(api_key="wa_...", project_id="proj_demo") as client:
run = await client.web_search.run(
queries=["best Python ORM 2026", "SQLAlchemy vs Tortoise"],
max_results_per_query=10,
rerank=True,
)
for hit in run["results"]["results"]:
print(hit["final_rank"], hit["title"], hit["url"])Result
The run's results field (WebSearchResults):
| Field | Description |
|---|---|
results | The list of hits, each a SearchResultItem |
total_unique_results | Total number of results after deduplication |
is_summarized | Whether summaries were attached (true when summarize=true) |
engine_answer | The answer returned directly by the engine (provided by some engines) |
Each SearchResultItem:
| Field | Description |
|---|---|
title / url | Title and link |
canonical_url | The normalized URL; deduplication is keyed on this |
snippet | The summary fragment returned by the engine |
summary | The summary generated by WebAgent (present when summarize=true) |
final_rank / original_rank | Rank after / before reranking |
source_engine | Which engine the hit came from |
source_query | Which query the hit corresponds to |
dedup_count | How many engines/queries this result was hit by — higher means more trustworthy |
Async and continuation
WebSearch returns synchronously by default. With a large number of queries or summarize enabled, it takes longer; you can subscribe to the event stream to follow along:
GET /v1/projects/{pid}/web_search/runs/{run_id}/eventsThe event stream follows the SSE conventions. Other operations: cancel (cancel), refine (re-run the same batch of queries with a new intent), send_followup (add queries).
Next steps
- DeepResearch — use this when you want a written report
- Track — use this when you want to "continuously monitor changes to a query"
- API Overview — shared conventions; the full field set is in the OpenAPI spec