Web Search, X Search, and Web Fetch Tools
Learn to use web_search, x_search, and web_fetch for querying the web, X content, or fetching URLs. Configure providers and understand caching and execution details.
Read this when
- You want to enable or configure web_search
- You want to enable or configure x_search
- You need to choose a search provider
- You want to understand auto-detection and provider selection
web_search queries the web through the provider you have set up and delivers
results in a standardized format, with caching per query lasting 15 minutes
(adjustable). OpenClaw additionally includes x_search for X (formerly Twitter)
content and web_fetch for simple URL retrieval. web_fetch executes entirely on
your machine; web_search goes through xAI Responses when Grok serves as the
provider, and x_search relies on xAI Responses in all cases.
Info
web_searchfunctions as a basic HTTP tool, not a full browser. For pages heavy on JavaScript or requiring authentication, turn to the Web Browser. When you need one particular URL, opt for Web Fetch.
Quick start
Choose a provider
Choose a provider and finish any necessary configuration. Certain providers work without keys, while others demand an API key. Check the individual provider pages listed below for specifics.
Configure
openclaw configure --section web
This holds the provider along with any required credentials. For providers
backed by an API, you have the alternative of setting the provider's env
var (such as BRAVE_API_KEY) and bypassing this step.
Configuration can also happen through conversation with
OpenClaw: mention configure web search in openclaw setup
or within the Control UI's Settings → Ask OpenClaw chat. The hosted
workflow manages both provider selection and credential entry, with API
keys hidden in the browser, and the terminal chat transfers control to the
masked wizard using open search wizard.
Use it
await web_search({ query: "OpenClaw plugin SDK" });
For X posts:
await x_search({ query: "dinner recipes" });
Choosing a provider
-
Brave Search, Offers structured results with snippets. Includes
llm-contextmode and country/language filters. A free tier exists. -
Codex Hosted Search, Delivers AI-generated grounded answers via your Codex app-server account.
-
DuckDuckGo, No key required. Works without an API key. Integration is unofficial and HTML-based.
-
Exa, Combines neural and keyword search with content extraction, including highlights, text, and summaries.
-
Firecrawl, Provides structured results. Works best alongside
firecrawl_searchandfirecrawl_scrapefor thorough extraction. -
Gemini, Produces AI-generated answers with citations grounded in Google Search.
-
Grok, Produces AI-generated answers with citations grounded in xAI web search.
-
Kimi, Produces AI-generated answers with citations via Moonshot web search; ungrounded chat fallbacks fail explicitly.
-
MiniMax Search, Supplies structured results through the MiniMax Token Plan search API.
-
Ollama Web Search, Performs searches via a signed-in local Ollama host or the hosted Ollama API.
-
Parallel, Paid Parallel Search API (
PARALLEL_API_KEY); offers higher rate limits and objective tuning. -
Parallel Search (Free), Key-free opt-in. Parallel's free Search MCP, featuring LLM-optimized dense excerpts and no API key.
-
Perplexity, Gives structured results with content extraction controls and domain filtering.
-
SearXNG, Self-hosted meta-search. No API key needed. Pulls together Google, Bing, DuckDuckGo, and others.
-
Tavily, Delivers structured results with search depth, topic filtering, and
tavily_extractfor URL extraction.
Provider comparison
| Provider | Result style | Filters | API key |
|---|---|---|---|
| Brave | Structured snippets | Country, language, time, llm-context mode | BRAVE_API_KEY |
| Codex Hosted Search | AI-synthesized + source URLs | Domains, context size, user location | None; uses Codex/OpenAI sign-in |
| DuckDuckGo | Structured snippets | -- | None (key-free) |
| Exa | Structured + extracted | Neural/keyword mode, date, content extraction | EXA_API_KEY |
| Firecrawl | Structured snippets | Via firecrawl_search tool | FIRECRAWL_API_KEY |
| Gemini | AI-synthesized + citations | -- | GEMINI_API_KEY |
| Grok | AI-synthesized + citations | -- | xAI OAuth, XAI_API_KEY, or plugins.entries.xai.config.webSearch.apiKey |
| Kimi | AI-synthesized + citations; fails on ungrounded chat fallbacks | -- | KIMI_API_KEY / MOONSHOT_API_KEY |
| MiniMax Search | Structured snippets | Region (global / cn) | MINIMAX_CODE_PLAN_KEY / MINIMAX_CODING_API_KEY / MINIMAX_OAUTH_TOKEN |
| Ollama Web Search | Structured snippets | -- | None for signed-in local hosts; OLLAMA_API_KEY for direct https://ollama.com search |
| Parallel | Dense excerpts ranked for LLM context | -- | PARALLEL_API_KEY (paid) |
| Parallel Search (Free) | Dense excerpts ranked for LLM context | -- | None (free Search MCP) |
| Perplexity | Structured snippets | Country, language, time, domains, content limits | PERPLEXITY_API_KEY / OPENROUTER_API_KEY |
| SearXNG | Structured snippets | Categories, language | None (self-hosted) |
| Tavily | Structured snippets | Via tavily_search tool | TAVILY_API_KEY |
Result shape
At the core tool boundary, web_search standardizes every bundled and external plugin provider. Whatever the source, callers get one of these fixed shapes:
type WebSearchOutput =
| {
kind: "error";
provider: string;
error: "provider_error";
message: string;
docs?: string;
}
| {
kind: "results";
provider: string;
query: string;
count: number;
tookMs?: number;
results: Array<{
title: string;
url: string;
snippet?: string;
published?: string;
siteName?: string;
}>;
externalContent: {
untrusted: true;
source: "web_search";
wrapped: true;
provider: string;
};
cached?: true;
}
| {
kind: "answer";
provider: string;
query: string;
tookMs?: number;
content: string;
citations?: Array<{ url: string; title?: string }>;
externalContent: {
untrusted: true;
source: "web_search";
wrapped: true;
provider: string;
};
cached?: true;
}
| {
kind: "raw";
provider: string;
data: unknown;
};
For structured providers, kind: "results" applies; for synthesized ones, kind: "answer" is used. External plugin providers whose payloads fit neither shape are forwarded unchanged as kind: "raw" to preserve compatibility. Fields specific to a provider, such as raw scores, excerpts, related searches, inline-citation offsets, model ids, or session metadata, are not carried over on normalized branches. When a provider's richer response matters to your workflow, reach for that provider's dedicated tool instead.
The boundary itself guarantees externalContent.wrapped: true as a trust marker: provider prose (title, snippet, siteName, content, citation titles, error message) has any pre-existing envelope lines removed and is re-wrapped exactly once at the core boundary, so no provider metadata can forge the marker. query always holds the requested query, citation and result URLs must parse as http(s), published must follow ISO-date shape, URLs are emitted canonicalized, and a payload containing an error key is always flagged as kind: "error", with the raw provider code kept inside the wrapped message. Raw passthrough payloads retain whatever markers the provider set.
For Perplexity, Tavily, and xAI HTTP errors, the status code and bounded diagnostics are preserved, while reflected request credentials are redacted. Before sharing diagnostics, review them; redaction does not eliminate every type of sensitive content.
Auto-detection
In docs and setup flows, provider lists appear alphabetically. Auto-detection follows a separate, fixed precedence order and only selects a provider that requires a credential (requiresCredential !== false) when one is found configured. If no provider is set, OpenClaw evaluates providers in this sequence and picks the first one that is ready:
API-backed providers come first:
- Brave --
BRAVE_API_KEYorplugins.entries.brave.config.webSearch.apiKey(order 10) - MiniMax Search --
MINIMAX_CODE_PLAN_KEY/MINIMAX_CODING_API_KEY/MINIMAX_OAUTH_TOKEN/MINIMAX_API_KEYorplugins.entries.minimax.config.webSearch.apiKey(order 15) - Gemini --
plugins.entries.google.config.webSearch.apiKey,GEMINI_API_KEY, ormodels.providers.google.apiKey(order 20) - Grok -- xAI OAuth,
XAI_API_KEY, orplugins.entries.xai.config.webSearch.apiKey(order 30) - Kimi --
KIMI_API_KEY/MOONSHOT_API_KEYorplugins.entries.moonshot.config.webSearch.apiKey(order 40) - Perplexity --
PERPLEXITY_API_KEY/OPENROUTER_API_KEYorplugins.entries.perplexity.config.webSearch.apiKey(order 50) - Firecrawl --
FIRECRAWL_API_KEYorplugins.entries.firecrawl.config.webSearch.apiKey(order 60) - Exa --
EXA_API_KEYorplugins.entries.exa.config.webSearch.apiKey; optionalplugins.entries.exa.config.webSearch.baseUrloverrides the Exa endpoint (order 65) - Tavily --
TAVILY_API_KEYorplugins.entries.tavily.config.webSearch.apiKey(order 70) - Parallel -- paid Parallel Search API via
PARALLEL_API_KEYorplugins.entries.parallel.config.webSearch.apiKey; optionalplugins.entries.parallel.config.webSearch.baseUrloverrides the endpoint (order 75)
Following those, endpoint-configured providers:
- SearXNG --
SEARXNG_BASE_URLorplugins.entries.searxng.config.webSearch.baseUrl(order 200)
Providers without keys, such as Parallel Search (Free), DuckDuckGo,
Ollama Web Search, and Codex Hosted Search, never win auto-detection
despite carrying an internal order value. They activate only when chosen
explicitly via tools.web.search.provider or with
openclaw configure --section web. OpenClaw will not route managed
web_search queries to a key-free provider solely because no API-backed
provider is set up.
OpenAI Responses models break the pattern: while tools.web.search.provider
remains empty, they rely on OpenAI's built-in web search rather than the managed
providers listed above (details below). Assign tools.web.search.provider to
parallel-free (or any other provider) to send them through the managed
route instead.
Note
SecretRef objects are accepted in every provider key field. Plugin-scoped SecretRefs under
plugins.entries.<plugin>.config.webSearch.apiKeyget resolved for the installed API-backed web search providers, covering Brave, Exa, Firecrawl, Gemini, Grok, Kimi, MiniMax, Parallel, Perplexity, and Tavily, regardless of whether the provider is chosen explicitly viatools.web.search.provideror picked through auto-detection. In auto-detect mode, OpenClaw resolves only the selected provider's key, leaving non-selected SecretRefs dormant, so multiple providers can stay configured without incurring resolution overhead for unused ones.
Native OpenAI web search
When OpenClaw web search is enabled and no managed provider is pinned, direct
OpenAI Responses models (api: "openai-responses", provider openai,
no base URL or an official OpenAI API base URL) automatically use OpenAI's
hosted web_search tool. This behavior belongs to the bundled
OpenAI plugin and does not extend to OpenAI-compatible proxy base URLs or Azure
routes. To keep the managed web_search tool for OpenAI models, set
tools.web.search.provider to another provider such as brave; alternatively, set
tools.web.search.enabled: false to turn off both managed search and native
OpenAI search.
Native Codex web search
With web search enabled and no managed provider chosen, the Codex app-server
runtime automatically relies on Codex's hosted web_search tool. Native hosted
search and OpenClaw's managed web_search dynamic tool cannot coexist, so
managed search has no way around native domain restrictions. OpenClaw falls
back to the managed tool when hosted search is unavailable, explicitly
disabled, or replaced by a selected managed provider. Codex's standalone
web.run extension stays disabled (features.standalone_web_search: false)
because production app-server traffic rejects its user-defined web
namespace.
- Configure native search through
tools.web.search.openaiCodex - Assign
tools.web.search.provider: "codex"to enable Codex Hosted Search as the managedweb_searchprovider for any parent model. Every call triggers a limited, short-lived Codex app-server turn and errors out if Codex fails to return a hostedwebSearchitem. mode: "cached"serves as the default setting, but Codex converts it to live external access for unrestricted app-server turns; set"live"to explicitly request live access- Point
tools.web.search.providerat a managed provider likebraveto rely on OpenClaw's managedweb_searchinstead - Configure
tools.web.search.openaiCodex.enabled: falseto disable Codex-hosted search; other managed providers stay accessible - Limiting the Codex native tool surface also preserves managed
web_searchavailability - When
allowedDomainsis enabled, it constrains both hostedweb_searchand managedweb_fetchon turns where native hosted search is active. Turns that use a managed search provider remain unaffected. Automatic managed search fallback also fails closed if hosted search becomes unavailable. - Tool-disabled LLM-only runs turn off both native and managed search
tools.web.search.enabled: falsedeactivates managed and native search alike
Persistent effective Codex search-policy modifications launch a new bound thread, preventing an already loaded app-server thread from holding onto outdated hosted-search access. Transient per-turn constraints rely on a temporary restricted thread and keep the current binding intact for later resumption.
Direct OpenAI ChatGPT Responses traffic can also tap into OpenAI's hosted web_search tool. That separate route stays opt-in through tools.web.search.openaiCodex.enabled: true and applies only to compatible openai/* models using api: "openai-chatgpt-responses".
{
tools: {
web: {
search: {
enabled: true,
// Optional: use Codex Hosted Search from non-Codex parent models too.
provider: "codex",
openaiCodex: {
enabled: true,
mode: "cached",
allowedDomains: ["example.com"],
contextSize: "high",
userLocation: {
country: "US",
city: "New York",
timezone: "America/New_York",
},
},
},
},
},
}
For runtimes and providers lacking native Codex search support, Codex can fall back to the managed web_search option via OpenClaw's dynamic tool namespace. Choose an explicit managed provider when you require OpenClaw's provider-specific network controls over Codex-hosted search.
Picking provider: "codex" activates the bundled codex plugin and applies the same tools.web.search.openaiCodex restrictions described earlier. Authenticate the Codex app-server first with openclaw models auth login --provider openai. The parent agent can run on any model or runtime; only the bounded search worker executes through Codex.
Network safety
Managed HTTP web_search provider calls follow OpenClaw's guarded fetch path, limited to the current provider's own hostname. For that hostname only, OpenClaw permits Surge, Clash, and sing-box fake-IP DNS responses in 198.18.0.0/15 and fc00::/7. Other private, loopback, link-local, and metadata destinations stay blocked. Codex Hosted Search stands apart: its bounded worker hands network access to the Codex app-server's hosted web_search tool.
This automatic allowance does not extend to arbitrary web_fetch URLs. For web_fetch, turn on tools.web.fetch.ssrfPolicy.allowRfc2544BenchmarkRange and tools.web.fetch.ssrfPolicy.allowIpv6UniqueLocalRange explicitly only when your trusted proxy owns those synthetic ranges.
Config
{
tools: {
web: {
search: {
enabled: true, // default: true
provider: "brave", // or omit for auto-detection
maxResults: 5,
timeoutSeconds: 30,
cacheTtlMinutes: 15,
},
},
},
}
tools.web.search.cacheTtlMinutes governs OpenClaw's local search-result caches. Set it to 0 to skip reads and writes, even for queries already cached. A shorter positive TTL limits reuse by entry age; a longer TTL does not stretch an entry's original expiry. Provider-side caching operates independently.
Provider-specific settings (API keys, base URLs, modes) sit under plugins.entries.<plugin>.config.webSearch.*. Gemini can also reuse models.providers.google.apiKey and models.providers.google.baseUrl as lower-priority fallbacks after its dedicated web-search config and GEMINI_API_KEY. Check the provider pages for examples. Grok can also reuse an xAI OAuth auth profile from openclaw models auth login --provider xai --method oauth; API-key config remains the fallback.
tools.web.search.provider gets checked against the web-search provider ids declared by bundled and installed plugin manifests. A typo like "brvae" fails config validation rather than silently dropping to auto-detection. If a configured provider only has stale plugin evidence, such as a leftover plugins.entries.<plugin> block after uninstalling a third-party plugin, OpenClaw keeps startup resilient and emits a warning so you can reinstall the plugin or run openclaw doctor --fix to clear the stale config.
web_fetch fallback provider selection works separately:
- pick it with
tools.web.fetch.provider - or leave that field empty and let OpenClaw auto-detect the first ready web-fetch provider from configured credentials
- non-sandboxed
web_fetchcan use installed plugin providers that declarecontracts.webFetchProviders; sandboxed fetches allow bundled providers and verified official plugin installs, but exclude third-party external plugins - the official Firecrawl plugin is the only bundled
webFetchProviderscontributor today, configured underplugins.entries.firecrawl.config.webFetch.*
When you pick Kimi during openclaw onboard or openclaw configure --section web, OpenClaw can also request:
- the Moonshot API region (
https://api.moonshot.ai/v1orhttps://api.moonshot.cn/v1) - the default Kimi web-search model (defaults to
kimi-k2.6)
For x_search, set plugins.entries.xai.config.xSearch.*. The same xAI auth profile used for chat applies here, or you can use the XAI_API_KEY / plugin web-search credential that Grok web search relies on.
openclaw doctor --fix automatically migrates legacy tools.web.x_search.* configuration.
When you pick Grok during openclaw onboard or openclaw configure --section web, OpenClaw additionally offers optional x_search setup with the same credential immediately after Grok setup finishes. That follow-up step lives inside the Grok path itself, not as a separate top-level web-search provider option. Choosing any other provider means OpenClaw skips the x_search prompt entirely.
Storing API keys
Config file
Execute openclaw configure --section web or assign the key directly:
{
plugins: {
entries: {
brave: {
config: {
webSearch: {
apiKey: "YOUR_KEY", // pragma: allowlist secret
},
},
},
},
},
}
Environment variable
In the Gateway process environment, set the provider env var:
export BRAVE_API_KEY="YOUR_KEY"
For a gateway install, place it in ~/.openclaw/.env.
Check Env vars.
Tool parameters
| Parameter | Description |
|---|---|
query | Search query (required) |
count | Results to return (1-10, default: 5) |
country | 2-letter ISO country code (e.g. "US", "DE") |
language | ISO 639-1 language code (e.g. "en", "de") |
search_lang | Search-language code (Brave only) |
freshness | Time filter: day, week, month, or year |
date_after | Results after this date (YYYY-MM-DD) |
date_before | Results before this date (YYYY-MM-DD) |
ui_lang | UI language code (Brave only) |
domain_filter | Domain allowlist/denylist array (Perplexity only) |
max_tokens | Total content token budget, native Perplexity Search API only |
max_tokens_per_page | Per-page extraction token limit, native Perplexity Search API only |
Warning
Provider support varies across parameters. Brave's
llm-contextmode rejectsui_lang;date_beforelikewise requiresdate_after, since Brave custom freshness ranges demand both start and end dates. Gemini, Grok, and Kimi each return a single synthesized answer with citations. They acceptcountfor shared-tool compatibility, yet it does not alter the grounded answer format. For Gemini,dayfreshness acts as a recency hint; wider freshness values and explicit dates set Google Search grounding time ranges. Perplexity follows the same pattern through the Sonar/OpenRouter compatibility path (plugins.entries.perplexity.config.webSearch.baseUrl/modelorOPENROUTER_API_KEY); that route also dropsmax_tokensandmax_tokens_per_pagesupport. SearXNG acceptshttp://only for trusted private-network or loopback hosts; public SearXNG endpoints must rely onhttps://. Firecrawl and Tavily support onlyqueryandcountviaweb_search, so advanced options require their dedicated tools.
x_search
x_search searches X (formerly Twitter) posts through xAI and delivers AI-synthesized answers with citations. Natural-language queries and optional structured filters are both accepted. Rather than keeping it permanently registered, OpenClaw builds the built-in xAI x_search tool per request, so it stays active only for the turn that invokes it.
Warning
x_searchexecutes on xAI's servers. xAI charges $5 per 1,000 tool calls, plus the model's input and output tokens.
Note
According to xAI documentation,
x_searchsupports keyword search, semantic search, user search, and thread fetch. For per-post engagement stats like reposts, replies, bookmarks, or views, a targeted lookup for the exact post URL or status ID works better. Broad keyword searches may locate the right post but yield less complete per-post metadata. A solid approach: find the post first, then issue a secondx_searchquery aimed at that specific post.
x_search config
When enabled is not provided, x_search appears only if the active model's provider happens to be xai and xAI credentials are available. If the active model uses a recognized provider other than xAI, you can enable cross-provider usage by setting plugins.entries.xai.config.xSearch.enabled to true. Should the provider for the active model be absent or fail to resolve, the tool remains hidden. Setting enabled to false turns it off across all providers. xAI credentials are mandatory in every case.
{
plugins: {
entries: {
xai: {
config: {
xSearch: {
enabled: true, // required for a known non-xAI model provider
model: "grok-4.3",
baseUrl: "https://api.x.ai/v1", // optional, overrides webSearch.baseUrl
inlineCitations: false,
maxTurns: 2,
timeoutSeconds: 30,
cacheTtlMinutes: 15,
},
webSearch: {
apiKey: "xai-...", // optional if an xAI auth profile or XAI_API_KEY is set
baseUrl: "https://api.x.ai/v1", // optional shared xAI Responses base URL
},
},
},
},
},
}
With plugins.entries.xai.config.xSearch.baseUrl in place, x_search sends requests to <baseUrl>/responses. When that field is absent, the destination defaults to plugins.entries.xai.config.webSearch.baseUrl, and then to the public xAI endpoint at https://api.x.ai/v1.
plugins.entries.xai.config.xSearch.cacheTtlMinutes governs OpenClaw's local x_search result cache. Assigning it 0 disables both reading from and writing to the cache. A reduced TTL curbs how often existing entries get reused, while a longer TTL never stretches their original expiration.
x_search parameters
| Parameter | Description |
|---|---|
query | Search query (required) |
allowed_x_handles | Cap results to no more than 20 X handles |
excluded_x_handles | Omit up to 20 X handles |
from_date | Include only posts dated on or after this date (YYYY-MM-DD) |
to_date | Include only posts dated on or before this date (YYYY-MM-DD) |
enable_image_understanding | Allow xAI to examine images attached to relevant posts |
enable_video_understanding | Allow xAI to examine videos attached to relevant posts |
allowed_x_handles and excluded_x_handles cannot be used together.
x_search example
await x_search({
query: "dinner recipes",
allowed_x_handles: ["nytfood"],
from_date: "2026-03-01",
});
// Per-post stats: use the exact status URL or status ID when possible
await x_search({
query: "https://x.com/huntharo/status/1905678901234567890",
});
Examples
// Basic search
await web_search({ query: "OpenClaw plugin SDK" });
// German-specific search
await web_search({ query: "TV online schauen", country: "DE", language: "de" });
// Recent results (past week)
await web_search({ query: "AI developments", freshness: "week" });
// Date range
await web_search({
query: "climate research",
date_after: "2024-01-01",
date_before: "2024-06-30",
});
// Domain filtering (Perplexity only)
await web_search({
query: "product reviews",
domain_filter: ["-reddit.com", "-pinterest.com"],
});
Tool profiles
When working with tool profiles or allowlists, include web_search, x_search, or group:web:
{
tools: {
allow: ["web_search", "x_search"],
// or: allow: ["group:web"] (includes web_search, x_search, and web_fetch)
},
}
Related
- Web Fetch -- retrieve a URL and pull out readable content
- Web Browser -- complete browser automation for sites heavy on JavaScript
- Grok Search -- Grok serving as the
web_searchprovider - Ollama Web Search -- web search with no API key via your Ollama host