@exalabs/convex-exa
v0.1.0
Published
Convex component for web search and content extraction with Exa
Readme
convex-exa
Web search and content extraction for Convex applications. Search the web, pull clean page content, and return structured answers.
Quick Start
1. Install the Component
npm install @exalabs/convex-exa zodzod is required when you pass a Zod schema to deepSearch.
2. Configure Convex
Add the component to your convex/convex.config.ts:
import { defineApp } from "convex/server";
import { v } from "convex/values";
import exa from "@exalabs/convex-exa/convex.config";
const app = defineApp({
env: {
EXA_API_KEY: v.string(),
},
});
app.use(exa, {
name: "exa",
env: {
EXA_API_KEY: app.env.EXA_API_KEY,
},
});
export default app;3. Set Up Environment Variables
Add this to your Convex Dashboard → Settings → Environment Variables:
| Variable | Description |
|----------|-------------|
| EXA_API_KEY | Your Exa API key |
You can also set it from the CLI: npx convex env set EXA_API_KEY <your-key>.
4. Use the Component
import { action } from "./_generated/server";
import { ExaClient } from "@exalabs/convex-exa";
import { components } from "./_generated/api";
import { z } from "zod";
const exa = new ExaClient(components.exa);
export const searchNews = action({
handler: async (ctx) => {
return await exa.search(ctx, {
query: "recent llm launches",
contents: {
highlights: true,
maxAgeHours: 24,
},
});
},
});
export const summarizeFunding = action({
handler: async (ctx) => {
return await exa.deepSearch(ctx, {
query: "recent AI startup funding announcements",
systemPrompt: "Prefer official sources and avoid duplicate reporting.",
schema: z.object({
summary: z.string(),
companies: z.array(z.string()),
}),
});
},
});
export const fetchKnownPage = action({
handler: async (ctx) => {
return await exa.contents(ctx, {
urls: ["https://exa.ai/docs"],
highlights: true,
maxAgeHours: 12,
});
},
});API Reference
search(ctx, args)
Run Exa /search with type: "auto" by default. Use for general retrieval; pass nested contents when you want highlights or text on result URLs.
await exa.search(ctx, {
query: "battery recycling policy changes in the EU",
contents: {
highlights: true,
},
});Parameters:
query- Search querycontents- Optional nested options for text, highlights, summary,maxAgeHours, etc.- Other fields are forwarded to the Exa search API (filters,
numResults,type, etc.)
deepSearch(ctx, args)
Run Exa /search with type: "deep" by default. Use when you want structured or synthesized output.
await exa.deepSearch(ctx, {
query: "Compare recent frontier model launches",
schema: z.object({
summary: z.string(),
models: z.array(z.string()),
}),
});Parameters:
query- Search queryschema- Zod schema for structured output (converted to JSON Schema for Exa)outputSchema- Raw JSON Schema instead of ZodsystemPrompt- Optional guidance for the deep search modeltype- One ofdeep-lite,deep,deep-reasoning
Returns: Exa search response; structured fields follow your schema when provided
contents(ctx, args)
Fetch content for URLs you already know via Exa /contents.
await exa.contents(ctx, {
urls: ["https://exa.ai/docs"],
highlights: true,
maxAgeHours: 12,
});Parameters:
urls- URLs to fetchtext,highlights,summary- Top-level content options (not nested undercontentslike on/search)
Requirements
- Exa account and API key
- Convex 1.39.1 or later
zodwhen using schemas withdeepSearch
How It Works
This component wraps the Exa API inside a Convex component. Your actions call ExaClient, which runs component actions that:
- Read
EXA_API_KEYfrom component environment configuration - Call Exa
/searchor/contentswith your arguments - Return typed results to your Convex action
The API key stays in Convex env—not in client-visible code.
Development
Building the Component
To build the component locally:
# Install dependencies
npm install
cd example && npm install && cd ..
# Build with Convex codegen (generates component API)
npm run build:codegen
# Or just build TypeScript
npm run build:esm
# Run tests
npm testThe component requires a Convex deployment to generate proper component API types (_generated/component.ts).
Example App
Work against a live deployment with the example app:
npm run devThis runs the example Convex backend and rebuilds the component when src/ changes.
See example/README.md for a walkthrough of the example app, which demonstrates:
searchNews: Retrieve general web results based on queries.deepResearch: Perform structured and schema-driven deep search.fetchKnownPage: Extract contents from a specific, known URL.
These example actions highlight key parameters you’ll likely want to adjust in your own application, such as:
- Filtering by domain
- Including or excluding text via text filters
- Setting the number of results to return
- Choosing a search mode
- Selecting a content mode (
highlights,text, orsummary) - Limiting document recency with
maxAgeHours
See the Exa API Docs for full reference on the available parameters and capabilities.
