Skip to content

How to Use Exa, Tavily, and Firecrawl in OpenClaw

Problem

When I built research agents in OpenClaw, I had to manually install and configure web search plugins. Each plugin had different APIs, configuration formats, and dependency issues. The setup was painful.

OpenClaw 2026.3.22-beta.1 solved this by bundling Exa, Tavily, and Firecrawl as first-class plugins. But now I faced a different question: which of these three should I use, and when?

This post shows how to use OpenClaw’s bundled web search plugins. The key point is matching each plugin to its strength.

What Changed in OpenClaw 2026.3.22-beta.1

The release notes said:

“Exa added with native date filters, search-mode selection, and optional content extraction.” “Tavily added with dedicated tavily_search and tavily_extract tools.” “Firecrawl added with firecrawl_search and firecrawl_scrape tools.”

This means three serious web-search options are now bundled and first-class. No manual plugin install required - they work out of the box. Each has its own config namespace so I can run them alongside each other.

Research agents just got more capable out of the box.

When to Use Each Plugin

After testing all three, I found each excels at different tasks:

PluginBest ForKey Feature
ExaSemantic search with recencyNative date filtering
TavilyStructured data extractionClean JSON output
FirecrawlFull page scrapingJavaScript rendering

Let me show you how I use each one.

Exa: Semantic Search with Date Filters

I use Exa when I need AI-native search that understands meaning, not just keywords. Its date filtering is unique among the three.

When I Use Exa

  • Finding recent articles (last 7 days, last month)
  • Semantic research where keyword search fails
  • Finding related content through meaning
  • Agentic research loops where search quality matters

Configuration

~/.openclaw/config.yaml
plugins:
exa:
apiKey: "your-exa-api-key"
defaultSearchMode: "auto" # auto | keyword | neural
defaultNumResults: 10
exa-basic.ts
// Exa search with semantic understanding
const results = await exa.search({
query: "latest developments in AI agent frameworks",
numResults: 10,
useAutoprompt: true
})
// Results are ranked by semantic relevance, not just keyword match
results.results.forEach(result => {
console.log(result.title)
console.log(result.url)
console.log(result.score) // Relevance score
})

I use this feature constantly for news and recent developments:

exa-date-filter.ts
// Find articles from last 7 days
const lastWeek = new Date()
lastWeek.setDate(lastWeek.getDate() - 7)
const recentResults = await exa.search({
query: "OpenClaw release updates",
numResults: 5,
startPublishedDate: lastWeek.toISOString(),
endPublishedDate: new Date().toISOString()
})

Search with Content Extraction

exa-extract.ts
// Search and extract full content in one call
const searchWithContent = await exa.search({
query: "LangGraph tutorial",
numResults: 5,
contents: {
text: { maxCharacters: 1000 },
highlights: { numSentences: 3 }
}
})
// Each result now includes extracted text
searchWithContent.results.forEach(result => {
console.log(result.text) // Extracted content
console.log(result.highlights) // Key highlights
})

Tavily: Structured Data Extraction

I use Tavily when I need clean, structured data from web searches. Its output is optimized for agent consumption.

When I Use Tavily

  • Building knowledge bases from web content
  • Extracting specific data points from multiple pages
  • Research agents that need structured input
  • Follow-up extraction after initial discovery

Configuration

~/.openclaw/config.yaml
plugins:
tavily:
apiKey: "your-tavily-api-key"
includeRawContent: false
maxResults: 5

Basic Search with AI Answer

tavily-basic.ts
// Tavily search with structured output
const results = await tavily.search({
query: "best practices for MCP server development",
maxResults: 5,
includeAnswer: true // Get AI-generated answer
})
console.log(results.answer) // AI-generated summary
console.log(results.results) // Structured results

Extract Structured Data from URLs

tavily-extract.ts
// Extract from specific URLs
const extracted = await tavily.extract({
urls: [
"https://docs.openclaw.ai/plugins/overview",
"https://docs.openclaw.ai/mcp/integration"
],
extractDepth: "advanced" // basic | advanced
})
// Get structured data from each URL
extracted.forEach(page => {
console.log(page.url)
console.log(page.rawContent) // Cleaned content
console.log(page.metadata) // Page metadata
})

Search Specific Domains

tavily-domains.ts
// I use this for documentation-only searches
const domainResults = await tavily.search({
query: "agent orchestration patterns",
maxResults: 10,
includeDomains: ["docs.anthropic.com", "python.langchain.com"]
})

Firecrawl: Full Page Scraping

I use Firecrawl when I need complete page content, especially for JavaScript-rendered pages or documentation ingestion.

When I Use Firecrawl

  • Documentation ingestion
  • Full article/blog content extraction
  • Pages requiring JavaScript rendering
  • Converting web content to LLM-friendly format

Configuration

~/.openclaw/config.yaml
plugins:
firecrawl:
apiKey: "your-firecrawl-api-key"
formats: ["markdown"]
waitForEvent: "load"

Full Page Scrape

firecrawl-scrape.ts
// Scrape a single page with markdown output
const page = await firecrawl.scrape({
url: "https://docs.openclaw.ai/getting-started",
formats: ["markdown", "html"]
})
console.log(page.markdown) // LLM-friendly markdown
console.log(page.html) // Original HTML
console.log(page.metadata) // Page metadata

Search and Scrape Combined

firecrawl-search.ts
// Search and get full content in one call
const results = await firecrawl.search({
query: "OpenClaw browser automation guide",
limit: 5
})
// Each result includes full scraped content
results.forEach(result => {
console.log(result.markdown) // Full content
})

Handle JavaScript-Rendered Pages

This is Firecrawl’s superpower - it handles dynamic content:

firecrawl-dynamic.ts
// Scrape JavaScript-rendered pages
const dynamicPage = await firecrawl.scrape({
url: "https://example.com/spa-page",
formats: ["markdown"],
waitFor: 2000, // Wait 2 seconds for JS to render
actions: [
{ type: "scroll", direction: "down" }
]
})
// Get content that would be invisible to simple scrapers
console.log(dynamicPage.markdown)

Combining Plugins in a Research Agent

The real power comes from chaining these plugins together. Here’s how I built a research agent:

research-agent.ts
async function researchTopic(topic: string) {
// 1. Use Exa for semantic discovery with recency
const discoveries = await exa.search({
query: topic,
numResults: 10,
startPublishedDate: getLastWeekISOString(),
useAutoprompt: true
})
// 2. Use Tavily for structured extraction from top results
const topUrls = discoveries.results.slice(0, 3).map(r => r.url)
const structured = await tavily.extract({
urls: topUrls,
extractDepth: "advanced"
})
// 3. Use Firecrawl for full content if needed
if (needsFullContent(structured)) {
const fullContent = await firecrawl.scrape({
url: topUrls[0],
formats: ["markdown"]
})
return { discoveries, structured, fullContent }
}
return { discoveries, structured }
}
function getLastWeekISOString(): string {
const date = new Date()
date.setDate(date.getDate() - 7)
return date.toISOString()
}
function needsFullContent(structured: any): boolean {
// Check if we need more detail
return structured.some(page => page.rawContent.length < 500)
}

Common Mistakes

Mistake 1: Using One Plugin for Everything

Each plugin is optimized for different tasks. Don’t force Firecrawl to do semantic search, or Exa to do full-page scraping. Match the tool to the job.

// WRONG: Using Firecrawl for semantic search
const results = await firecrawl.search({
query: "AI agent frameworks",
limit: 10
})
// Firecrawl's search is basic, not semantic
// CORRECT: Use Exa for semantic search
const results = await exa.search({
query: "AI agent frameworks",
numResults: 10,
useAutoprompt: true
})

Mistake 2: Ignoring API Keys

While bundled, each plugin still requires its own API key:

# WRONG: Missing API keys
plugins:
exa:
defaultSearchMode: "auto"
# No apiKey - will fail
# CORRECT: Configure keys
plugins:
exa:
apiKey: "your-exa-api-key"
defaultSearchMode: "auto"

Mistake 3: Not Chaining Tools

The power comes from combining plugins:

// WRONG: Using only one tool
const results = await exa.search({ query: topic })
// CORRECT: Chain tools for better results
const discoveries = await exa.search({ query: topic })
const structured = await tavily.extract({
urls: discoveries.results.map(r => r.url)
})

Mistake 4: Overlooking Date Filters in Exa

Exa’s date filtering is unique among the three:

// WRONG: Ignoring date filters
const results = await exa.search({
query: "OpenClaw updates"
})
// Gets old, potentially outdated results
// CORRECT: Use date filters for recent content
const lastMonth = new Date()
lastMonth.setMonth(lastMonth.getMonth() - 1)
const results = await exa.search({
query: "OpenClaw updates",
startPublishedDate: lastMonth.toISOString()
})

Mistake 5: Forgetting Rate Limits

Each service has its own rate limits:

// WRONG: No rate limiting
for (const url of urls) {
await firecrawl.scrape({ url })
}
// CORRECT: Add delays
for (const url of urls) {
await firecrawl.scrape({ url })
await sleep(1000) // Respect rate limits
}

Plugin Comparison

Here’s my quick reference for choosing:

FeatureExaTavilyFirecrawl
Primary UseSemantic searchStructured extractionFull scraping
Search QualityAI-native, semanticKeyword-basedBasic search
Date FilteringYes (unique)NoNo
Content DepthOptional extractionStructured dataFull markdown
JS RenderingNoLimitedYes
Rate LimitsPer API planPer API planPer API plan
Best ForResearch discoveryData extractionDocumentation

Summary

In this post, I showed how to use OpenClaw’s bundled web search plugins. The key point is matching each plugin to its strength:

  • Use Exa when you need semantic search with date filtering - ideal for finding recent, relevant content
  • Use Tavily when you need structured, clean data extraction - ideal for building knowledge bases
  • Use Firecrawl when you need complete page content - ideal for documentation ingestion and JS-rendered pages

All three can be configured independently and used together in research workflows. Configure your API keys, understand each plugin’s strengths, and chain them together for powerful research agents.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments