Web Search Solutions on AWS
A guide to unlocking web search for Anthropic models on AWS Bedrock using Claude Platform, Brave, or Tavily.
The Problem
Native web search is not currently available for Anthropic models on Bedrock. This feature gap between Anthropic's first-party offering and Bedrock may be blocking you from migrating your inference workloads to AWS, and there is no confirmed date for when native web search will land on Bedrock.
The Solutions
You have a few possible paths forward, each with different tradeoffs depending on your requirements.
Claude Platform on Bedrock: Claude Platform on AWS gives you direct access to Anthropic's first-party APIs and infrastructure using your AWS billing and IAM credentials. It supports identical server-side tool functionality to Anthropic's native API, including web search, making it the simplest drop-in option.
The caveat: if you have strict data residency requirements, this isn't the right fit. Your data is processed and stored by Anthropic's backend rather than AWS. If that's a concern, the next option is a better fit.
Migrate to Bedrock with Third-Party Web Search: Tavily and Brave are both strong third-party alternatives. Anthropic's built-in web search is the simplest to use natively in Claude, but it's also the most expensive per query and gives you the least control over how results are gathered and reused. Here's how the three stack up on pricing:
| Option | Pricing |
|---|---|
| Brave Search API | $5 per 1,000 requests, with $5 in monthly free credits |
| Tavily | Free tier: 1,000 credits/month; pay-as-you-go: $0.008/credit; monthly plans: ~$0.0075–$0.005/credit; enterprise pricing available. Standard search = 1 credit, advanced = 2 credits |
| Anthropic Built-in | $10 per 1,000 searches, plus standard token costs for search-generated content |
For cost-sensitive customers, Brave is the clear winner. Brave's LLM Context API endpoint takes in a query string and returns a data-first ranking where the most relevant chunks are scored, ranked, and compiled in a compact format optimized directly for LLM consumption.
Tavily takes a similar approach but is more agent-oriented and customizable. The Tavily Search API aggregates up to 20 sites per API call and uses proprietary AI to score, filter, and rank the most relevant sources and content for your task or query.
Implementation Examples
The samples below show a simple agentic loop using the Bedrock Converse API with web search wired in as a tool. These are intentionally minimal examples meant to illustrate the pattern - in a production setup you'd layer in error handling, retries, and whatever orchestration framework fits your stack.
Brave:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import os
import json
import boto3
import requests
BRAVE_API_KEY = os.environ["BRAVE_API_KEY"]
BEDROCK_MODEL_ID = "us.anthropic.claude-sonnet-4-5-20250929-v1:0"
TOOLS = [{
"toolSpec": {
"name": "web_search",
"description": "Search the web for current information.",
"inputSchema": {
"json": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "The search query"}
},
"required": ["query"]
}
}
}
}]
def web_search(query):
resp = requests.get(
"https://api.search.brave.com/res/v1/llm/context",
headers={"X-Subscription-Token": BRAVE_API_KEY, "Accept": "application/json"},
params={"q": query, "count": 5},
)
return json.dumps(resp.json())
def run_agent(user_query):
session = boto3.Session(profile_name="admin339")
client = session.client("bedrock-runtime", region_name="us-east-1")
messages = [{"role": "user", "content": [{"text": user_query}]}]
while True:
resp = client.converse(
modelId=BEDROCK_MODEL_ID,
toolConfig={"tools": TOOLS},
messages=messages,
)
output = resp["output"]["message"]
messages.append(output)
if resp["stopReason"] == "end_turn":
return output["content"][0]["text"]
# Claude called a tool — execute it and feed results back
tool_results = []
for block in output["content"]:
if "toolUse" in block:
tool = block["toolUse"]
print(f"[searching] {tool['input']['query']}")
result = web_search(tool["input"]["query"])
tool_results.append({
"toolResult": {
"toolUseId": tool["toolUseId"],
"content": [{"text": result}],
}
})
messages.append({"role": "user", "content": tool_results})
print(run_agent("What are the latest AI news stories this week?"))
Tavily:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import os
import json
import boto3
from tavily import TavilyClient
TAVILY_API_KEY = os.environ["TAVILY_API_KEY"]
BEDROCK_MODEL_ID = "us.anthropic.claude-sonnet-4-5-20250929-v1:0"
TOOLS = [{
"toolSpec": {
"name": "web_search",
"description": "Search the web for current information.",
"inputSchema": {
"json": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "The search query"}
},
"required": ["query"]
}
}
}
}]
def web_search(query):
client = TavilyClient(api_key=TAVILY_API_KEY)
resp = client.search(query, max_results=5)
return json.dumps(resp)
def run_agent(user_query):
session = boto3.Session(profile_name="admin339")
client = session.client("bedrock-runtime", region_name="us-east-1")
messages = [{"role": "user", "content": [{"text": user_query}]}]
while True:
resp = client.converse(
modelId=BEDROCK_MODEL_ID,
toolConfig={"tools": TOOLS},
messages=messages,
)
output = resp["output"]["message"]
messages.append(output)
if resp["stopReason"] == "end_turn":
return output["content"][0]["text"]
# Claude called a tool — execute it and feed results back
tool_results = []
for block in output["content"]:
if "toolUse" in block:
tool = block["toolUse"]
print(f"[searching] {tool['input']['query']}")
result = web_search(tool["input"]["query"])
tool_results.append({
"toolResult": {
"toolUseId": tool["toolUseId"],
"content": [{"text": result}],
}
})
messages.append({"role": "user", "content": tool_results})
print(run_agent("What are the latest AI news stories this week?"))
The two implementations are nearly identical in structure, which is intentional - swapping between providers is straightforward. The only meaningful differences are the
web_search function itself and the respective API key. Conclusion
If your data residency requirements are flexible and you want the simplest possible path to native web search, Claude Platform on Bedrock is the easiest drop-in. For those who need to keep data within AWS, both Brave and Tavily are solid options that integrate cleanly with Bedrock. If you're starting fresh and cost is the primary driver, go with Brave. If you need more agent-oriented control and richer result metadata, Tavily is worth the slight premium.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article