---
name: exa
description: Use when building web search, content extraction, or autonomous research workflows. Reach for Exa when you need to find relevant web pages, extract clean content from URLs, build structured lists from open-ended criteria, or run multi-step research tasks with grounded citations.
metadata:
  mintlify-proj: exa
  version: "1.0"
---

# Exa Skill

## Product summary

Exa is a web search and content extraction API that powers AI agents and applications with real-time web data. It provides three core APIs: **Search** (find and rank relevant pages with highlights or full text), **Contents** (extract clean content from known URLs), and **Agent** (async research, list-building, and enrichment with structured output). The SDKs (Python: `exa-py`, JavaScript: `exa-js`) read `EXA_API_KEY` from the environment. Primary docs: https://exa.ai/docs. Comprehensive page listing: https://exa.ai/docs/llms.txt.

## When to use

- **Search API**: User asks to find web pages, research a topic, or retrieve ranked results with highlights or full text. Use when you need a single retrieval pass with optional synthesis.
- **Contents API**: User provides URLs and asks to extract text, highlights, or summaries. Use when you already know which pages to read.
- **Agent API**: User asks to build a list from criteria, enrich entities, run multi-hop research, or produce structured JSON from web research. Use when the task requires multiple search passes, verification, or complex reasoning.
- **Integrations**: User is building with Claude, ChatGPT, Cursor, or other LLM tools. Use the Exa MCP (Model Context Protocol) server at `https://mcp.exa.ai/mcp`, signing in with OAuth or an API key, or the SDKs' tool-calling helpers for OpenAI and Anthropic.

## Quick reference

### API Endpoints

| Endpoint | Method | Use case |
| --- | --- | --- |
| `/search` | POST | Find and rank pages; return highlights, text, or synthesis |
| `/contents` | POST | Extract content from known URLs |
| `/agent/runs` | POST | Start async research, list-building, or enrichment |
| `/agent/runs/{id}` | GET | Poll run status and retrieve results |

### Search Types

| Type | Latency | Cost | Best for |
| --- | --- | --- | --- |
| `lite` | ~450 ms | $4/1000 | High-volume, cost-sensitive, real-time (voice, chat) |
| `auto` | ~1 s | $7/1000 | Default; balanced quality and speed |
| `deep-lite` | ~4 s | $12/1000 | Lightweight research with synthesis |
| `deep` | 4–15 s | $12/1000 | Multi-step research, complex synthesis |

### Agent Effort Levels

| Effort | Price | Best for |
| --- | --- | --- |
| `minimal` | $0.012/request | Lowest-cost lookups, narrow factual tasks |
| `low` | $0.025/request | Simple lookups, short answers |
| `medium` | $0.10/request | Standard research |
| `high` | $0.50/request | Harder research, more citations |
| `xhigh` | $1.00/request | High-value tasks, complex schemas |
| `auto` | Metered; $5 cap | Default. Variable-scope work, list building |
| `ultra` | Metered; $20 cap | Large list building, exhaustive research |

### Content Options (Search & Contents)

| Option | Returns | Cost on Search | Cost on Contents |
| --- | --- | --- | --- |
| `highlights: true` | Query-relevant excerpts, sized per result | Included | $1/1000 pages |
| `text: { maxCharacters: N }` | Full page body as markdown | Included | $1/1000 pages |
| `summary: { query: "..." }` | LLM-generated overview | $1/1000 pages | $1/1000 pages |
| `summary: { schema: {...} }` | LLM-extracted JSON fields | $1/1000 pages | $1/1000 pages |

Contents bills each content type separately, so one page with `text` and `highlights` counts as two.

### SDK Installation

```bash
# Python
pip install exa-py

# Or, if using uv:
uv add exa-py

# JavaScript
npm install exa-js
```

### Authentication

Set `EXA_API_KEY` environment variable. SDKs read it automatically:

```python
from exa_py import Exa
exa = Exa()  # reads EXA_API_KEY

# Or pass explicitly
exa = Exa(api_key="your-key")
```

```javascript
import Exa from "exa-js";
const exa = new Exa();  // reads EXA_API_KEY
```

## Decision guidance

### When to use Search vs. Agent

| Need | Use |
| --- | --- |
| Find ranked pages for a well-formed query | Search with `type: "auto"` or `lite` |
| Difficult searches, synthesis across many results, or structured output with 3+ fields | Search with `type: "deep"` or Agent |
| Build a list from open-ended criteria, enrich entities, or run multi-hop research | Agent API |
| Single low-latency retrieval for chat or voice | Search with `type: "lite"` |

### When to use Highlights vs. Full Text

| Need | Use |
| --- | --- |
| Agent or RAG context; token efficiency matters | `highlights: true` (Exa sizes excerpts per result) |
| Broader page context, document structure, or details outside query focus | `text: { maxCharacters: N }` |
| Fixed excerpt limit per page | `highlights: { maxCharacters: N }` |

### When to use Contents vs. Search

| Need | Use |
| --- | --- |
| URLs already known; extract content from them | Contents API |
| Need to find pages first, then extract content | Search API with `contents` options |
| Bulk extraction from many URLs | Contents API with a list of URLs per request |

## Workflow

### 1. Search for pages

**Understand the task**: What pages does the user need? What content matters (highlights, full text, synthesis)?

**Build the request**:
- Start with natural-language `query` and `contents: { highlights: true }`
- Add `type: "lite"` for cost/latency, `type: "deep"` for complex synthesis
- Add `numResults` if you need more than 10 pages
- Add `includeDomains` or `excludeDomains` only for hard constraints
- Add `outputSchema` if you need synthesized JSON

**Make the call**:
```python
result = exa.search(
    "recent AI infrastructure funding announcements",
    type="auto",
    contents={"highlights": True},
    num_results=10,
)
```

**Verify**: Check `results` for title, URL, and highlights. If results are off-topic, refine the query (not the filters).

### 2. Extract content from URLs

**Understand the task**: Do you need highlights, full text, or a summary? Is freshness critical?

**Build the request**:
- Pass URLs or document IDs in `ids` (or `urls`)
- Choose one content view: `highlights`, `text`, or `summary`
- Add `highlights: { query: "..." }` to focus extraction
- Add `maxAgeHours: 0` only if you need fresh content

**Make the call**:
```python
result = exa.get_contents(
    ["https://example.com/research"],
    highlights={"query": "methodology and results"},
)
```

**Verify**: Check `statuses` for success/failure of each URL. Read `results[].highlights` or `results[].text`.

### 3. Run async research (Agent)

**Understand the task**: Does the user want a list, enrichment, verification, or structured output? How many entities?

**Build the request**:
- Write a clear `query` describing what to find or verify
- Add `outputSchema` for validated JSON (use `maxItems` to bound list size)
- Choose `effort`: start with `"medium"` for standard research, `"auto"` for variable-scope work
- Add `dataSources` only if you need premium data partners (Similarweb, Fiber, etc.)

**Create and poll**:
```python
run = exa.agent.runs.create(
    query="Find AI infrastructure companies that raised Series A/B in the last 6 months",
    output_schema={
        "type": "object",
        "properties": {
            "companies": {
                "type": "array",
                "maxItems": 10,
                "items": {
                    "type": "object",
                    "properties": {
                        "name": {"type": "string"},
                        "round": {"type": "string"},
                        "website": {"type": "string"},
                    },
                    "required": ["name", "round"],
                },
            }
        },
        "required": ["companies"],
    },
    effort="auto",
)

# Poll until done
run = exa.agent.runs.poll_until_finished(run.id)
```

**Verify**: Check that `run.status` is `completed` before reading `output`. A `failed` run carries `error` instead. Check `run.output.structured` for JSON, `run.output.grounding` for citations, `run.cost_dollars` for cost.

## Common gotchas

- **Lite search rejects many parameters**: `lite` does not support `outputSchema`, `summary`, `maxAgeHours` (with any value), or `additionalQueries`. Use `auto` if you need these. Error message names the unsupported field.
- **Contents and Search nest options differently**: Search uses `contents: { highlights: true }`, but Contents uses top-level `highlights: true`. No `contents` wrapper on `/contents`.
- **Highlights are sized per result**: Do not set `highlights.maxCharacters` unless you need a fixed limit. Exa allocates budget based on relevance by default.
- **Agent runs are async**: Always poll or stream. Do not expect immediate results. Default budget is $5 for `auto`, $20 for `ultra`.
- **Search outputSchema limits**: On `/search`, max 10 properties total (nested count) and 2 levels of nesting. For wider schemas, use Agent. Do not add citation or confidence fields; Exa returns them in `output.grounding`.
- **Deprecated parameters**: `useAutoprompt`, `livecrawl`, `startCrawlDate`, `endCrawlDate`, `includeText`, `excludeText` are deprecated. Remove `useAutoprompt`, use `startPublishedDate`/`endPublishedDate` instead of the ignored crawl dates, `contents.maxAgeHours` instead of `livecrawl`, and put `includeText`/`excludeText` terms in the query. Check `warnings` in the response. `lite` rejects `includeText`, `excludeText`, `startCrawlDate`, `endCrawlDate` and `contents.livecrawl` with a 400.
- **userIdentifier must be opaque**: Never send email, phone, username, or name. Hash or UUID only. 1–64 characters: letters, digits, `_`, `-`.
- **ZDR (Zero Data Retention) blocks previousRunId**: If your team has ZDR enabled, you cannot continue from a previous run, `dataSources` accepts only ZDR-eligible Connect providers, and a run can be retrieved for only 10 minutes after it finishes. ZDR is an Enterprise feature. Contact sales to enable it.
- **Search does not support pagination**: `numResults` returns up to 100 results in one call. No cursor or offset.
- **Agent effort is not a latency guarantee**: Runtime varies by query difficulty, schema complexity, and source availability. Treat effort as a quality/cost tradeoff.

## Verification checklist

Before submitting work:

- [ ] API key is set in environment or passed explicitly
- [ ] Query is natural language, not a bag of keywords
- [ ] Search type matches the task (lite for speed, deep for synthesis, auto for balance)
- [ ] Content options are nested correctly (`contents: { highlights: true }` for Search, top-level for Contents)
- [ ] `outputSchema` is valid JSON Schema. On `/search`, it has at most 10 properties and 2 nesting levels. On Agent, it supports draft-07, 2019-09, and 2020-12 via `$schema`
- [ ] Agent `effort` is set explicitly based on task scope (medium for standard, auto for variable, ultra for exhaustive)
- [ ] Agent `status` is `completed` before `output` is read
- [ ] `maxItems` bounds list sizes in Agent schemas to control cost
- [ ] Domain filters (`includeDomains`, `excludeDomains`) are used only for hard constraints, not preferences
- [ ] `userIdentifier` is opaque (UUID or hash), not personal information
- [ ] Response includes `requestId` for support troubleshooting
- [ ] Warnings are logged; notices are passed to models (not warnings)

## Resources

**Comprehensive page listing**: https://exa.ai/docs/llms.txt

**Critical documentation**:
1. [Search API Quickstart](https://exa.ai/docs/search/quickstart) — Core search request shapes, filters, output options
2. [Agent API Quickstart](https://exa.ai/docs/agent/quickstart) — Async research, list-building, structured output, streaming
3. [Search Best Practices](https://exa.ai/docs/search/best-practices) — Query tuning, latency budgets, common mistakes, decision tables

---

> For additional documentation and navigation, see: https://exa.ai/docs/llms.txt
