> ## Documentation Index > Fetch the complete documentation index at: https://openrouter.ai/docs/llms.txt > Use this file to discover all available pages before exploring further. # Web Search > Model-agnostic grounding **Try Web Search Server Tool** For improved quality results, try the [`openrouter:web_search` server tool](/docs/guides/features/server-tools/web-search). Server tools give the model control over when and how often to search, rather than always running once per request. You can incorporate relevant web search results for *any* model on OpenRouter by activating and customizing the `web` plugin, or by appending `:online` to the model slug: ```json lines theme={null} { "model": "openai/gpt-5.2:online" } ``` You can also append `:online` to `:free` model variants like so: ```json lines theme={null} { "model": "openai/gpt-oss-20b:free:online" } ``` Using web search will incur extra costs, even with free models. See the [pricing section](#pricing) below for details. `:online` is a shortcut for using the `web` plugin, and is exactly equivalent to: ```json lines theme={null} { "model": "openrouter/auto", "plugins": [{ "id": "web" }] } ``` The web search plugin is powered by native search for Anthropic, Google, OpenAI, Perplexity, and SpaceXAI models. See the [server tools web search docs](/docs/guides/features/server-tools/web-search#native-search-providers) for the full list of supported model families per provider. For SpaceXAI models, the web search plugin enables both Web Search and X Search. For other models, the web search plugin is powered by [Exa](https://exa.ai). It uses their ["auto"](https://docs.exa.ai/reference/how-exa-search-works#combining-neural-and-keyword-the-best-of-both-worlds-through-exa-auto-search) method (a combination of keyword search and embeddings-based web search) to find the most relevant results and augment/ground your prompt. For each result, OpenRouter requests Exa [highlights](https://docs.exa.ai/reference/contents-retrieval-with-exa-api#highlights) — extractive excerpts drawn from the page that Exa selects as most relevant to the search query, sized adaptively (typically \~2,000–4,000 characters per result). These are returned to the model and surfaced via `url_citation` annotations, with Exa's `[...]` markers separating excerpts that come from different parts of the same page. ## Parsing web search results Web search results for all models (including native-only models like Perplexity and OpenAI Online) are available in the API and standardized by OpenRouter to follow the same annotation schema in the [OpenAI Chat Completion Message type](https://platform.openai.com/docs/api-reference/chat/object): ```json lines theme={null} { "message": { "role": "assistant", "content": "Here's the latest news I found: ...", "annotations": [ { "type": "url_citation", "url_citation": { "url": "https://www.example.com/web-search-result", "title": "Title of the web search result", "content": "Content of the web search result", // Added by OpenRouter if available "start_index": 100, // The index of the first character of the URL citation in the message. "end_index": 200 // The index of the last character of the URL citation in the message. } } ] } } ``` ## Customizing the Web Plugin The maximum results allowed by the web plugin and the prompt used to attach them to your message stream can be customized: ```json lines theme={null} { "model": "openai/gpt-5.2:online", "plugins": [ { "id": "web", "engine": "parallel", // Optional: "native", "exa", "firecrawl", "parallel", "perplexity", or undefined "mode": "turbo", // Optional; accepted values depend on the selected engine "max_results": 1, // Defaults to 5 "search_prompt": "Some relevant web results:", // See default below "include_domains": ["example.com", "*.substack.com"], // Optional "exclude_domains": ["reddit.com"] // Optional } ] } ``` By default, the web plugin uses the following search prompt, using the current date: ```lines theme={null} A web search was conducted on `date`. Incorporate the following web search results into your response. IMPORTANT: Cite them using markdown links named using the domain of the source. Example: [nytimes.com](https://nytimes.com/some-page). ``` ## Domain Filtering You can restrict which domains appear in web search results using `include_domains` and `exclude_domains`: ```json lines theme={null} { "model": "openai/gpt-5.2", "plugins": [ { "id": "web", "include_domains": ["example.com", "*.substack.com"], "exclude_domains": ["reddit.com"] } ] } ``` Both fields accept an array of domain strings. You can use wildcards (`*.substack.com`) and path filtering (`openai.com/blog`). ### Engine Compatibility | Engine | `include_domains` | `exclude_domains` | Notes | | -------------- | :---------------: | :---------------: | --------------------------------------------------------------- | | **Exa** | Yes | Yes | Both can be used simultaneously | | **Parallel** | Yes | Yes | Either can be used, they are mutually exclusive | | **Perplexity** | Yes | Yes | Mutually exclusive (when both provided, `include_domains` wins) | | **Native** | Varies | Varies | See provider notes below | | **Firecrawl** | Yes | Yes | Mutually exclusive (cannot use both at once) | ### Native Provider Behavior When using native search, domain filter support depends on the provider: * **Anthropic**: Supports both `include_domains` and `exclude_domains`, but they are mutually exclusive — you cannot use both at once * **Google**: Domain filtering is not supported. With the default engine (auto), OpenRouter falls back to Exa when filters are set. With `"engine": "native"`, returns a 400 error * **OpenAI**: Supports `include_domains` only; `exclude_domains` is silently ignored * **SpaceXAI**: Supports both, but they are mutually exclusive with a maximum of 5 domains each ## X Search Filters (SpaceXAI only) When using SpaceXAI models with web search enabled, OpenRouter automatically adds the `x_search` tool alongside `web_search`. You can pass filter parameters to control X/Twitter search results using the top-level `x_search_filter` parameter: ```json lines theme={null} { "model": "x-ai/grok-4.1-fast", "messages": [ { "role": "user", "content": "What are people saying about OpenRouter?" } ], "plugins": [{ "id": "web" }], "x_search_filter": { "allowed_x_handles": ["OpenRouterAI"], "from_date": "2025-01-01", "to_date": "2025-12-31" } } ``` ### Filter Parameters | Parameter | Type | Description | | ---------------------------- | --------- | ----------------------------------------------------------- | | `allowed_x_handles` | string\[] | Only include posts from these handles (max 20) | | `excluded_x_handles` | string\[] | Exclude posts from these handles (max 20) | | `from_date` | string | Start date for search range (ISO 8601, e.g. `"2025-01-01"`) | | `to_date` | string | End date for search range (ISO 8601, e.g. `"2025-12-31"`) | | `enable_image_understanding` | boolean | Enable analysis of images within posts | | `enable_video_understanding` | boolean | Enable analysis of videos within posts | `allowed_x_handles` and `excluded_x_handles` are mutually exclusive — you cannot use both in the same request. If validation fails, the filter is silently dropped and a basic `x_search` tool is used instead. ## Engine Selection The web search plugin supports the following options for the `engine` parameter: * **`native`**: Always uses the model provider's built-in web search capabilities * **`exa`**: Uses Exa's search API for web results * **`firecrawl`**: Uses [Firecrawl](https://firecrawl.dev)'s search API * **`parallel`**: Uses [Parallel](https://parallel.ai)'s search API for web results * **`perplexity`**: Uses the [Perplexity](https://docs.perplexity.ai/api-reference/search-post) Search API for ranked web results * **`undefined` (not specified)**: Uses native search if available for the provider, otherwise falls back to Exa ### Default Behavior When the `engine` parameter is not specified: * **Native search is used by default** for OpenAI, Anthropic, Google, Perplexity, and SpaceXAI models that support it * **Exa search is used** for all other models or when native search is not supported When you explicitly specify `"engine": "native"`, it will always attempt to use the provider's native search, even if the model doesn't support it (which may result in an error). ### Forcing Engine Selection You can explicitly specify which engine to use: ```json lines theme={null} { "model": "openai/gpt-5.2", "plugins": [ { "id": "web", "engine": "native" } ] } ``` Or force Exa search even for models that support native search: ```json lines theme={null} { "model": "openai/gpt-5.2", "plugins": [ { "id": "web", "engine": "exa", "max_results": 3 } ] } ``` ### Firecrawl Firecrawl is a BYOK (bring your own key) search engine. To use it: 1. Go to your [OpenRouter plugin settings](https://openrouter.ai/settings/plugins) and select Firecrawl as the web search engine 2. Accept the [Firecrawl Terms of Service](https://www.firecrawl.dev/terms-of-service) — this automatically creates a Firecrawl account linked to your email 3. Your account starts with **10,000 free credits** (credits expire after 3 months) Once set up, Firecrawl searches use your Firecrawl credits directly — there is no additional charge from OpenRouter. Each search costs 2 credits per 10 results, plus 5 credits per result scraped (1 base scrape + 4 for [highlights extraction](https://docs.firecrawl.dev/features/scrape#output-formats)). See [Firecrawl pricing](https://www.firecrawl.dev/pricing) for details. ```json lines theme={null} { "model": "openai/gpt-5.2", "plugins": [ { "id": "web", "engine": "firecrawl", "max_results": 5 } ] } ``` Firecrawl supports `include_domains` and `exclude_domains`, but they are mutually exclusive — you cannot use both in the same request. ### Parallel [Parallel](https://parallel.ai) is a search engine that supports domain filtering. Set `mode` when `engine` is `parallel`. OpenRouter uses `basic` by default and sends the resolved mode explicitly. | Mode | Latency | Request cost | Language availability | | ----------------- | ----------- | ---------------------- | -------------------------- | | `turbo` | \~200 ms | \$1 per 1,000 requests | English and Japanese | | `fast` | \~550 ms | \$1 per 1,000 requests | Not documented by Parallel | | `basic` (default) | \~1 second | \$5 per 1,000 requests | Broad language support | | `advanced` | \~3 seconds | \$5 per 1,000 requests | Broad language support | Each mode includes up to 10 results. Additional results cost \$1 per 1,000 results. ```json lines theme={null} { "model": "openai/gpt-5.2", "plugins": [ { "id": "web", "engine": "parallel", "mode": "advanced", "max_results": 5, "include_domains": ["arxiv.org"] } ] } ``` ### Exa modes Exa uses `auto` by default. Choose a mode to trade latency and search depth: | Mode | Approximate latency | Request cost | | ---------------- | ------------------- | ----------------------- | | `instant` | \~250 ms | \$7 per 1,000 requests | | `fast` | \~450 ms | \$7 per 1,000 requests | | `auto` (default) | \~1 second | \$7 per 1,000 requests | | `deep-lite` | \~4 seconds | \$12 per 1,000 requests | | `deep` | \~4–15 seconds | \$12 per 1,000 requests | | `deep-reasoning` | \~12–40 seconds | \$15 per 1,000 requests | Each mode includes up to 10 results. Additional results cost \$1 per 1,000 results. ```json lines theme={null} { "model": "openai/gpt-5.2", "plugins": [ { "id": "web", "engine": "exa", "mode": "deep-lite", "max_results": 5 } ] } ``` ### Engine-Specific Pricing * **Native search**: Pricing is passed through directly from the provider (see provider-specific pricing info below) * **Exa search**: Instant, Fast, and Auto cost \$0.007 per request; Deep Lite and Deep cost \$0.012; Deep Reasoning costs \$0.015. Includes up to 10 results, then \$0.001 per additional result * **Parallel search**: Turbo and Fast use OpenRouter credits at \$0.001 per request; Basic and Advanced use \$0.005 per request. Each includes up to 10 results, then \$0.001 per additional result * **Perplexity search**: Uses OpenRouter credits at \$0.005 per request * **Firecrawl search**: Uses your Firecrawl credits directly (2 credits per 10 results + 5 per result scraped with highlights). Refill at [Firecrawl.dev](https://www.firecrawl.dev) ## Pricing ### Exa Search Pricing When using Exa search (either explicitly via `"engine": "exa"` or as fallback), the web plugin uses your OpenRouter credits and charges based on the selected Exa mode. Auto remains the default at \$0.007 per request. This includes up to 10 results; additional results are charged at \$0.001 each, in addition to the LLM usage for the search result prompt tokens. ### Native Search Pricing (Provider Passthrough) Some models have built-in web search. These models charge a fee based on the search context size, which determines how much search data is retrieved and processed for a query. ### Search Context Size Thresholds Search context can be 'low', 'medium', or 'high' and determines how much search context is retrieved for a query: * **Low**: Minimal search context, suitable for basic queries * **Medium**: Moderate search context, good for general queries * **High**: Extensive search context, ideal for detailed research ### Specifying Search Context Size You can specify the search context size in your API request using the `web_search_options` parameter: ```json lines theme={null} { "model": "openai/gpt-4.1", "messages": [ { "role": "user", "content": "What are the latest developments in quantum computing?" } ], "web_search_options": { "search_context_size": "high" } } ``` **Native Web Search Pricing** Refer to each provider's documentation for their native web search pricing info: * [OpenAI Pricing](https://platform.openai.com/docs/pricing#built-in-tools) * [Anthropic Pricing](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool#usage-and-pricing) * [Google Pricing](https://ai.google.dev/pricing) * [Perplexity Pricing](https://docs.perplexity.ai/getting-started/pricing) * [SpaceXAI Pricing](https://docs.x.ai/docs/models#tool-invocation-costs) Native web search pricing only applies when using `"engine": "native"` or when native search is used by default for supported models. When using `"engine": "exa"`, the Exa search pricing applies instead.