tavily-python: a thin SDK over the Tavily search API, with a keyless mode for evaluation
The Tavily Python SDK allows for easy interaction with the Tavily API, offering the full range of our search, extract, crawl, map, and research functionalities directly from your Python programs. Easily integrate smart search, content extraction, and research capabilities into your applications, harnessing Tavily's powerful features.
At a glance
- What is it?
- The Tavily Python SDK wraps a hosted search, extract, crawl, map and research API behind a TavilyClient object. Its most unusual feature is keyless mode, which lets you call search() and extract() without an API key under a rate cap.
- Who is it for?
- Adopt tavily-python if you already pay for Tavily and want its search, extract, crawl, map and research endpoints behind one Python object rather than hand-rolled HTTP calls. Do not adopt it as a general web scraping or crawling library: crawl is invite-only, keyless mode covers only search and extract, and every call depends on Tavily's hosted service and your network.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem tavily-python solves, and who it is written for
Tavily is a hosted search API aimed at programs rather than people. The SDK exists so that a Python application can call that API without writing its own HTTP client, its own request serialisation, or its own error handling for each endpoint. The README frames the audience directly: it says the wrapper offers search, extract, crawl, map and research "directly from your Python programs", and it presents the RAG use case as a single line of code, with get_search_context() returning "a context string that you can feed directly into your RAG Application". That is the shape of the intended user: someone building an agent, a retrieval pipeline, or a question-answering feature who wants web content as a string, not as a browser session. The repository topics list agent, crawl, extract, map, search and python, which matches that positioning. This is not a library for parsing HTML you already have, and it is not a self-hosted search engine. It is a client for someone else's service, and the value it adds is convenience plus a small amount of client-side structure around errors and responses.
What TavilyClient actually does between your code and the API
The mechanism is deliberately thin. You import TavilyClient, instantiate it with an API key, and call methods named after the endpoints: search(), get_search_context(), qna_search(), extract(), crawl() and map(). The README states that a search call "is equivalent to directly querying our REST API", which is the clearest available description of the layer: the SDK is a wrapper, not an orchestration engine. Responses arrive as dictionaries. The extract example indexes response["results"] and reads result["url"], result["raw_content"] and result["images"], and it notes that URLs which could not be extracted land in response["failed_results"]. The crawl example reads response["results"] and slices result["raw_content"][:200]. So the data flow is: your query or URL list goes out, a structured dict comes back, and partial failure is represented inside that dict rather than by raising. The one place the SDK adds behaviour beyond pass-through is keyless mode, where TavilyClient() with no arguments runs against the public Tavily API and raises TavilyKeylessLimitError when the rate cap is hit. That exception is documented as carrying a human-readable message plus structured fields: code, window, retry_after_seconds and next_actions. That is a more useful error contract than a bare HTTP status, and it is the part of the client most worth reading before you build retry logic.
Installing it and making a first call without an API key
Installation is a single command: pip install tavily-python. The README's keyless example is the fastest way to see whether the service fits your problem, because it needs no credentials. You instantiate the client with no arguments, call search() with a query string, and catch TavilyKeylessLimitError. The documented exception fields are code, window, retry_after_seconds and next_actions, and the README prints e.retry_after_seconds as the wait before retrying. The constraint is stated plainly: keyless mode supports search() and extract() only, and other methods raise an error explaining that an API key is required. For the full endpoint set, including crawl, map and research, you sign up at tavily.com and pass the key as TavilyClient(api_key="tvly-..."). From there the calls are short. A search is tavily_client.search("Who is Leo Messi?"). Exact phrase matching is client.search(query='"John Smith" CEO Acme Corp', exact_match=True), which the README says returns only results containing the exact phrases inside quotes. get_search_context(query=...) returns a context string, and qna_search(query=...) returns an answer. For extraction, client.extract(urls=urls, include_images=True) accepts a list, and the README notes you can provide up to 20 URLs simultaneously. Crawl takes url, max_depth, limit and an instructions string; the example uses max_depth=3, limit=50 and instructions="Find all pages on citrus fruits".
Crawl is invite-only, and keyless mode is not a free tier
Two constraints in the README change how you should plan a build. The first is access. Crawl carries a note that it is "currently available on an invite-only basis", with a pointer to crawl.tavily.com. That means you cannot assume the crawl() method will work for a new account, and a prototype that depends on it may stall on provisioning rather than on code. The second is the keyless cap. Keyless mode is described as rate-limited, and TavilyKeylessLimitError exists precisely because that limit is reachable in normal use. If you build a demo on keyless mode and then move to a key, you are changing both the credentials and the rate regime, so the throughput you observe while evaluating is not the throughput you will get in production. There is also a structural limitation that follows from the architecture rather than from any single line of the README: every method here is a network call to Tavily's hosted API. There is no local index, no offline path, and no fallback if the service is unreachable or your key is rejected. If your requirement is to crawl sites you control without sending requests through a third party, or to run in an air-gapped environment, this SDK is the wrong tool regardless of how clean the API is.
How this differs from a general-purpose scraping or crawling library
The obvious alternative for a Python team is a scraping and crawling stack built around requests plus a parser such as BeautifulSoup, or a framework like Scrapy. The difference is not quality, it is where the work happens. With those tools you own the fetching, the politeness rules, the JavaScript rendering problem, the retry policy and the parsing, and you get results that do not depend on a third-party account or a per-call bill. With tavily-python you hand all of that to Tavily and receive structured dictionaries plus, for extract, a failed_results list that tells you which URLs did not come back. The trade is control and operational burden against a smaller amount of code. The README's own framing supports this reading: it advertises generating RAG context "in one line of code" and answers "in one line of code", which is a claim about developer time, not about extraction fidelity or crawl coverage. If your sources are a fixed set of pages you already know how to fetch, a local scraper will be cheaper and more predictable. If your sources are arbitrary web pages discovered at query time, and you would rather not maintain a rendering and parsing pipeline, the hosted approach is the one being offered here.
Maintenance, versioning and the MIT licence
The repository is licensed MIT, which permits commercial use, modification and redistribution provided the copyright notice and licence text are retained. That is a permissive licence and it places no copyleft obligation on your application. It does not, however, govern the Tavily service itself: the SDK is MIT, but the API it calls is a commercial product with its own account, pricing and rate limits, and the README directs you to tavily.com to sign up. Those are two separate agreements and the MIT grant says nothing about the second. On maintenance, the material available here is limited. The repository is not archived and the last push is dated 2026-09-09, and the README references a CI workflow through a badge, but no releases were retrieved for this review, so there is no changelog or semantic versioning history to inspect. That matters for upgrade planning: because the client is thin, most behavioural change will arrive from the API rather than the package, and the README does not describe a deprecation policy or a version support window. Treat the SDK version as a small dependency and the API as the thing you are actually integrating against.
Who should adopt tavily-python, and who should not
Adopt it if you are already a Tavily customer or intend to become one, and your application needs web search, content extraction or RAG context assembled inside a Python process. The SDK removes boilerplate, the keyless path lets you validate the response shape before you buy anything, and the structured TavilyKeylessLimitError gives you something concrete to branch on. Skip it if any of the following is true. You need crawl today and have not been granted invite-only access. You need to run without network access to a third-party service. You need a search backend you host yourself. Or you need guaranteed throughput before you have checked your plan's limits, since the README documents a rate cap on keyless use and gives no numbers for keyed use. The first thing to verify is not in the README: your own account's rate limits and whether crawl is enabled for it. The second is your retry behaviour against retry_after_seconds, because a client that ignores that field will hammer a capped endpoint. The third is whether response["failed_results"] from extract is handled in your code, since silent gaps in a RAG context string are harder to debug than an exception.
Editorial conclusion
Adopt tavily-python if you already pay for Tavily and want its search, extract, crawl, map and research endpoints behind one Python object rather than hand-rolled HTTP calls. Do not adopt it as a general web scraping or crawling library: crawl is invite-only, keyless mode covers only search and extract, and every call depends on Tavily's hosted service and your network. Before committing, check three things in the README and on your Tavily account: whether crawl access has been granted, what your plan's rate limits are, and whether TavilyKeylessLimitError's retry_after_seconds fits your retry logic.
Community notes