Exa Cost Tuning
Overview
Reduce Exa API costs through strategic search type selection, result caching, query deduplication, and usage monitoring. Exa charges per search request with costs varying by search type and content retrieval options.
Cost Drivers
| Factor | Higher Cost | Lower Cost |
|---|
| Search type | deep-reasoning > deep > neural | keyword < fast < instant |
| numResults | 10-100 results | 3-5 results |
| Content retrieval | Full text + highlights + summary | Metadata only (no content) |
| Content length | maxCharacters: 5000 | maxCharacters: 500 |
| Live crawling | livecrawl: "always" | Cached content (default) |
Instructions
Step 1: Match Search Config to Use Case
import Exa from "exa-js";
const exa = new Exa(process.env.EXA_API_KEY);
const SEARCH_PROFILES = {
"autocomplete": { type: "instant" as const, numResults: 3 },
"quick-lookup": { type: "fast" as const, numResults: 3 },
"rag-context": {
type: "auto" as const,
numResults: 5,
text: { maxCharacters: 1000 },
},
"deep-research": {
type: "neural" as const,
numResults: 10,
text: { maxCharacters: 3000 },
highlights: { maxCharacters: 500 },
},
};
async function costAwareSearch(
query: string,
profile: keyof typeof SEARCH_PROFILES
) {
const config = SEARCH_PROFILES[profile];
if ("text" in config || "highlights" in config) {
return exa.searchAndContents(query, config);
}
return exa.search(query, config);
}
Step 2: Query-Level Caching (40-60% Cost Reduction)
import { LRUCache } from "lru-cache";
const searchCache = new LRUCache<string, any>({
max: 5000,
ttl: 3600 * 1000,
});
async function cachedSearch(query: string, opts: any) {
const key = `${query.toLowerCase().trim()}:${opts.type}:${opts.numResults}`;
const cached = searchCache.get(key);
if (cached) return cached;
const results = await exa.searchAndContents(query, opts);
searchCache.set(key, results);
return results;
}
Step 3: Query Deduplication for Batch Jobs
function deduplicateQueries(queries: string[]): string[] {
const seen = new Set<string>();
return queries.filter(q => {
const normalized = q.toLowerCase().trim().replace(/\s+/g, " ");
if (seen.has(normalized)) return false;
seen.add(normalized);
return true;
});
}
const uniqueQueries = deduplicateQueries(allQueries);
console.log(`Deduped: ${allQueries.length} → ${uniqueQueries.length} queries`);
Step 4: Use Keyword Search When Appropriate
function selectCostEffectiveType(query: string): "neural" | "keyword" | "auto" {
if (query.match(/^https?:\/\//)) return "keyword";
if (query.match(/^[A-Z][a-z]+ [A-Z]/)) return "keyword";
if (query.includes('"')) return "keyword";
if (query.split(" ").length > 5) return "neural";
return "auto";
}
Step 5: Monitor Usage and Set Budget Alerts
set -euo pipefail
curl -s https://api.exa.ai/v1/usage \
-H "x-api-key: $EXA_API_KEY" | \
python3 -c "
import json, sys
d = json.load(sys.stdin)
print(f'Searches today: {d.get(\"searches_today\", \"N/A\")}')
print(f'Monthly total: {d.get(\"searches_this_month\", \"N/A\")}')
print(f'Monthly limit: {d.get(\"monthly_limit\", \"N/A\")}')
" 2>/dev/null || echo "Usage endpoint not available"
class ExaBudgetTracker {
private searchCount = 0;
private dailyLimit: number;
constructor(dailyLimit = 1000) {
this.dailyLimit = dailyLimit;
}
async search(exa: Exa, query: string, opts: any) {
if (this.searchCount >= this.dailyLimit) {
throw new Error(`Daily Exa budget exceeded (${this.dailyLimit} searches)`);
}
this.searchCount++;
return exa.search(query, opts);
}
getUsage() {
return {
used: this.searchCount,
remaining: this.dailyLimit - this.searchCount,
utilization: `${((this.searchCount / .dailyLimit) * ).toFixed()}%`,
};
}
}
Cost Optimization Checklist
Error Handling
| Issue | Cause | Solution |
|---|
| Monthly limit hit early | Uncached batch queries | Add caching (40%+ savings) |
| High cost per result | numResults too high | Reduce to 3-5 for most use cases |
| Budget spike from batch | No deduplication | Deduplicate before batch execution |
402 NO_MORE_CREDITS | Account balance exhausted | Top up at dashboard.exa.ai |
Resources
Next Steps
For performance optimization, see exa-performance-tuning. For reliability, see exa-reliability-patterns.