Web Search and Extract Integration for Hermes Agent

Connects Hermes Agent to web search and extract providers for AI-powered browsing.

Data & On-Chainintermediate13 min readVerified Jul 27, 2026

The Hermes Agent web search and extract integration connects the Hermes Agent runtime to multiple web search and content extraction providers, enabling AI agents to search the web and extract readable content from URLs. Once wired up, an agent can call web_search to retrieve ranked search results and web_extract to fetch and summarize page content, using backends such as Firecrawl, SearXNG, Brave Search, DuckDuckGo, Tavily, Exa, Parallel, or xAI (Grok).

What It Does

Hermes Agent includes two model-callable web tools backed by multiple providers:

  • web_search: Search the web and return ranked results.
  • web_extract: Fetch and extract readable content from one or more URLs.

Both tools are configured through a single backend selection, which can be set via hermes tools or directly in config.yaml. The integration supports per-capability configuration, meaning you can use different providers for search and extract independently. For example, you could use SearXNG (free) for search and Firecrawl for extract.

According to the official documentation, the supported backends and their capabilities are as follows:

  • Firecrawl (default): Supports both search and extract. Free tier includes 500 credits per month. Requires FIRECRAWL_API_KEY.
  • SearXNG: Search only. Free, self-hosted. Requires SEARXNG_URL.
  • Brave Search (free tier): Search only. 2,000 queries per month. Requires BRAVE_SEARCH_API_KEY.
  • DDGS (DuckDuckGo): Search only. Free, no API key needed.
  • Tavily: Supports both search and extract. 1,000 searches per month on free tier. Requires TAVILY_API_KEY.
  • Exa: Supports both search and extract. 1,000 searches per month on free tier. Requires EXA_API_KEY.
  • Parallel: Supports both search and extract. Paid. Requires PARALLEL_API_KEY.
  • xAI (Grok): Search only. Paid (SuperGrok or per-token). Requires XAI_API_KEY or hermes auth add xai-oauth.

Brave Search, DDGS, and xAI are search-only. If you also need web_extract, you must pair any of them with Firecrawl, Tavily, Exa, or Parallel. DDGS uses the ddgs Python package under the hood; if it is not already installed, run pip install ddgs (or let Hermes lazy-install it on first use). xAI runs Grok's server-side web_search tool on the Responses API. Results are LLM-generated rather than index-backed, so titles, descriptions, and URL choice are all model output (see the trust-model caveat below).

For Nous Subscribers with a paid Nous Portal subscription, web search and extract are available through the Tool Gateway via managed Firecrawl with no API key needed. New installs can run hermes setup --portal to log in and turn on all gateway tools at once; existing installs can flip just web via hermes tools.

Setup

Quick setup via hermes tools

Run hermes tools, navigate to Web Search & Extract, and pick a provider. The wizard prompts for the required URL or API key and writes it to your config.

hermes tools

Firecrawl (default)

Firecrawl is the default backend and is recommended for most users. It provides full-featured search and extract.

# ~/.hermes/.env
FIRECRAWL_API_KEY = fc-your-key-here

Get a key at firecrawl.dev. The free tier includes 500 credits per month.

For self-hosted Firecrawl, point at your own instance instead of the cloud API:

# ~/.hermes/.env
FIRECRAWL_API_URL = http://localhost:3002

When FIRECRAWL_API_URL is set, the API key is optional (disable server auth with USE_DB_AUTHENTICATION=false).

SearXNG (free, self-hosted)

SearXNG is a privacy-respecting, open-source metasearch engine that aggregates results from 70+ search engines. No API key is required. Just point Hermes at a running SearXNG instance. SearXNG is search-only; web_extract requires a separate extract provider.

Option A: Self-host with Docker (recommended)

This gives you a private instance with no rate limits.

  1. Create a working directory:
mkdir -p ~/searxng/searxng
cd ~/searxng
  1. Write a docker-compose.yml:
# ~/searxng/docker-compose.yml
services :
searxng :
image : searxng/searxng : latest
container_name : searxng
ports :
- "8888:8080"
volumes :
- ./searxng : /etc/searxng : rw
environment :
- SEARXNG_BASE_URL=http : //localhost : 8888/
restart : unless - stopped
  1. Start the container:
docker compose up -d
  1. Enable the JSON API format:

SearXNG ships with JSON output disabled by default. Copy the generated config and enable it:

# Copy the auto-generated config out of the container
docker cp searxng:/etc/searxng/settings.yml ~/searxng/searxng/settings.yml

Open ~/searxng/searxng/settings.yml. If use_default_settings: true is present, the file only contains your overrides. All other settings are inherited from the built-in defaults. To enable JSON responses for Hermes, add the following override:

search :
formats :
- html
- json

Your settings.yml should look similar to:

# Read the documentation before extending the defaults:
# https://docs.searxng.org/admin/settings/

use_default_settings : true

server :
secret_key : "abcdef12345678"
image_proxy : true

search :
formats :
- html
- json
  1. Restart to apply:
docker cp ~/searxng/searxng/settings.yml searxng:/etc/searxng/settings.yml
docker restart searxng
  1. Verify it works:
curl -s "http://localhost:8888/search?q=test&format=json" | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(f'{len(d[ " results " ])} results')"

You should see something like 10 results. If you get a 403 Forbidden, JSON format is still disabled. Recheck step 4.

  1. Configure Hermes:
# ~/.hermes/.env
SEARXNG_URL = http://localhost:8888

Then select SearXNG as the search backend in ~/.hermes/config.yaml:

web :
search_backend : "searxng"

Or set via hermes tools -> Web Search & Extract -> SearXNG.

Option B: Use a public instance

Public SearXNG instances are listed at searx.space. Filter by instances that have JSON format enabled (shown in the table).

# ~/.hermes/.env
SEARXNG_URL = https://searx.example.com

Public instances have rate limits, variable uptime, and may disable JSON format at any time. For production use, self-hosting is strongly recommended.

Pair SearXNG with an extract provider

SearXNG handles search; you need a separate provider for web_extract. Use the per-capability keys:

# ~/.hermes/config.yaml
web :
search_backend : "searxng"
extract_backend : "firecrawl" # or tavily, exa, parallel

With this config, Hermes uses SearXNG for all search queries and Firecrawl for URL extraction, combining free search with high-quality extraction.

Tavily

Tavily is an AI-optimised search and extract provider with a generous free tier.

# ~/.hermes/.env
TAVILY_API_KEY = tvly-your-key-here

Get a key at app.tavily.com. The free tier includes 1,000 searches per month.

Exa

Exa is a neural search engine with semantic understanding. Good for research and finding conceptually related content.

# ~/.hermes/.env
EXA_API_KEY = your-exa-key-here

Get a key at exa.ai. The free tier includes 1,000 searches per month.

Parallel

Parallel is an AI-native search and extraction provider with deep research capabilities.

# ~/.hermes/.env
PARALLEL_API_KEY = your-parallel-key-here

Get access at parallel.ai.

xAI (Grok)

Routes web_search through Grok's server-side web_search tool on the Responses API. Grok runs the actual searching and returns the top results as structured JSON.

Works with either credential path. No new env vars, no new setup wizard:

# ~/.hermes/.env (env-var path)
XAI_API_KEY = sk-xai-your-key-here

Or for SuperGrok subscribers:

hermes auth add xai-oauth

Then select xAI as the search backend:

# ~/.hermes/config.yaml
web :
backend : "xai"

Optional knobs:

web :
backend : "xai"
xai :
model : grok - build - 0.1 # reasoning model required by web_search (default)
allowed_domains : # optional, max 5, mutex with excluded_domains
- arxiv.org
excluded_domains : # optional, max 5
- example - spam.com
timeout : 90 # seconds (default)

Search-only. Pair with Firecrawl, Tavily, Exa, or Parallel if you also need web_extract. On 401, the provider performs a single forced OAuth-token refresh and retries (covers mid-window revocation and opaque tokens the proactive expiry check cannot decode); env-var credentials skip the retry.

Trust model: Unlike index-backed providers (Brave, Tavily, Exa) which return verbatim search-engine results, xAI is an LLM choosing which URLs to surface and writing the titles and descriptions itself. The content of the query influences the output, so a maliciously crafted query (e.g. injected via untrusted upstream input the agent picked up) can in principle steer Grok into emitting attacker-chosen URLs. Treat returned URLs the same way you would treat any model-generated link. Validate before fetching, especially if the query came from untrusted input.

Configuration Reference

Single backend

Set one provider for all web capabilities:

# ~/.hermes/config.yaml
web :
backend : "searxng" # firecrawl | searxng | brave-free | ddgs | tavily | exa | parallel | xai

Per-capability configuration

Use different providers for search vs extract. This lets you combine free search (SearXNG) with a paid extract provider, or vice versa:

# ~/.hermes/config.yaml
web :
search_backend : "searxng" # used by web_search
extract_backend : "firecrawl" # used by web_extract

When per-capability keys are empty, both fall through to web.backend. When web.backend is also empty, the backend is auto-detected from whichever API key or URL is present.

Priority order (per capability):

  • web.search_backend / web.extract_backend (explicit per-capability)
  • web.backend (shared fallback)
  • Auto-detect from environment variables

Auto-detection

If no backend is explicitly configured, Hermes picks the first available one based on which credentials are set:

Credential presentAuto-selected backend
FIRECRAWL_API_KEY or FIRECRAWL_API_URLfirecrawl
PARALLEL_API_KEYparallel
TAVILY_API_KEYtavily
EXA_API_KEYexa
SEARXNG_URLsearxng

xAI Web Search is not in the auto-detection chain. Having XAI_API_KEY set (or being signed in via xAI Grok OAuth) does not automatically route web traffic through xAI, since those credentials are also used for inference, TTS, image generation, and the user may want a different backend for web. Opt in explicitly with web.backend: "xai".

xAI-specific options

OptionTypeDefaultDescription
web.xai.modelstringgrok - build - 0.1The reasoning model required by web_search.
web.xai.allowed_domainslist of stringsnoneOptional, max 5. Mutex with excluded_domains.
web.xai.excluded_domainslist of stringsnoneOptional, max 5.
web.xai.timeoutinteger90Timeout in seconds for the xAI web search request.

Auxiliary model for web_extract summarization

OptionTypeDefaultDescription
auxiliary.web_extract.providerstring"auto"The provider for the summarization model. "auto" uses the main chat model.
auxiliary.web_extract.modelstringsame as main modelThe model to use for summarization.
auxiliary.web_extract.timeoutinteger360 (fresh installs), 30 (if key missing)Timeout in seconds for the summarization call.

How It Works

How web_extract handles long pages

Backends return raw page markdown, which can be very large (forum threads, docs sites, news articles with embedded comments). To keep the context window usable and costs down, web_extract runs returned content through the web_extract auxiliary model before handing it to the agent. Behavior is purely size-driven:

Page size (characters)What happens
Under 5,000Returned as-is. No LLM call, full markdown reaches the agent.
5,000 to 500,000Single-pass summary via the web_extract auxiliary model, capped at approximately 5,000 characters of output.
500,000 to 2,000,000Chunked: split into 100k-character chunks, summarize each in parallel, then synthesize a final summary (approximately 5,000 characters).
Over 2,000,000Refused with a hint to use a more focused source URL.

The summary keeps quotes, code blocks, and key facts in their original formatting. It is a content compressor, not a paraphraser. If summarization fails or times out, Hermes falls back to the first approximately 5,000 characters of raw content rather than returning a useless error.

Which model does the summarizing?

The web_extract auxiliary task. By default (auxiliary.web_extract.provider: "auto"), this is your main chat model. Same provider, same model as hermes model. That is fine for most setups, but on expensive reasoning models (Opus, MiniMax M2.7, etc.) every long-page extract adds meaningful cost.

To route extraction summaries to a cheap, fast model regardless of your main:

# ~/.hermes/config.yaml
auxiliary :
web_extract :
provider : openrouter
model : google/gemini - 3 - flash - preview
timeout : 360 # seconds; raise if you hit summarization timeouts

Or pick interactively: hermes model -> Configure auxiliary models -> web_extract.

When summarization gets in the way

If you specifically need raw, unsummarized page content (for example, you are scraping a structured page where the LLM summary would drop important fields), use browser_navigate + browser_snapshot instead. The browser tool returns the live accessibility tree without auxiliary-model rewriting, subject to its own 8,000-character snapshot cap on huge pages.

Requirements and Limitations

  • Firecrawl is the default backend. The free tier includes 500 credits per month.
  • SearXNG is search-only. It requires a separate extract provider for web_extract.
  • Brave Search (free tier) is search-only, with 2,000 queries per month.
  • DDGS (DuckDuckGo) is search-only, free, and requires no API key. It uses the ddgs Python package. If not already installed, run pip install ddgs or let Hermes lazy-install it on first use.
  • Tavily free tier includes 1,000 searches per month.
  • Exa free tier includes 1,000 searches per month.
  • Parallel is paid.
  • xAI (Grok) is search-only and paid (SuperGrok or per-token). It is not in the auto-detection chain. You must opt in explicitly with web.backend: "xai".
  • xAI results are LLM-generated, not index-backed. Treat returned URLs with caution, especially if the query came from untrusted input.
  • For xAI, on 401 the provider performs a single forced OAuth-token refresh and retries. Env-var credentials skip the retry.
  • Public SearXNG instances have rate limits, variable uptime, and may disable JSON format at any time. Self-hosting is strongly recommended for production use.
  • The web_extract tool refuses pages over 2,000,000 characters with a hint to use a more focused source URL.
  • The web_extract auxiliary model timeout defaults to 360 seconds on fresh installs, but 30 seconds if the key is missing. Raise it if you hit summarization timeouts.
  • The browser_navigate + browser_snapshot alternative has its own 8,000-character snapshot cap on huge pages.

Troubleshooting

web_search returns {"success": false}

  • Check that SEARXNG_URL is reachable: curl -s "http://localhost:8888/search?q=test&format=json"
  • If you get HTTP 403, JSON format is disabled. Add json to the formats list in settings.yml and restart.
  • If you get a connection error, the container may not be running: docker ps | grep searxng

web_extract says "search-only backend"

SearXNG cannot extract URL content. Set web.extract_backend to a provider that supports extraction:

web :
search_backend : "searxng"
extract_backend : "firecrawl" # or tavily / exa / parallel

SearXNG returns 0 results

Some public instances disable certain search engines or categories. Try:

  • A different query
  • A different public instance from searx.space
  • Self-hosting your own instance for reliable results

Rate limited on a public instance

Switch to a self-hosted instance (see Option A under SearXNG setup). With Docker, your own instance has no rate limits.

web_extract returns truncated content with a "summarization timed out" note

The auxiliary model did not finish summarizing within the configured timeout. Either:

  • Raise auxiliary.web_extract.timeout in config.yaml (default 360s on fresh installs, 30s if the key is missing)
  • Switch the web_extract auxiliary task to a faster model (e.g. google/gemini-3-flash-preview). See the section on how web_extract handles long pages.
  • For pages where summarization is the wrong tool, use browser_navigate instead.

Optional skill: searxng-search

For agents that need to use SearXNG via curl directly (e.g. as a fallback when the web toolset is not available), install the searxng-search optional skill:

hermes skills install official/research/searxng-search

This adds a skill that teaches the agent how to:

  • Call the SearXNG JSON API via curl or Python
  • Filter by category (general, news, science, etc.)
  • Handle pagination and error cases
  • Fall back gracefully when SearXNG is unreachable

Verify your setup

Run hermes setup to see which web backend is detected:

✅ Web Search & Extract (searxng)

Or check via the CLI:

# Activate the venv and run the web tools module directly
source ~/.hermes/hermes-agent/.venv/bin/activate
python -m tools.web_tools

This prints the active backend and its status:

✅ Web backend: searxng
Using SearXNG (search only): http://localhost:8888

Sources & References

This page was researched from 1 independent source, combined and verified for completeness.

Newsletter

The #1 AI Newsletter

The most important ai updates, guides, and fixes — one weekly email.

No spam, unsubscribe anytime. Privacy policy

Other Hermes Agent integrations