Providers
Tavily
The Tavily search API, with an optional generated answer in response metadata, and Tavily Extract for reading pages.
- env var
- TAVILY_API_KEY
- auth
- request body for search, Bearer header for read
- operations
- search · read
- results
- 10, up to 20
Address it
import { create, readUrl, searchProviderDetailed } from "@agntn/web";
const tavily = await create("tavily"); // TAVILY_API_KEY
const results = await tavily.search("query", { includeDomains: ["docs.python.org"] });
const recent = await tavily.search("query", { category: "news", startPublishedDate: "2026-06-01" });
const answer = await searchProviderDetailed("tavily", "query", { summary: true, fullText: true });
answer.metadata?.answer; // the generated answer for the query
const page = await readUrl("https://docs.python.org/3/", { provider: "tavily", format: "text" });
Search puts the key in the body of a POST to api.tavily.com, Extract takes it as a Bearer token.
What it reads
| Call | Endpoint |
|---|---|
search | POST /search with max_results, search_depth: "basic", include_answer, include_raw_content, include_published_date: true, and topic, start_date, end_date when asked |
read | POST /extract with one URL in urls, extract_depth: "basic", format and timeout |
What comes back
score, publishedDate and, with fullText, text from raw_content. summary asks for the query answer, which lands in response metadata.answer, not on a result. Include and exclude domains work, startPublishedDate and endPublishedDate go through as start_date and end_date, and category set to general, news or finance picks Tavily's topic.
Reads give markdown or text in content, the page title and Tavily's request_id in metadata.requestId. timeout is passed on in seconds, clamped to Tavily's 1 to 60. No links, images or selectors, and maxTokens and noCache are ignored.
Gotchas
- The answer is one string for the whole query, so it lives on the response, not on a result.
search()alone cannot show it,searchDetailed()can. search_depthis alwaysbasic. Advanced depth costs more credits and is not exposed, on purpose.- Tavily dates a result only when asked, so every search asks. It writes the date as
Tue, 11 Mar 2025 17:00:00 GMT, which becomes ISO 8601 here like everyone else's, and a page it couldn't date has nopublishedDate. Tavily calls the field beta. - The window is by day, so a datetime bound becomes its UTC day. Pages Tavily couldn't date stay in, three of five on a plain query, so
filter_by_published_dateisn't sent on purpose. - A spent plan or pay-as-you-go cap comes back as HTTP 432 or 433, not 402. Both are
PaymentErrorhere, so automatic search and read move on to the next configured provider. A wrong key is still 401 and still stops the chain. - A page Extract cannot fetch is not an HTTP error. The response is a 200 with an empty
resultsand the reason infailed_results(404 page not found,Failed to fetch url, which is also what a PDF gets). That becomes aWebErrorwith the reason, not a fallback. urlon a read is the one you asked for. Extract does not report where a redirect ended up.- Extract is
basicdepth,advanced(tables and embedded content, twice the credits) is not exposed. Basic costs one credit per five successful pages.
Where it lives
src/providers/tavily.ts.