BraveWebSearchTool¶
Web search capabilities using the Brave Search API. Provides up-to-date information from the web with optional domain filtering.
Features: - Search the web using Brave's privacy-focused search API - Configurable result count (default: 10) - Domain filtering (include/exclude specific domains) - Supports both web and video search results - Client-side domain filtering with subdomain matching - Structured JSON response format - Error handling with graceful fallbacks
Overview¶
The BraveWebSearchTool enables AI agents to search the web for current information beyond their knowledge cutoff. It uses the Brave Search API to retrieve search results and returns them in a structured format suitable for AI processing.
Key Characteristics: - Returns search results as JSON with title, URL, and description - Supports domain-based filtering (client-side) - Includes both web pages and videos in results - Privacy-focused (Brave Search doesn't track users)
Basic Usage¶
BraveWebSearchTool searchTool = BraveWebSearchTool.builder("your-api-key")
.build();
String results = searchTool.webSearch("Spring AI framework", null, null);
System.out.println(results);
Response Format:
[
{
"title": "Spring AI - Spring",
"url": "https://spring.io/projects/spring-ai",
"description": "Spring AI provides abstractions for developing AI applications..."
},
{
"title": "Spring AI Reference Documentation",
"url": "https://docs.spring.io/spring-ai/reference/",
"description": "Comprehensive guide to Spring AI features..."
}
]
Getting an API Key¶
- Visit Brave Search API
- Sign up for an account
- Subscribe to a plan (Free tier available with rate limits)
- Copy your API subscription token
- Store it securely (environment variable recommended)
Pricing (as of 2025): - Free: 2,000 queries/month - Paid plans: Higher limits and additional features
Builder Configuration¶
Required Parameter¶
apiKey - Your Brave Search API subscription token
Optional Parameters¶
| Option | Default | Description |
|---|---|---|
resultCount |
10 | Number of search results to return (max typically 20) |
Example with custom result count:
BraveWebSearchTool searchTool = BraveWebSearchTool.builder("your-api-key")
.resultCount(15) // Return up to 15 results
.build();
Domain Filtering¶
Client-Side Filtering¶
The tool supports filtering results by domain. Important: Domain filtering is applied client-side after fetching results, meaning filtered results still count against your API quota.
Include Specific Domains¶
BraveWebSearchTool searchTool = BraveWebSearchTool.builder("your-api-key").build();
// Only include results from spring.io
String results = searchTool.webSearch(
"Spring Boot tutorial",
List.of("spring.io"), // allowedDomains
null // blockedDomains
);
Exclude Specific Domains¶
// Exclude results from example.com and spam.com
String results = searchTool.webSearch(
"Java programming",
null, // allowedDomains
List.of("example.com", "spam.com") // blockedDomains
);
Combine Allowed and Blocked¶
// Only spring.io and baeldung.com, but exclude outdated-site.com
String results = searchTool.webSearch(
"Spring Framework 2025",
List.of("spring.io", "baeldung.com"), // allowedDomains
List.of("outdated-site.com") // blockedDomains
);
Subdomain Matching¶
Domain filters automatically match subdomains:
// Filter: "spring.io" matches:
// - spring.io
// - docs.spring.io
// - start.spring.io
// - blog.spring.io
Search Operators (Recommended)¶
For better API quota efficiency, use Brave's search operators directly in your query instead of client-side filtering:
BraveWebSearchTool searchTool = BraveWebSearchTool.builder("your-api-key").build();
// Search only on spring.io (more efficient)
String results = searchTool.webSearch("Spring AI site:spring.io", null, null);
// Exclude a domain
String results2 = searchTool.webSearch("Java tutorial -site:example.com", null, null);
// Multiple site operators
String results3 = searchTool.webSearch(
"Spring Framework (site:spring.io OR site:baeldung.com)",
null,
null
);
Why search operators are better: - Results are filtered server-side by Brave - Doesn't waste API quota on filtered-out results - Faster response (no client-side processing) - More accurate (Brave's native filtering)
Spring Boot Integration¶
Configuration with Environment Variable¶
application.properties:
Environment variable:
Bean Configuration¶
@Configuration
public class SearchConfig {
@Bean
public BraveWebSearchTool braveWebSearchTool(
@Value("${brave.api.key}") String apiKey) {
return BraveWebSearchTool.builder(apiKey)
.resultCount(10)
.build();
}
}
ChatClient Integration¶
@Configuration
public class AgentConfig {
@Bean
public ChatClient chatClient(
ChatClient.Builder chatClientBuilder,
@Value("${brave.api.key}") String braveApiKey) {
return chatClientBuilder
.defaultTools(BraveWebSearchTool.builder(braveApiKey)
.resultCount(15)
.build())
.build();
}
}
Usage Examples¶
Example 1: Basic Web Search¶
BraveWebSearchTool searchTool = BraveWebSearchTool.builder("api-key").build();
String results = searchTool.webSearch("latest Spring AI features 2025", null, null);
// Returns JSON array of search results
Example 2: Current Events¶
// AI automatically uses current year in query
String results = searchTool.webSearch(
"Spring Framework news 2025",
null,
null
);
Example 3: Domain-Specific Research¶
// Research from official documentation only
String officialDocs = searchTool.webSearch(
"Spring AI vector stores",
List.of("spring.io", "docs.spring.io"),
null
);
// Exclude tutorial sites, focus on official sources
String research = searchTool.webSearch(
"Spring Boot 4.0 migration guide",
List.of("spring.io"),
List.of("tutorialspoint.com", "w3schools.com")
);
Example 4: Competitive Research¶
// Compare frameworks, exclude specific domains
String comparison = searchTool.webSearch(
"Spring vs Quarkus performance benchmarks",
null,
List.of("biased-site.com")
);
Example 5: Technology Stack Research¶
// Find tutorials from trusted sources
String tutorials = searchTool.webSearch(
"Spring AI LangChain4j integration tutorial",
List.of("spring.io", "github.com", "medium.com", "dev.to"),
null
);
AI Agent Integration¶
When integrated with ChatClient, AI agents can automatically search the web and cite sources:
ChatClient chatClient = chatClientBuilder
.defaultTools(BraveWebSearchTool.builder(apiKey).build())
.build();
String response = chatClient.prompt()
.user("What are the latest Spring AI features announced in 2025?")
.call()
.content();
// AI response will include search results and sources:
// "Based on recent announcements, Spring AI 2.0 includes..."
//
// Sources:
// - [Spring AI 2.0 Release Notes](https://spring.io/blog/2025/...)
// - [Spring AI Documentation](https://docs.spring.io/spring-ai/...)
Response Format¶
The tool returns a JSON array of search results:
[
{
"title": "Page Title",
"url": "https://example.com/page",
"description": "Brief description or snippet from the page"
}
]
Fields:
- title (string): The title of the web page or video
- url (string): The full URL
- description (string): Snippet or summary (may be empty for some results)
Error Handling¶
Empty Query¶
API Errors¶
// Invalid API key, network error, or API down
String results = searchTool.webSearch("query", null, null);
// Returns: "[]" (empty JSON array)
// Error logged but doesn't throw exception
Null/Invalid API Key¶
// Throws IllegalArgumentException at build time
BraveWebSearchTool searchTool = BraveWebSearchTool.builder(null).build();
// Exception: "API key must not be null or empty"
Best Practices¶
1. Use Search Operators for Filtering¶
// ✅ GOOD: Server-side filtering (efficient)
searchTool.webSearch("Spring AI site:spring.io", null, null);
// ❌ LESS EFFICIENT: Client-side filtering (wastes quota)
searchTool.webSearch("Spring AI", List.of("spring.io"), null);
2. Include Year in Queries¶
// ✅ GOOD: Specifies current year for recent info
searchTool.webSearch("React best practices 2025", null, null);
// ❌ LESS PRECISE: May return outdated results
searchTool.webSearch("React best practices", null, null);
3. Store API Key Securely¶
// ✅ GOOD: Environment variable
String apiKey = System.getenv("BRAVE_API_KEY");
// ✅ GOOD: Spring property
@Value("${brave.api.key}") String apiKey;
// ❌ BAD: Hardcoded
String apiKey = "abc123..."; // Never do this!
4. Optimize Result Count¶
// ✅ GOOD: Just enough results
BraveWebSearchTool.builder(apiKey).resultCount(10).build();
// ❌ WASTEFUL: Too many results (costs more quota)
BraveWebSearchTool.builder(apiKey).resultCount(50).build();
5. Handle Empty Results¶
String jsonResults = searchTool.webSearch("query", null, null);
if (jsonResults.equals("[]")) {
// No results found or error occurred
logger.warn("Search returned no results");
}
Advanced Usage¶
Custom Result Processing¶
BraveWebSearchTool searchTool = BraveWebSearchTool.builder(apiKey).build();
String jsonResults = searchTool.webSearch("Spring AI", null, null);
// Parse JSON and process
ObjectMapper mapper = new ObjectMapper();
List<SearchResult> results = mapper.readValue(
jsonResults,
new TypeReference<List<SearchResult>>() {}
);
for (SearchResult result : results) {
System.out.println(result.title() + ": " + result.url());
}
Combining with SmartWebFetchTool¶
BraveWebSearchTool searchTool = BraveWebSearchTool.builder(apiKey).build();
SmartWebFetchTool fetchTool = SmartWebFetchTool.builder(chatClient).build();
// 1. Search for relevant pages
String searchResults = searchTool.webSearch(
"Spring AI vector databases tutorial",
List.of("spring.io", "baeldung.com"),
null
);
// 2. Parse results
List<SearchResult> results = parseResults(searchResults);
// 3. Fetch and summarize top result
if (!results.isEmpty()) {
String url = results.get(0).url();
String summary = fetchTool.webFetch(url, "Summarize the tutorial");
System.out.println(summary);
}
Multi-Source Research¶
BraveWebSearchTool searchTool = BraveWebSearchTool.builder(apiKey)
.resultCount(20)
.build();
String[] queries = {
"Spring AI embeddings site:spring.io",
"Spring AI vector store comparison",
"Spring AI RAG implementation guide"
};
for (String query : queries) {
String results = searchTool.webSearch(query, null, null);
// Process each result set
analyzeResults(results);
}
Limitations¶
API Quota¶
- Free tier: 2,000 queries/month
- Each query counts even if results are filtered client-side
- Use search operators for efficient filtering
Geographic Availability¶
- Web search is optimized for US-based queries
- Results may vary by geographic location
- Some features may be region-specific
Client-Side Filtering¶
- Domain filtering happens after API call
- Filtered results still count against quota
- Use
site:operator for server-side filtering
Result Count Limits¶
- Maximum typically ~20 results per query
- Higher counts may not return proportionally more results
- Brave API limits may apply
No Authentication Support¶
- Results are from public web only
- Cannot access authenticated/paywalled content
- No support for API keys in search results
Troubleshooting¶
"Empty response from Brave Search API"¶
Causes: - Invalid API key - Network connectivity issues - API service down - Rate limit exceeded
Solutions:
// Verify API key is correct
String apiKey = System.getenv("BRAVE_API_KEY");
logger.info("Using API key: {}...", apiKey.substring(0, 8));
// Check API status at brave.com
Results Count Against Quota¶
Problem: Domain filtering still uses quota
Solution: Use search operators instead
// Instead of this:
searchTool.webSearch("query", List.of("example.com"), null);
// Do this:
searchTool.webSearch("query site:example.com", null, null);
No Results Returned¶
Causes: - Query too specific - All results filtered by domain rules - Brave has no indexed results
Solutions:
// Broaden the query
searchTool.webSearch("Spring Framework", null, null);
// Relax domain filters
searchTool.webSearch("query", null, null);
// Check if results exist on Brave Search directly
Rate Limit Exceeded¶
Solution: Implement rate limiting
@Component
public class RateLimitedSearchTool {
private final BraveWebSearchTool searchTool;
private final RateLimiter rateLimiter;
public RateLimitedSearchTool(BraveWebSearchTool searchTool) {
this.searchTool = searchTool;
// 2000 queries per month = ~1.5 per minute average
this.rateLimiter = RateLimiter.create(1.0);
}
public String search(String query) {
rateLimiter.acquire();
return searchTool.webSearch(query, null, null);
}
}
Security Considerations¶
API Key Protection¶
Never commit API keys to version control:
Use environment variables:
Or Spring profiles:
Input Validation¶
The tool automatically handles: - Empty queries (returns empty array) - Null domain lists (no filtering applied) - Invalid URLs in results (filtered out)
Query Sanitization¶
// Tool automatically handles special characters
String results = searchTool.webSearch(
"user input with special chars: & ? #",
null,
null
);
// URL encoding handled automatically
Performance Tips¶
Minimize API Calls¶
// ✅ GOOD: Single search with site operator
searchTool.webSearch("Spring AI site:spring.io OR site:baeldung.com", null, null);
// ❌ WASTEFUL: Multiple searches
searchTool.webSearch("Spring AI site:spring.io", null, null);
searchTool.webSearch("Spring AI site:baeldung.com", null, null);
Cache Results¶
@Component
public class CachedSearchTool {
private final BraveWebSearchTool searchTool;
private final Cache<String, String> cache;
public CachedSearchTool(BraveWebSearchTool searchTool) {
this.searchTool = searchTool;
this.cache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(15, TimeUnit.MINUTES)
.build();
}
public String search(String query) {
return cache.get(query, () -> searchTool.webSearch(query, null, null));
}
}
Optimize Result Count¶
// Start with fewer results
BraveWebSearchTool searchTool = BraveWebSearchTool.builder(apiKey)
.resultCount(5) // Only fetch what you need
.build();
Source Citation Requirements¶
CRITICAL: When using search results in AI responses, always cite sources:
// AI must include sources section
String response = """
Based on the search results, Spring AI 2.0 introduces vector store support...
Sources:
- [Spring AI Release Notes](https://spring.io/blog/2025/01/spring-ai-2.0)
- [Vector Store Documentation](https://docs.spring.io/spring-ai/reference/vectors)
""";
Required format:
- "Sources:" section at the end of response
- Each source as markdown link: [Title](URL)
- Include all relevant sources used
See Also¶
- SmartWebFetchTool - Fetch and summarize specific URLs
- FileSystemTools - File operations for storing search results
- Brave Search API Documentation - Official API reference