Use Web Search Tools

Su Suriya Ravichandran Updated 10 Nov 2026
6 min read ·Lesson 155 of 200

Letting Claude Look Things Up

Everything in the model's knowledge has a date. Questions about prices, news, software versions, or the current holder of an office depend on information that may have changed since training. The web search tool lets Claude search the internet while it answers, and cite the pages it relied on. It is a server tool, which means the search runs on Anthropic's infrastructure rather than in your code. You enable it in the request, and the search happens inside the same API call.

That difference matters for how the feature is built. With a client tool (Lessons 86–90), your code runs the function and returns the result. With a server tool, your code does nothing during the search. The response you receive already contains the searches Claude made, the results it saw, and the answer it wrote with citations. Your job is to read those parts correctly, to decide what to trust, and to present sources to users.

This lesson explains how server tools differ from client tools, how the search appears in the response, how citations link answers to sources, and how to build a function that collects and checks the sources an answer used.


Server Tools and Client Tools

The two kinds of tool differ in where they run and who completes the work:

AspectClient toolServer tool (web search)
Where it runsYour codeAnthropic's servers
Who executes itYour applicationThe API
What the response containsA tool_use block that you must answerThe search activity and results, already completed
Your loopYou send results back, and repeat until doneThe API may pause the turn for long searches, which you resume
Stop reason to watchtool_usepause_turn (Lesson 88)

Lesson 88 introduced pause_turn. A server-side loop can run for several iterations, and the API may return a paused response partway through. The documentation's continuation pattern sends the paused assistant content back as it is, to let the search finish. A loop that treats pause_turn as an error will stop too early.


Enabling the Tool

The web search tool is declared in the request's tool list, with its type identifier. The type string carries a version, and the exact identifier for the current version is in the web search tool reference, which should be copied from there:

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=2048,
    tools=[{"type": "web_search_20250305", "name": "web_search"}],
    messages=[{"role": "user", "content": "What is the current Python release?"}],
)

The identifier shown is the one used in the examples in the search documentation at the time of writing. Versions change, and an out-of-date identifier can be rejected, so the reference is the place to confirm it before use.


What the Response Contains

A response that used web search has several kinds of content block, in order. Reading them in sequence explains how the answer was formed:

BlockMeaning
server_tool_useThe search Claude ran, including its query
web_search_tool_resultThe results returned for that query, each with a URL and title
textClaude's answer, with citations attached to the sentences that rely on sources

The text blocks may carry citations. Each citation names a source by URL and title, and quotes the passage it relied on. A citation of type web_search_result_location is the form used for web sources, and it lets an application link each claim to a page.

Citations are evidence, not proof. A citation shows that a page said something, which can be wrong, outdated, or biased. The application must decide how much weight the sources deserve, and whether the answer is consistent with them.


Collecting the Sources

An application that presents sources needs three things: the list of pages searched, the subset the answer cited, and a check that each citation points to a page that actually appeared in the results. The last check guards against malformed or mismatched data. The function below does all three, working from the content blocks:

"""web_sources.py: collect the sources an answer used, and check every citation against the results."""


def collect_sources(content: list[dict]) -> dict:
    searched, results = [], {}
    for block in content:
        if block.get("type") == "server_tool_use":
            searched.append(block["input"].get("query", ""))
        elif block.get("type") == "web_search_tool_result":
            for item in block.get("content", []):
                results[item["url"]] = item.get("title", "")

    cited, problems = {}, []
    for block in content:
        if block.get("type") != "text":
            continue
        for citation in block.get("citations") or []:
            url = citation.get("url")
            if url in results:
                cited[url] = results[url]
            else:
                problems.append(f"citation to a page that was not in the results: {url}")
    return {"queries": searched, "searched_pages": len(results),
            "cited": cited, "problems": problems}


if __name__ == "__main__":
    content = [
        {"type": "server_tool_use", "name": "web_search", "input": {"query": "latest Python release"}},
        {"type": "web_search_tool_result", "content": [
            {"type": "web_search_result", "url": "https://www.python.org/downloads/", "title": "Downloads"},
            {"type": "web_search_result", "url": "https://example.org/news", "title": "Unrelated news"},
        ]},
        {"type": "text", "text": "The newest release is listed on the official downloads page.",
         "citations": [{"type": "web_search_result_location",
                        "url": "https://www.python.org/downloads/", "title": "Downloads",
                        "cited_text": "Python release downloads"}]},
        {"type": "text", "text": " A blog post also mentions it.",
         "citations": [{"type": "web_search_result_location",
                        "url": "https://blog.invalid/post", "title": "Post",
                        "cited_text": "a mention"}]},
    ]
    sources = collect_sources(content)
    print("queries:", sources["queries"])
    print("pages searched:", sources["searched_pages"])
    print("cited:", sources["cited"])
    print("problems:", sources["problems"])

Output:

queries: ['latest Python release']
pages searched: 2
cited: {'https://www.python.org/downloads/': 'Downloads'}
problems: ['citation to a page that was not in the results: https://blog.invalid/post']

How It Works

  1. The queries come from server_tool_use blocks, so the application can show what was searched, and can audit whether the searches fit the question.
  2. The results are indexed by URL. Every page the search returned is recorded, along with its title, so citations can be matched against them.
  3. Each citation is checked. The first is to a page in the results, so it is recorded as cited. The second points to a page that never appeared in the search, which is the kind of mismatch the check exists to catch.
  4. The problem is reported, not hidden. An application that displays sources should either drop the unsupported citation, or flag the answer for review.
  5. The result separates what was searched from what was cited. Two pages were searched, and only one was cited, which is a useful signal about how the answer was built.

Choosing What to Trust

Search results vary in quality, and the application's policy decides how to handle them. A reasonable policy checks the source's domain against a list of trusted publishers for high-stakes questions, asks for a second source when claims conflict, and labels answers that rest on a single page. The documentation describes options that restrict which domains the search can use, and the reference should be consulted for the exact parameters. Whatever the mechanism, the principle is that a search is a way of gathering evidence, and the application is responsible for judging it.


Cost and Limits

Each search has a cost in addition to the tokens, and the search results themselves are input to the model, so they count toward the token bill. The pricing and any usage limits for the tool are published with the tool's documentation. An application that allows users to trigger searches freely should monitor how often they run, using the same usage tracking as Lesson 125.


Summary

The web search tool is a server tool: Claude searches during the API call, and the response records the queries, the results, and the citations. Reading those blocks in order explains the answer, and checking each citation against the results keeps the sources honest. Search provides current information, but the application remains responsible for weighing it. The next lesson covers a different kind of server-side capability, computer use, in which Claude operates a graphical environment.

0 Comments

Reviewed before they appear

No comments yet.

Anthropic SDK Using Python
Anthropic SDK Intro Claude API Intro SDK Requirements Install Anthropic SDK Upgrade the SDK Create an API Key Set API Keys Use Environment Variables Import Anthropic Create a Client Send Your First Message Choose a Claude Model Set Max Tokens Read a Response Print Response Text Understand Message Blocks Use System Prompts Send User Messages Set Temperature Handle Stop Reasons Messages API Intro Create Messages Use Message Roles Send Conversation History Continue a Conversation Build a Chat Loop Reset Chat History Use Multiple Turns Inspect Message IDs Read Usage Data Write Clear Prompts Set a System Prompt Add Context to Prompts Use Prompt Templates Add Examples to Prompts Request JSON Output Use XML Tags Control Response Length Improve Prompt Quality Avoid Prompt Injection Read Text Blocks Read Content Blocks Check Stop Reasons Count Input Tokens Count Output Tokens Count Tokens Before Sending Limit Output Tokens Use Stop Sequences Read Request IDs Parse API Responses Streaming Intro Stream Text Output Use Stream Events Use Stream Helpers Get Final Messages Stream Async Responses Handle Stream Errors Build a Live Chat Stream Long Responses Close Streams Safely Build a Chatbot Keep Chat History Manage Chat Sessions Add Chat Memory Build a CLI Chatbot Build a Web Chatbot Use Flask with Claude Use FastAPI with Claude Return JSON from an API Add Chat Error Messages Async SDK Intro Create an Async Client Send Async Messages Use asyncio Run Parallel Requests Stream Async Text Handle Async Errors Set Async Timeouts Close Async Clients Choose Sync or Async Tool Use Intro Define a Tool Create Tool Schemas Send Tools to Claude Read Tool Calls Run Python Tools Return Tool Results Continue After Tool Use Control Tool Choice Handle Tool Errors Use the beta_tool Decorator Create a Tool Runner Add Tool Docstrings Validate Tool Inputs Use Multiple Tools Limit Tool Calls Log Tool Activity Build a Weather Tool Build a Search Tool Build a Calculator Tool Structured Output Intro Request JSON Data Validate JSON Output Use Pydantic Models Handle Invalid JSON Extract Fields from Text Generate Typed Data Use Image URLs Send Base64 Images Read PDFs with Claude Use Output Schemas Build Data Extraction Test Structured Responses Send Image Inputs Upload Files Use File IDs Process Text Files Summarize Documents Extract Table Data Handle File Errors Read Cache Usage Reduce Repeated Input Costs Debug Cache Misses Prompt Caching Intro Enable Prompt Caching Cache System Prompts Cache Long Context Test Cache Performance Use Cache Breakpoints Cache Best Practices Message Batches Intro Create a Message Batch Set Batch IDs Check Batch Status List Message Batches Get Batch Results Process Batch Outputs Handle Failed Batch Items Use Batches for Bulk Tasks Compare Batches and Requests Handle API Errors Handle Rate Limits Retry Failed Requests Set Request Timeouts Handle Network Errors Use Exponential Backoff Build Reliable API Calls Use Extended Thinking Log API Errors Track Request IDs Paginate API Results Set Thinking Budgets Read Thinking Blocks Use Tool Search Use Web Search Tools Use Computer Tools Use Citations Use Token Counting Read Raw Responses Set Custom Headers Use Claude on AWS Bedrock Use Claude on Vertex AI Use Claude on Microsoft Foundry Configure Cloud Credentials Choose a Cloud Provider Compare API Integrations Configure Provider Clients Handle Cloud Errors Use Cloud SDK Extras Deploy Cloud Apps Protect API Keys Use a .env File Ignore Secrets in Git Validate User Input Reduce Prompt Injection Limit Tool Permissions Avoid Unsafe Tool Calls Sanitize Tool Results Set Usage Limits Review Security Logs Test SDK Functions Mock API Responses Test Error Handling Test Streaming Code Measure Token Usage Track API Costs Configure Logging Deploy with Docker Deploy a FastAPI App Monitor Production Apps Build a Claude Chatbot Build a Text Summarizer Build a Code Explainer Build a JSON Extractor Build a PDF Assistant Build a Streaming Chat App Build a Tool-Calling Agent Build a Batch Processor Build a Research Assistant Build a Claude API Dashboard
Ask about this post
AI Ask about this post

Ask questions about Use Web Search Tools and get answers drawn from it.

Signed-in readers only.