Skip to main content

Claude API Web Search Tool in Practice: Built-in Internet Search, No More Scraping (2026)

A deep dive into how Claude API's built-in Web Search Tool works and how to integrate it — with step-by-step examples showing how to let Claude search the internet directly, so you can stop writing scrapers or wiring up third-party search APIs for good.

ToolsClaudeAPI Web SearchEst. read25min
2026.04.22 published
Claude API Web Search Tool in Practice: Built-in Internet Search, No More Scraping (2026)

Claude API Web Search Tool in Practice: Built-in Internet Search, No More Scraping (2026)

GA as of April 2026 — enable web search in your Claude API calls with a single parameter. No Beta header. No third-party scraper. Available to all Claude API users out of the box.


What This Means for You

Before this, getting real-time information into a Claude response meant:

  1. Writing your own web scraper
  2. Wiring up a Google / Bing search API
  3. Running an MCP Server or RAG pipeline

Now it’s one parameter:

tools=[{"type": "web_search_20250305"}]
tools=[{"type": "web_search_20250305"}]

Claude automatically searches the web when needed, reads the content, cites its sources, and replies — all in one round trip.


Quick Start: Enable Search in 3 Lines

import anthropic

client = anthropic.Anthropic(
    api_key="your-api-key",
    base_url="https://api.claudeapi.com",
)

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=[{"type": "web_search_20250305"}],  # that's it
    messages=[
        {"role": "user", "content": "What happened in the stock market today?"}
    ]
)

# Parse the response
for block in response.content:
    if block.type == "text":
        print(block.text)
import anthropic

client = anthropic.Anthropic(
    api_key="your-api-key",
    base_url="https://api.claudeapi.com",
)

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=[{"type": "web_search_20250305"}],  # that's it
    messages=[
        {"role": "user", "content": "What happened in the stock market today?"}
    ]
)

# Parse the response
for block in response.content:
    if block.type == "text":
        print(block.text)

That’s all there is to it. Claude decides on its own whether a search is needed. When it is, it will:

  1. Generate search keywords
  2. Search the web
  3. Read relevant content
  4. Synthesize an answer
  5. Automatically include source URLs as citations

Parsing the Response

When Claude performs a search, the content array contains multiple block types:

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=[{"type": "web_search_20250305"}],
    messages=[
        {"role": "user", "content": "What new models has Anthropic released recently?"}
    ]
)

for block in response.content:
    if block.type == "tool_use":
        # Claude initiated a search
        print(f"🔍 Search: {block.input}")
    
    elif block.type == "web_search_tool_result":
        # Search results
        for result in block.content:
            if hasattr(result, "url"):
                print(f"📄 Source: {result.title} - {result.url}")
    
    elif block.type == "text":
        # Claude's final answer
        print(f"\n💬 Reply: {block.text}")
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=[{"type": "web_search_20250305"}],
    messages=[
        {"role": "user", "content": "What new models has Anthropic released recently?"}
    ]
)

for block in response.content:
    if block.type == "tool_use":
        # Claude initiated a search
        print(f"🔍 Search: {block.input}")
    
    elif block.type == "web_search_tool_result":
        # Search results
        for result in block.content:
            if hasattr(result, "url"):
                print(f"📄 Source: {result.title} - {result.url}")
    
    elif block.type == "text":
        # Claude's final answer
        print(f"\n💬 Reply: {block.text}")

Example output:

🔍 Search: Anthropic new model release 2026

📄 Source: Introducing Claude Opus 4.7 - https://www.anthropic.com/news/claude-opus-4-7
📄 Source: Claude Opus 4.7 is generally available - https://github.blog/changelog/...

💬 Reply: Anthropic released Claude Opus 4.7 on April 16, 2026.
It is the latest in the Opus series, with significant improvements
in coding ability and visual resolution...
🔍 Search: Anthropic new model release 2026

📄 Source: Introducing Claude Opus 4.7 - https://www.anthropic.com/news/claude-opus-4-7
📄 Source: Claude Opus 4.7 is generally available - https://github.blog/changelog/...

💬 Reply: Anthropic released Claude Opus 4.7 on April 16, 2026.
It is the latest in the Opus series, with significant improvements
in coding ability and visual resolution...

Use Case 1: Real-Time News Briefing Bot

import anthropic

client = anthropic.Anthropic(
    api_key="your-api-key",
    base_url="https://api.claudeapi.com",
)

def news_briefing(topic: str) -> str:
    """Generate a real-time news summary for a given topic."""
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=2048,
        tools=[{"type": "web_search_20250305"}],
        system="""You are a news analyst. After searching for the latest information, respond in this format:
        
## 📰 Latest on {topic}

### Key Takeaways
- Point 1
- Point 2
- Point 3

### Analysis
(200 words max)

### Sources
List all referenced URLs""",
        messages=[
            {"role": "user", "content": f"Search and summarize the latest news on: {topic}"}
        ]
    )
    
    for block in response.content:
        if block.type == "text":
            return block.text
    return "No information retrieved"

# Usage
print(news_briefing("AI coding tools"))
print(news_briefing("Claude Opus 4.7"))
import anthropic

client = anthropic.Anthropic(
    api_key="your-api-key",
    base_url="https://api.claudeapi.com",
)

def news_briefing(topic: str) -> str:
    """Generate a real-time news summary for a given topic."""
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=2048,
        tools=[{"type": "web_search_20250305"}],
        system="""You are a news analyst. After searching for the latest information, respond in this format:
        
## 📰 Latest on {topic}

### Key Takeaways
- Point 1
- Point 2
- Point 3

### Analysis
(200 words max)

### Sources
List all referenced URLs""",
        messages=[
            {"role": "user", "content": f"Search and summarize the latest news on: {topic}"}
        ]
    )
    
    for block in response.content:
        if block.type == "text":
            return block.text
    return "No information retrieved"

# Usage
print(news_briefing("AI coding tools"))
print(news_briefing("Claude Opus 4.7"))

Use Case 2: Competitive Pricing Monitor

def compare_prices(product: str) -> str:
    """Search and compare product pricing across platforms."""
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=2048,
        tools=[{"type": "web_search_20250305"}],
        system="You are a pricing analyst. After searching, output a Markdown table comparing prices across platforms.",
        messages=[
            {"role": "user", "content": f"Search for {product} pricing across platforms and output a comparison table"}
        ]
    )
    
    for block in response.content:
        if block.type == "text":
            return block.text

print(compare_prices("Claude API vs GPT API pricing"))
def compare_prices(product: str) -> str:
    """Search and compare product pricing across platforms."""
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=2048,
        tools=[{"type": "web_search_20250305"}],
        system="You are a pricing analyst. After searching, output a Markdown table comparing prices across platforms.",
        messages=[
            {"role": "user", "content": f"Search for {product} pricing across platforms and output a comparison table"}
        ]
    )
    
    for block in response.content:
        if block.type == "text":
            return block.text

print(compare_prices("Claude API vs GPT API pricing"))

Use Case 3: Auto-Querying Technical Docs

def search_docs(question: str) -> str:
    """Search technical documentation to answer a question."""
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=2048,
        tools=[{"type": "web_search_20250305"}],
        system="""You are a technical consultant. When answering questions:
1. Search official docs and technical blogs first
2. Give a precise answer with code examples
3. Cite source URLs
4. Flag if information may be outdated""",
        messages=[
            {"role": "user", "content": question}
        ]
    )
    
    for block in response.content:
        if block.type == "text":
            return block.text

# Examples
print(search_docs("What is the latest version of the Python anthropic SDK? How do I install it?"))
print(search_docs("What is the max_tokens limit for Claude?"))
def search_docs(question: str) -> str:
    """Search technical documentation to answer a question."""
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=2048,
        tools=[{"type": "web_search_20250305"}],
        system="""You are a technical consultant. When answering questions:
1. Search official docs and technical blogs first
2. Give a precise answer with code examples
3. Cite source URLs
4. Flag if information may be outdated""",
        messages=[
            {"role": "user", "content": question}
        ]
    )
    
    for block in response.content:
        if block.type == "text":
            return block.text

# Examples
print(search_docs("What is the latest version of the Python anthropic SDK? How do I install it?"))
print(search_docs("What is the max_tokens limit for Claude?"))

Use Case 4: Search + Multi-Turn Chat

def chat_with_search():
    """Multi-turn conversation with built-in search."""
    messages = []
    
    while True:
        user_input = input("\nYou: ")
        if user_input.lower() in ("quit", "exit"):
            break
        
        messages.append({"role": "user", "content": user_input})
        
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=2048,
            tools=[{"type": "web_search_20250305"}],
            messages=messages
        )
        
        assistant_text = ""
        for block in response.content:
            if block.type == "text":
                assistant_text += block.text
        
        print(f"\nClaude: {assistant_text}")
        messages.append({"role": "assistant", "content": response.content})

chat_with_search()
def chat_with_search():
    """Multi-turn conversation with built-in search."""
    messages = []
    
    while True:
        user_input = input("\nYou: ")
        if user_input.lower() in ("quit", "exit"):
            break
        
        messages.append({"role": "user", "content": user_input})
        
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=2048,
            tools=[{"type": "web_search_20250305"}],
            messages=messages
        )
        
        assistant_text = ""
        for block in response.content:
            if block.type == "text":
                assistant_text += block.text
        
        print(f"\nClaude: {assistant_text}")
        messages.append({"role": "assistant", "content": response.content})

chat_with_search()

Advanced Configuration

Limit the Number of Searches

tools=[
    {
        "type": "web_search_20250305",
        "max_uses": 3,  # max 3 searches per conversation turn
    }
]
tools=[
    {
        "type": "web_search_20250305",
        "max_uses": 3,  # max 3 searches per conversation turn
    }
]

Restrict Search to Specific Domains

tools=[
    {
        "type": "web_search_20250305",
        "allowed_domains": [
            "anthropic.com",
            "github.com",
            "stackoverflow.com"
        ]
    }
]
tools=[
    {
        "type": "web_search_20250305",
        "allowed_domains": [
            "anthropic.com",
            "github.com",
            "stackoverflow.com"
        ]
    }
]

Block Specific Domains

tools=[
    {
        "type": "web_search_20250305",
        "blocked_domains": [
            "reddit.com",
            "quora.com"
        ]
    }
]
tools=[
    {
        "type": "web_search_20250305",
        "blocked_domains": [
            "reddit.com",
            "quora.com"
        ]
    }
]

Force Search vs. Auto-Decide

# Default: Claude decides whether to search
tools=[{"type": "web_search_20250305"}]

# Nudge Claude to always search (via prompt)
messages=[
    {"role": "user", "content": "Please search the web first, then answer: What are today's top AI news stories?"}
]
# Default: Claude decides whether to search
tools=[{"type": "web_search_20250305"}]

# Nudge Claude to always search (via prompt)
messages=[
    {"role": "user", "content": "Please search the web first, then answer: What are today's top AI news stories?"}
]

Pricing

Item Billing
Web Search tool invocation Per search request
Search result input tokens Standard input token rate
Claude response output tokens Standard output token rate

ClaudeAPI.com users get 20% off on all usage, including Web Search Tool calls.


Comparison: Web Search Tool vs. DIY Approach

Dimension Web Search Tool DIY (Google API + Scraper)
Code required 1 parameter 100+ lines (API call + HTML parsing + data cleaning)
Maintenance Zero Anti-bot measures, API quota management
Result quality Claude auto-filters relevant content You build your own relevance ranking
Source citations Automatic with URLs Manual assembly
Dependencies None Google API Key / BeautifulSoup / Selenium
Cost Search fee + tokens Search API fee + server + tokens

FAQ

Q: How does the Web Search Tool differ from MCP-based search?

The Web Search Tool is a native Claude API capability — one parameter and you’re done, no extra services needed. MCP search requires deploying a separate MCP Server. It’s more flexible but also more complex. Use the Web Search Tool for straightforward scenarios; reach for MCP when you need to search custom data sources or private databases.


Q: Does Claude search on every request?

No. Claude autonomously decides whether a search is needed. If the question falls within its training knowledge, it answers directly. Searches are only triggered for real-time information, recent data, or topics beyond its training cutoff.


Q: Can I control the language of search results?

Yes, via prompt engineering. For example, add to your system prompt: “When searching, prefer English keywords and cite English-language sources.”


Q: How many searches can happen in a single request?

You can control this with max_uses. Without it, there’s no hard limit, but Claude typically searches 1–3 times before it has enough information to answer.


Q: Is there any difference when calling through ClaudeAPI.com?

None whatsoever. ClaudeAPI.com is fully compatible with the Anthropic API. The Web Search Tool works identically, and you get 20% off. Just set base_url to https://gw.claudeapi.com.


TL;DR

What you want to do Before Now
Get real-time info Scraper + Search API tools=[{"type": "web_search_20250305"}]
Look up latest docs Manual search & paste Claude searches and cites automatically
Monitor competitors Scheduled scraper scripts One API call
Summarize news RSS + parser + summarizer One API call

The Web Search Tool turns Claude from “can only answer from training data” into “can search the entire web first, then answer” — and all you need is one extra parameter.


Get Started

Sign up for ClaudeAPI →

Pay with stripes. 20% off standard Anthropic pricing. Web Search Tool ready to use.

Related Articles