Skip to content

LangChain web search with ContextFetch: TavilySearch and Exa tools

Keep the LangChain tools you know. TavilySearch from langchain-tavily takes tavily_api_key and api_base_url, and ExaSearchResults from langchain-exa takes exa_api_key and exa_base_url. Give them your ContextFetch key and the ContextFetch URLs, and any LangChain or LangGraph agent that binds them now searches through ContextFetch for $1 per 1,000 searches. The tool names, schemas and result shapes your prompts rely on stay the same.

Verified PythonLangChain/tavily/search/search

1. Get a ContextFetch key

A free key carries $2.50 of balance, which is 2,500 default searches, and needs no signup. Only one is issued per network. Export it so both tools can read it from CONTEXTFETCH_API_KEY.

curl -X POST https://api.contextfetch.dev/v1/keys/free# {"apiKey": "cf_live_...", "balance_usd": 2.5, "searches": 2500}export CONTEXTFETCH_API_KEY="cf_live_..."

2. Install the integration packages

Each tool is its own partner package. You only need the one you plan to bind, but the program installs both.

pip install langchain-tavily langchain-exa

3. Create the tools with ContextFetch URLs

TavilySearch hands tavily_api_key and api_base_url to its API wrapper, so requests go to https://api.contextfetch.dev/tavily/search. ExaSearchResults passes exa_base_url to the Exa client, which calls https://api.contextfetch.dev/search. Everything else, including max_results, topic, include_domains and num_results, is passed through as before.

import osfrom langchain_exa import ExaSearchResultsfrom langchain_tavily import TavilySearch KEY = os.environ["CONTEXTFETCH_API_KEY"]tavily = TavilySearch(tavily_api_key=KEY, api_base_url="https://api.contextfetch.dev/tavily", max_results=5)exa = ExaSearchResults(exa_api_key=KEY, exa_base_url="https://api.contextfetch.dev")

4. Bind them to an agent

Pass the tools to create_agent (or bind_tools on a chat model, or a LangGraph ToolNode). When the model emits a tool call, LangChain runs tool.invoke(args). The program below makes that same invoke call itself, so you can see what the model would receive without an LLM key.

from langchain.agents import create_agent agent = create_agent("openai:gpt-5-mini", tools=[tavily])result = agent.invoke({"messages": [{"role": "user", "content": "Compare Rust async runtimes"}]})print(result["messages"][-1].content)

5. Pricing and limits

A basic TavilySearch call or an auto Exa call is one default search, $1 per 1,000, with up to 25 results and page text included. The tools let the model choose search_depth="advanced", which ContextFetch runs on its deep tier at $3 per 1,000; set the depth when you create the tool if you want to pin the cost. Free keys get 100 requests a minute, paid keys 300.

The complete code

Python, runnable as is with CONTEXTFETCH_API_KEY set. Install first: langchain-tavily, langchain-exa. We ran it against the live API; the output below is what it printed.

import os from langchain_exa import ExaSearchResultsfrom langchain_tavily import TavilySearch KEY = os.environ["CONTEXTFETCH_API_KEY"] tavily = TavilySearch(    tavily_api_key=KEY,    api_base_url="https://api.contextfetch.dev/tavily",    max_results=3,)exa = ExaSearchResults(    exa_api_key=KEY,    exa_base_url="https://api.contextfetch.dev",) # Invoke the tools directly, exactly as an agent's tool call does.res = tavily.invoke({"query": "rust async runtime comparison tokio"})print("TavilySearch:")for r in res["results"]:    print(f"  {r['score']:.2f}  {r['title']}\n        {r['url']}") out = exa.invoke({"query": "rust async runtime comparison tokio", "num_results": 3})print("ExaSearchResults:")for r in out.results:    print(f"  {r.title}\n        {r.url}") 
OutputRecorded
TavilySearch:
  0.88  Rust Async Runtimes: Tokio vs async-std vs smol
        https://lucaberton.com/blog/rust-async-runtimes-tokio-2026
  0.88  Rust Async Runtimes Compared: Tokio vs Smol in 2026
        https://rust-trends.com/posts/rust-async-runtimes-compared
  0.87  Rust Async Runtimes Compared: tokio vs smol vs io_uring for Network Programming | MatterAI Guides
        https://www.matterai.so/guides/rust-networking-tokio-vs-async-std-vs-smol-for-async-network-programming
ExaSearchResults:
  Rust Async Runtimes: Tokio vs async-std vs smol
        https://lucaberton.com/blog/rust-async-runtimes-tokio-2026
  Rust Async Runtimes Compared: Tokio vs Smol in 2026
        https://rust-trends.com/posts/rust-async-runtimes-compared
  Rust Async Runtimes Compared: tokio vs smol vs io_uring for Network Programming | MatterAI Guides
        https://www.matterai.so/guides/rust-networking-tokio-vs-async-std-vs-smol-for-async-network-programming

The same call with curl

The raw HTTP request, and the response it returned (long text fields and lists shortened).

curl -s https://api.contextfetch.dev/tavily/search \  -H "Authorization: Bearer $CONTEXTFETCH_API_KEY" \  -H "Content-Type: application/json" \  -d '{"query": "rust async runtime comparison tokio", "max_results": 3, "search_depth": "basic"}'
ResponseRecorded
{
  "query": "rust async runtime comparison tokio",
  "images": [],
  "results": [
    {
      "title": "Rust Async Runtimes: Tokio vs async-std vs smol",
      "url": "https://lucaberton.com/blog/rust-async-runtimes-tokio-2026",
      "content": "# Rust Async Runtimes: Tokio vs async-std vs smol\n\nSkip to main content\n\n\n📬 Get weekly Production AI insights\n\n|\n\nPractical notes on Kubernetes, AI infrastructure and platform engineering. No spam.\n\nSubscribe free\nLuca Berton\n\nProduction AI\nToggle Menu\nSpeaking\nAdvisory\nAcademy\n…",
      "raw_content": null,
      "score": 0.884
    },
    {
      "title": "Rust Async Runtimes Compared: Tokio vs Smol in 2026",
      "url": "https://rust-trends.com/posts/rust-async-runtimes-compared",
      "content": "# Rust Async Runtimes Compared: Tokio vs Smol in 2026\n\nRust Trends\n\n\n\n\n\n\n\n/newsletter\n\n/posts\n\n/search\n\n/faq\n\n/about\n\n/sponsor\n\n/contact\n\n/sign up\nHome\nPosts\nRust Async Runtimes Compared: Tokio vs Smol in 2026\nRust Async Runtimes Compared: Tokio vs Smol in 2026\n.\nPosted on\n2026-0…",
      "raw_content": null,
      "score": 0.878
    },
    {
      "title": "Rust Async Runtimes Compared: tokio vs smol vs io_uring for Network Programming | MatterAI Guides",
      "url": "https://www.matterai.so/guides/rust-networking-tokio-vs-async-std-vs-smol-for-async-network-programming",
      "content": "# Rust Async Runtimes Compared: tokio vs smol vs io_uring for Network Programming | MatterAI Guides\n\nBack to Guides\n\nReal-Time Systems & Messaging\n\n# Rust Async Runtimes Compared: tokio vs smol vs io_uring for Network Programming\n\n\n\nMatterAI\n\n10 min read·March 2, 2026\n\n# <a id=\"r…",
      "raw_content": null,
      "score": 0.8664
    }
  ],
  "response_time": 0.024,
  "request_id": "c308af9188b64360bff4a2e3e64d3d76"
}

Questions

What does this save over Tavily or Exa?

Tavily's list price for a basic search is one credit at $0.008 pay-as-you-go, $8 per 1,000, and advanced is two credits. Exa's auto search lists at $7 per 1,000. Through ContextFetch the same calls are $1 per 1,000 (basic, auto) or $3 (advanced, deep). [The Tavily comparison](/compare/tavily-alternative) links the sources.

Is TavilySearch's answer generated by a model?

No. With include_answer, ContextFetch returns a passage quoted word for word from the most relevant result, or null. It runs no generative model, so the answer never says anything the sources do not.

Does the retriever work too?

ExaSearchRetriever in langchain-exa takes the same exa_base_url field, so it can point at ContextFetch the same way. The program on this page exercises the two tools, not the retriever.

Can I test without a key?

These tools require a key, so claim the free one. Raw requests sent with no Authorization header are allowed 25 times per IP address per day, which is enough to try the curl call.

Run it with your own key

A free key has 2,500 searches and needs no signup. Agents can claim one themselves with the POST below.

curl -X POST https://api.contextfetch.dev/v1/keys/free
Get a free key