web_search Tool Reference

Complete reference for the web_search tool available to the LLM during page generation.

Contents

1. Overview

The web_search tool gives the LLM the ability to query a live web search engine during page generation. When enabled, the model can issue search queries and receive back structured results — titles, URLs, and snippets — that it can incorporate into generated HTML.

This makes generated pages significantly more factual, current, and detailed compared to generation without tool access. For example, a page about a software project can pull in the current version number; a page about a city can include accurate population figures; a news-oriented page can surface recent headlines.

Web tools (both web_search and web_fetch) are enabled by default. Pass --no-web-tools at startup to disable them. See Section 11.

Note: Tool use requires additional API round-trips. Each search call adds latency and token cost to page generation. A single page may invoke web_search multiple times. See Rate Limits & Cost.

2. JSON Schema Definition

Rabbithole registers the web_search tool with the Anthropic API using the following JSON schema. This is passed verbatim in the tools array of every Claude API request when web tools are enabled.

{
  "name": "web_search",
  "description": "Search the web for current information. Returns a list of results
with titles, URLs, and text snippets. Use this to find real, up-to-date facts,
images, documentation, or any information you need to produce an accurate and
detailed page. Prefer specific, targeted queries over broad ones.",
  "input_schema": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "The search query string. Should be concise and specific.
1 to 6 words typically works best. Avoid special operators unless required."
      }
    },
    "required": ["query"]
  }
}

3. Parameters

The tool accepts the following input fields:

Field Type Required Description
query string REQUIRED The search query to execute. The model constructs this string based on what information it needs. Optimal queries are 1–6 words. Longer queries reduce relevance of returned results. The query is passed directly to the configured search provider's API.
No num_results parameter: The number of results returned is determined by the server-side configuration (see Configuration). The LLM cannot request more or fewer results per call.

4. Return Value

The tool returns a JSON array of search result objects. Each object contains the following fields:

Field Type Always present? Description
title string Yes The title of the web page as indexed by the search engine.
url string Yes The canonical URL of the result. Can be passed to web_fetch for full content.
snippet string Yes A short excerpt or description from the page, as provided by the search engine. Typically 1–4 sentences. May contain HTML entities depending on the provider.
published_date string | null No ISO 8601 date string indicating when the page was published or last indexed, if the provider exposes this. null when unavailable.

Return Value Structure

Results are returned as a top-level JSON array. If no results are found, an empty array [] is returned. If the search provider returns an error, the tool returns a JSON object with an error field:

{ "error": "Search provider returned HTTP 429: rate limit exceeded" }

The LLM is instructed to handle both empty results and error responses gracefully by falling back to its training knowledge.

5. Search Providers

Rabbithole's web_search implementation is provider-agnostic at the server level. The search backend is selected via environment variable or CLI flag. The following providers are supported:

Provider Env Variable Notes
Brave Search API BRAVE_API_KEY Default provider when a key is present. Independent index, privacy-focused. Free tier available (2,000 queries/month). Paid plans scale from $3/1,000 queries. brave.com/search/api
SerpAPI SERPAPI_KEY Wraps Google, Bing, and other engines. High quality results. Free tier is 100 searches/month; paid plans from $50/month for 5,000 searches. serpapi.com
Anthropic built-in (none required) When no provider key is configured, Rabbithole falls back to the web_search tool built into the Anthropic API (available on Claude models that support it natively). No additional key required, but billed as part of API token usage.
Provider selection priority: BRAVE_API_KEY > SERPAPI_KEY > Anthropic built-in. If you set both Brave and SerpAPI keys, Brave is used. To force a specific provider, unset the higher-priority keys.

6. Configuration

The following environment variables control the behavior of web_search at runtime. All are optional unless noted.

Variable Default Description
BRAVE_API_KEY unset API key for Brave Search. Enables Brave as the search provider when set.
SERPAPI_KEY unset API key for SerpAPI. Used as fallback if Brave key is not set.
RABBITHOLE_SEARCH_RESULTS 5 Number of results to request from the search provider per query. Increasing this gives the LLM more context but uses more tokens. Recommended range: 3–10.
RABBITHOLE_SEARCH_TIMEOUT_SECS 10 HTTP timeout in seconds for search provider requests. If exceeded, the tool returns an error object and the LLM falls back to training data.

These can also be set via a .env file in the working directory. CLI flag --no-web-tools disables all web tools regardless of which keys are set. See Configuration reference for full details.

7. Rate Limits & Cost

Search Provider Costs

The cost per search query depends on the provider:

Provider Free Tier Paid Rate
Brave Search API 2,000 queries/month ~$0.003 per query (Data for Search plan)
SerpAPI 100 searches/month ~$0.01 per search (Hobby plan)
Anthropic built-in N/A Billed via Claude API tokens (varies by model)

Token Cost Impact

Each web_search call introduces additional tokens into the conversation context:

Because tool results are injected into the context window, pages generated with web_search will consistently use more tokens than non-tool pages. Plan accordingly when setting --max-cost.

Budget cap: Use --max-cost <dollars> to set a total spend limit across all page generations. Once the cumulative cost (Claude API + any direct provider costs tracked by Rabbithole) exceeds the cap, uncached pages redirect to 404 instead of generating. This is the recommended safeguard for public-facing deployments. See Configuration.

Rate Limiting Behavior

Rabbithole does not implement its own request queue for search calls — if multiple pages are being generated concurrently (parallel visitors), each may independently issue web_search calls. On low-volume free tiers this can exhaust quotas quickly. For production deployments with sustained traffic, configure a paid provider tier or set --no-web-tools to eliminate provider rate limit risk.

8. Example Tool Call

The following is an example of what the Claude API sends Rabbithole when the model decides to invoke web_search during generation of a page about the Rust programming language:

{
  "type": "tool_use",
  "id": "toolu_01XzQpLm7Kn2bRfDgA4cPwEj",
  "name": "web_search",
  "input": {
    "query": "Rust programming language latest stable version 2025"
  }
}

Rabbithole intercepts this, executes the query against the configured search provider, and returns the results to the model as a tool_result block in the next API message:

{
  "type": "tool_result",
  "tool_use_id": "toolu_01XzQpLm7Kn2bRfDgA4cPwEj",
  "content": "[ ... search results JSON ... ]"
}

The model then continues generating the HTML page with this information incorporated.

9. Example Response

The following is a representative example of the JSON array returned by the tool:

[
  {
    "title": "Rust 1.84.0 Released - The Rust Programming Language Blog",
    "url": "https://blog.rust-lang.org/2025/01/09/Rust-1.84.0.html",
    "snippet": "The Rust team is happy to announce a new version of Rust, 1.84.0.
Rust is a programming language empowering everyone to build reliable and
efficient software.",
    "published_date": "2025-01-09"
  },
  {
    "title": "Rust (programming language) - Wikipedia",
    "url": "https://en.wikipedia.org/wiki/Rust_(programming_language)",
    "snippet": "Rust is a multi-paradigm, general-purpose programming language that
emphasizes performance, type safety, and concurrency. It enforces memory safety,
meaning that all references point to valid memory.",
    "published_date": null
  },
  {
    "title": "Install Rust - rust-lang.org",
    "url": "https://www.rust-lang.org/tools/install",
    "snippet": "Get started with Rust using rustup. The recommended installation
method for Rust on Linux and macOS is to use rustup, the official Rust toolchain
installer.",
    "published_date": null
  },
  {
    "title": "Releases · rust-lang/rust - GitHub",
    "url": "https://github.com/rust-lang/rust/releases",
    "snippet": "Release notes and changelogs for all stable, beta, and nightly
versions of the Rust compiler.",
    "published_date": "2025-01-09"
  },
  {
    "title": "The Rust Reference - rust-lang.org",
    "url": "https://doc.rust-lang.org/reference/",
    "snippet": "The Reference is not a formal specification of Rust's semantics but
is more detailed and comprehensive than the book.",
    "published_date": null
  }
]

The url field in each result can be passed directly to web_fetch to retrieve the full page content if the model needs more detail than the snippet provides.

10. Writing Good Search Queries in Prompts

When writing seed prompts or linked-page prompts for Rabbithole, you can influence how the LLM uses web_search by being explicit about what information you want it to look up. The following guidelines help get better results:

Be specific about what to search for

Rather than saying "include information about the project", say "search for the current GitHub star count and latest release version of the project." Explicit guidance prevents the model from skipping searches or issuing overly broad queries.

Name the source if you know it

If you want information from a specific source (e.g., Wikipedia, official docs, a news outlet), say so: "search for X on the official Rust documentation site." The model will construct a more targeted query.

Ask for images by URL

If you want real images hotlinked into the page, instruct the model to search for them: "search for a high-quality image of X and embed it with an <img> tag." The model can search for images and use the result URLs directly in src attributes.

Specify recency requirements

For rapidly changing data (prices, versions, statistics), add: "use web_search to find the most current figure available, and note the date in the page." This pushes the model to prioritize recent search results and attribute them.

Avoid over-specifying query wording

You generally do not need to write the exact query string in your prompt. The model is good at constructing search queries from high-level intent. Trust it to reformulate: "find recent benchmark comparisons" works better than prescribing the exact query string character-for-character.

Limit scope when appropriate

For pages where factual accuracy matters most (reference docs, product specs, biographies), include: "verify all factual claims with web_search before including them." For purely creative/fictional pages, you may instruct: "do not use web_search; invent all content."

Example prompt excerpt

Here is an example prompt excerpt demonstrating these principles:

Generate a reference page for the SQLite database engine.

Use web_search to find:
- The current stable version of SQLite and its release date
- The official SQLite website URL for linking
- A one-paragraph description from the official SQLite about page
- The current file size of the SQLite amalgamation source file

Embed the SQLite logo by searching for its image URL and hotlinking it.
Note the date of any statistics you include.

11. Disabling the Tool

To disable web_search (and web_fetch) entirely, start Rabbithole with the --no-web-tools flag:

cargo run -- --seed "My homepage" --no-web-tools

Reasons you might disable web tools:

See also: Web Tools overview for information on both web_search and web_fetch, and how they interact.

---MAPPINGS--- {}