The web plugin and :online model suffix are deprecated. They continue to work, but new integrations should use Server Tools instead. Server Tools give the model control over when to search, return structured citations, and support more engines.
ARouter supports web search grounding for any model — not just models with built-in search. Activate it by appending :online to the model slug or by passing the web plugin in your request body.
Quick Start
Append :online to any model slug to enable web search:
{"model": "openai/gpt-5.4:online"}
Or use the plugins array explicitly:
{
"model": "openai/gpt-5.4",
"plugins": [{"id": "web"}]
}
Both approaches are equivalent.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.arouter.ai/v1",
apiKey: "lr_live_xxxx",
});
const response = await client.chat.completions.create({
model: "openai/gpt-5.4:online",
messages: [{ role: "user", content: "What happened in tech news today?" }],
});
console.log(response.choices[0].message.content);
from openai import OpenAI
client = OpenAI(
base_url="https://api.arouter.ai/v1",
api_key="lr_live_xxxx",
)
response = client.chat.completions.create(
model="openai/gpt-5.4:online",
messages=[{"role": "user", "content": "What happened in tech news today?"}],
)
print(response.choices[0].message.content)
curl https://api.arouter.ai/v1/chat/completions \
-H "Authorization: Bearer lr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5.4:online",
"messages": [{"role": "user", "content": "What happened in tech news today?"}]
}'
Parsing Web Search Results
Web search results are standardized across all providers and returned in the annotations field of the response message:
{
"choices": [
{
"message": {
"role": "assistant",
"content": "Here's the latest news I found: ...",
"annotations": [
{
"type": "url_citation",
"url_citation": {
"url": "https://www.example.com/article",
"title": "Article title",
"content": "Excerpt from the article",
"start_index": 100,
"end_index": 200
}
}
]
}
}
]
}
Customizing the Web Plugin
Pass a plugins array to configure web search behavior:
{
"model": "openai/gpt-5.4",
"messages": [{"role": "user", "content": "Latest AI research"}],
"plugins": [
{
"id": "web",
"max_results": 3,
"search_prompt": "A web search was conducted. Use these results to answer:"
}
]
}
| Parameter | Type | Default | Description |
|---|
id | string | — | Must be "web" |
max_results | number | 5 | Maximum number of search results to retrieve |
search_prompt | string | See below | Prompt injected before search results |
engine | string | auto | Search engine: "native", "exa", or "parallel" |
include_domains | string[] | — | Only return results from these domains |
exclude_domains | string[] | — | Exclude results from these domains |
Default search prompt:
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
Restrict which domains appear in search results:
{
"model": "openai/gpt-5.4",
"plugins": [
{
"id": "web",
"include_domains": ["arxiv.org", "*.openai.com"],
"exclude_domains": ["reddit.com"]
}
]
}
Both include_domains and exclude_domains accept domain strings with optional wildcards (*.substack.com) and path filtering (openai.com/blog).
Engine Compatibility
| Engine | include_domains | exclude_domains |
|---|
| Exa | Yes | Yes |
| Parallel | Yes | Yes (mutually exclusive with include) |
| Native (Anthropic) | Yes | Yes (mutually exclusive) |
| Native (OpenAI) | Yes | Ignored |
| Native (xAI) | Yes | Yes (mutually exclusive, max 5 each) |
Engine Selection
ARouter supports multiple search engines via the engine parameter:
| Engine | Description |
|---|
| (unset) | Use native search if the provider supports it, otherwise fall back to Exa |
"native" | Always use the model provider’s built-in search (may error if unsupported) |
"exa" | Use Exa’s neural+keyword hybrid search |
"parallel" | Use Parallel’s search API |
Default Behavior
- OpenAI, Anthropic, xAI models → native search by default
- All other models → Exa search
{
"model": "google/gemini-2.5-flash:online",
"plugins": [{"id": "web", "engine": "exa", "max_results": 3}]
}
Search Context Size
For models that support native search, control how much search context is retrieved:
{
"model": "openai/gpt-5.4:online",
"messages": [{"role": "user", "content": "Latest quantum computing research"}],
"web_search_options": {
"search_context_size": "high"
}
}
| Value | Description |
|---|
"low" | Minimal search context — fast and cheap |
"medium" | Moderate context — suitable for most queries |
"high" | Extensive context — ideal for detailed research |
Pricing
Web search incurs additional charges beyond normal LLM token costs.
Exa Search
- **4per1,000results∗∗(default‘maxresults:5‘=0.02 per request maximum)
- Charged from your ARouter credits
Native Search
Pricing depends on the provider and search context size. Refer to each provider’s documentation:
Parallel Search
- $4 per 1,000 results (same rate as Exa)
- Charged from your ARouter credits
Web search charges apply even when used with :free model variants.
Combining with Free Models
You can combine :online with :free:
{"model": "meta-llama/llama-4-maverick:free:online"}
The LLM inference is free but web search still incurs search costs.
xAI X Search Filters
When using xAI models with web search, ARouter automatically includes X/Twitter search alongside web search. Control X search behavior with the x_search_filter parameter:
{
"model": "x-ai/grok-4.20:online",
"messages": [{"role": "user", "content": "What are people saying about AI?"}],
"x_search_filter": {
"allowed_x_handles": ["sama", "karpathy"],
"from_date": "2025-01-01",
"to_date": "2025-12-31"
}
}
| Parameter | Type | Description |
|---|
allowed_x_handles | string[] | Only include posts from these handles (max 10) |
excluded_x_handles | string[] | Exclude posts from these handles (max 10) |
from_date | string | Start date (ISO 8601, e.g. "2025-01-01") |
to_date | string | End date (ISO 8601) |
enable_image_understanding | boolean | Analyze images in posts |
enable_video_understanding | boolean | Analyze videos in posts |
allowed_x_handles and excluded_x_handles are mutually exclusive. If both are set, the filter is silently dropped.
Practical Examples
Research Assistant
response = client.chat.completions.create(
model="anthropic/claude-sonnet-4.6:online",
messages=[{
"role": "user",
"content": "What are the latest developments in fusion energy research?"
}],
extra_body={
"plugins": [{
"id": "web",
"max_results": 5,
"include_domains": ["nature.com", "science.org", "arxiv.org"]
}]
}
)
News Summarization
response = client.chat.completions.create(
model="openai/gpt-5.4:online",
messages=[{
"role": "user",
"content": "Summarize today's top 3 technology news stories"
}],
extra_body={
"plugins": [{
"id": "web",
"max_results": 10,
"exclude_domains": ["reddit.com", "twitter.com"]
}]
}
)
The recommended replacement for the web plugin and :online suffix is the openrouter:web_search Server Tool. Server Tools are invoked by the model itself when it determines a search is needed, rather than being forced on every request.
See Server Tools — Web Search for the migration guide and full configuration reference.
See Plugins Overview for the full list of available plugins.