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:
- Writing your own web scraper
- Wiring up a Google / Bing search API
- 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:
- Generate search keywords
- Search the web
- Read relevant content
- Synthesize an answer
- 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
Pay with stripes. 20% off standard Anthropic pricing. Web Search Tool ready to use.



