exa
Search, extract content, and get AI-generated context using the Exa API. Use for web search, page content extraction, structured websets, and code-aware context retrieval.
SKILL.mdpkgs/by-name/exa-cli/skills/exa/SKILL.md
GitHubSearch and extract using the Exa AI API.
Prerequisites
EXA_API_KEYenvironment variable with a valid Exa API key
Check before use:
[ -z "$EXA_API_KEY" ] && echo "Error: EXA_API_KEY not set" || echo "OK: EXA_API_KEY is set"
Note: Never hardcode EXA_API_KEY. Always use the environment variable.
Subcommands
| Command | Description |
|---|---|
exa search |
Neural search over the web |
exa contents |
Extract text, highlights, or summaries from URLs |
exa context |
Get AI-generated context for a query |
exa websets |
Manage Exa websets (create, get, list, items, delete, wait, cancel) |
Output Modes
| Flag | Value | Output format | Use case |
|---|---|---|---|
--output |
json (default) |
JSON (pretty) | Programmatic use, saving to file |
--output |
compact |
JSON (no whitespace) | Piping to jaq |
--output |
text |
Human-readable formatted output | Quick review of results |
The --output flag accepts one of json, compact, or text.
search
exa search [OPTIONS] QUERY
| Flag | API param | Description |
|---|---|---|
--type |
type |
auto, fast, instant, deep-lite, deep, deep-reasoning |
--num-results N |
numResults |
Max results (default 10) |
--category |
category |
Category filter (news, company, research paper, …) |
--include-domains DOMAIN |
includeDomains |
Restrict to domain; repeatable |
--exclude-domains DOMAIN |
excludeDomains |
Exclude domain; repeatable |
--start-published-date DATE |
startPublishedDate |
YYYY-MM-DD or ISO 8601 |
--end-published-date DATE |
endPublishedDate |
YYYY-MM-DD or ISO 8601 |
--moderation LEVEL |
moderation |
Moderation level |
--highlights |
contents.highlights |
Include key excerpts |
--summary |
contents.summary |
Include LLM-generated summary |
--text |
contents.text |
Include full page text |
--max-characters N |
contents.text.maxCharacters |
Max characters per text result |
--max-age-hours H |
contents.maxAgeHours |
Max age of cached content (0 = force livecrawl) |
--timeout SEC |
(client) | Request timeout (default 60) |
Important: On /search, content params (--highlights, --summary, --text) are nested under contents in the API body. The CLI handles this automatically.
Response (JSON)
{
"requestId": "...",
"searchType": "auto",
"results": [
{
"title": "Page Title",
"url": "https://example.com",
"id": "https://example.com",
"publishedDate": "2024-01-15T00:00:00.000Z",
"text": "Full page content (if --text)...",
"highlights": ["Key excerpt..."],
"summary": "LLM-generated summary (if --summary)..."
}
],
"costDollars": { "total": 0.007 }
}
Examples
# Basic search with highlights (recommended default)
exa search --highlights "recent breakthroughs in quantum computing"
# Domain-filtered news
exa search --highlights --category news \
--include-domains reuters.com --include-domains bbc.com \
--start-published-date 2025-01-01 \
"AI regulation policy updates"
# Deep search with structured output via jaq
exa search --output=compact --type deep "compare latest frontier AI models" | jaq '.results[].title'
# Human-readable review
exa search --output=text --highlights --num-results 5 "python asyncio patterns"
contents
exa contents [OPTIONS] URL [URL ...]
| Flag | API param | Description |
|---|---|---|
--text |
text |
Include full page text |
--highlights |
highlights |
Include key excerpts |
--summary |
summary |
Include LLM-generated summary |
--max-age-hours H |
maxAgeHours |
Max age of cached content |
--livecrawl-timeout MS |
livecrawlTimeout |
Livecrawl timeout in milliseconds |
--timeout SEC |
(client) | Request timeout (default 60) |
Important: On /contents, content params (--text, --highlights, --summary) are top-level in the API body (NOT nested under contents). This differs from /search. The CLI handles this automatically.
Examples
# Extract highlights from a URL
exa contents --highlights https://example.com/article
# Full text extraction
exa contents --text https://example.com/docs
# Multiple URLs at once
exa contents --highlights https://a.com https://b.com
# Compact JSON for piping
exa contents --output=compact --highlights https://example.com | jaq '.results[].highlights[]'
context
exa context [OPTIONS] QUERY
| Flag | API param | Description |
|---|---|---|
--tokens N |
tokensNum |
Token budget: integer or "dynamic" (default: dynamic) |
--timeout SEC |
(client) | Request timeout (default 60) |
Examples
# Default (dynamic token budget)
exa context "react hooks useEffect cleanup"
# Fixed token budget
exa context --tokens 2000 "nix flake overlay pattern"
# Human-readable output
exa context --output=text "python dataclass vs pydantic model"
websets
exa websets SUBCOMMAND [OPTIONS]
| Subcommand | Description |
|---|---|
create |
Create a webset |
get |
Get a webset by ID |
list |
List all websets |
items |
List items in a webset |
delete |
Delete a webset (requires --force) |
wait |
Poll until webset status is idle |
cancel |
Cancel running webset operations |
create
exa websets create [PAYLOAD_JSON | --file FILE]
# Create from inline JSON
exa websets create '{"search":{"query":"AI companies in Europe","count":10}}'
# Create from file
exa websets create --file webset-config.json
# Create with enrichments
exa websets create '{
"search": {"query": "AI startups Series A", "count": 20},
"enrichments": [
{"description": "CEO name", "format": "text"},
{"description": "Funding amount", "format": "text"}
]
}'
# Create and wait until idle
exa websets create '...' && exa websets wait <ID>
get
exa websets get [--expand items] ID
list
exa websets list [--cursor CURSOR] [--limit N]
items
exa websets items [--cursor CURSOR] [--limit N] WEBSET_ID
delete
exa websets delete --force ID
wait
exa websets wait [--timeout SEC] [--interval SEC] ID
Polls GET /websets/{id} until status == "idle". Default: 300s timeout, 2s interval.
cancel
exa websets cancel ID
Error Handling
| HTTP Status | Meaning | Action |
|---|---|---|
400 |
Bad request — invalid parameters | Check flags and parameter types |
401 |
Invalid or missing API key | Verify EXA_API_KEY is set and valid |
422 |
Validation error | Check parameter types and constraints |
429 |
Rate limit exceeded | Wait and retry with exponential backoff |
500 |
Internal server error | Retry later |
Exit codes: 0 = success, 1 = error, 124 = timeout, 130 = interrupt.
Best Practices
Use
--highlightsover--textfor agent workflows. Highlights return 10x fewer tokens with the most relevant excerpts.--type autois almost always the right search type. Only usefast/instantwhen latency matters more than quality. Usedeepvariants for complex multi-step queries.--max-age-hours 0forces livecrawl. This increases latency. Omit for the default (livecrawl only when no cache exists).Category filters disable some options.
companyandpeoplecategories do not support--exclude-domainsor date filters. Using them returns a 400 error.Websets are asynchronous. Use
exa websets wait <ID>after creating a webset to block until results are ready.Cache responses. Search results for stable topics can be reused for the duration of a session.
Pipe through
jaqfor custom filtering. Use--output=compactfor efficient JSON processing.
Common Mistakes to Avoid
| Wrong | Correct |
|---|---|
useAutoprompt: true |
Remove it. Deprecated and does nothing. |
includeUrls / excludeUrls |
Use --include-domains / --exclude-domains. No URL-level filters exist. |
--text nesting on /contents |
The CLI handles nesting automatically. On /search content params nest under contents; on /contents they are top-level. |
--max-age-hours 0 always |
Omit unless you specifically need fresh livecrawl results. |