Skip to main content
New to Exa? Try the Coding Agent Quickstart to get started in under a minute.
The official Python SDK for Exa. Search the web, get page contents, find similar pages, and get answers with citations.

Get API Key

Get your API key from the dashboard

Install

bash pip install exa-py
Requires Python 3.9+

Quick Start

from exa_py import Exa

exa = Exa()  # reads EXA_API_KEY from environment
Search the web and get page contents in one call.
results = exa.search(
    "blog post about artificial intelligence",
    contents={"highlights": {"max_characters": 4000}}
)
results = exa.search(
    "climate tech news",
    num_results=20,
    start_published_date="2024-01-01",
    include_domains=["techcrunch.com", "wired.com"],
    contents={"highlights": {"max_characters": 4000}}
)
structured_results = exa.search(
    "Who is the CEO of OpenAI?",
    type="deep",
    system_prompt="Prefer official sources and avoid duplicate results",
    output_schema={
        "type": "object",
        "properties": {
            "leader": {"type": "string"},
            "title": {"type": "string"},
            "source_count": {"type": "number"}
        },
        "required": ["leader", "title"]
    },
    contents={"highlights": {"max_characters": 4000}}
)

print(structured_results.output.content if structured_results.output else None)
output_schema and system_prompt work across all search types. Keep output_schema focused on the fields you want in output.content, and use system_prompt to guide the final returned result. For more demanding synthesis, prefer reasoning-focused search types like deep-lite, deep, deep-reasoning, or deep-max. Do not add citations/confidence fields there; grounding is returned automatically in output.grounding. Adding citation/confidence fields to output_schema creates duplicate data, weaker structure, and less reliable attribution.
Reasoning-focused search variants:
  • deep-lite: lowest-latency deep-search mode
  • deep: light mode
  • deep-reasoning: base reasoning mode
  • deep-max: maximum-effort deep-search mode
Need streaming structured synthesis? The raw /search endpoint supports stream: true together with outputSchema and returns OpenAI-compatible SSE chunks. See the Search API guide.

Get Contents

Get text, summaries, or highlights from URLs.
results = exa.get_contents(
    ["https://openai.com/research"],
    text=True
)
results = exa.get_contents(
    ["https://stripe.com/docs/api"],
    summary=True
)
results = exa.get_contents(
    ["https://arxiv.org/abs/2303.08774"],
    highlights={"max_characters": 2000}
)

Find Similar

Find pages similar to a URL.
results = exa.find_similar(
    "https://paulgraham.com/greatwork.html",
    contents={"text": True}
)
results = exa.find_similar(
    "https://waitbutwhy.com/2015/01/artificial-intelligence-revolution-1.html",
    exclude_source_domain=True,
    contents={"text": True}
)

Answer

Get answers to questions with citations.
response = exa.answer("What caused the 2008 financial crisis?")
print(response.answer)
for chunk in exa.stream_answer("Explain quantum computing"):
    print(chunk, end="", flush=True)

Async

Use AsyncExa for async operations.
from exa_py import AsyncExa

exa = AsyncExa()

results = await exa.search(
    "machine learning startups",
    contents={"highlights": {"max_characters": 4000}}
)

Research

Run research tasks with structured output.
task = exa.research.create(
    instructions="Summarize recent advances in fusion energy",
    output_schema={
        "type": "object",
        "properties": {
            "summary": {"type": "string"},
            "key_developments": {"type": "array", "items": {"type": "string"}}
        }
    }
)

result = exa.research.poll_until_finished(task.research_id)

Resources