| name | sdk-patterns |
| description | This skill should be used when the user asks about "Firecrawl SDK", "Exa SDK", "exa-js", "exa-py", "Perplexity SDK", "Jina SDK", "web search client library", "search npm package", "search Python package", or needs code patterns for integrating web search services into a project. |
Web Search Services SDK Patterns
Code patterns for integrating Firecrawl, Exa, Perplexity, and Jina into application code.
Firecrawl
Installation
npm install firecrawl
pip install firecrawl-py
TypeScript
import { Firecrawl } from 'firecrawl';
const firecrawl = new Firecrawl({ apiKey: process.env.FIRECRAWL_API_KEY });
const result = await firecrawl.scrape('https://example.com', {
formats: ['markdown', 'links'],
});
console.log(result.markdown);
const searchResults = await firecrawl.search('Next.js tutorials', { limit: 10 });
const crawl = await firecrawl.crawl('https://docs.example.com', { limit: 50 });
const job = await firecrawl.startCrawl('https://docs.example.com', { limit: 50 });
const status = await firecrawl.getCrawlStatus(job.id);
const map = await firecrawl.map('https://example.com');
const batch = await firecrawl.batchScrape(['https://example.com/a', 'https://example.com/b'], {
options: { formats: ['markdown'] },
});
const extracted = await firecrawl.extract({
urls: ['https://example.com/pricing'],
prompt: 'Extract pricing plans',
schema: { type: 'array', items: { type: 'object', properties: { plan: { type: 'string' }, price: { type: 'string' } } } },
});
v4 also adds interact() / stopInteraction() for live browser-session page manipulation.
Python
from firecrawl import Firecrawl
firecrawl = Firecrawl(api_key=os.environ["FIRECRAWL_API_KEY"])
doc = firecrawl.scrape("https://example.com", formats=["markdown"])
print(doc.markdown)
results = firecrawl.search("Next.js tutorials", limit=10)
crawl = firecrawl.crawl("https://docs.example.com", limit=50)
Exa
Installation
npm install exa-js
pip install exa-py
TypeScript
import Exa from 'exa-js';
const exa = new Exa(process.env.EXA_API_KEY);
const results = await exa.search('React hooks best practices', {
numResults: 10,
type: 'auto',
});
const withContent = await exa.search('Prisma ORM examples', {
numResults: 5,
contents: {
text: { maxCharacters: 5000 },
highlights: { maxCharacters: 200 },
},
});
const githubResults = await exa.search('authentication middleware', {
numResults: 10,
includeDomains: ['github.com'],
});
const similar = await exa.findSimilar('https://example.com/article', {
numResults: 10,
});
const { answer } = await exa.();
run = exa...({
: ,
: ,
});
finished = exa...(run.);
Python
from exa_py import Exa
exa = Exa(api_key=os.environ["EXA_API_KEY"])
results = exa.search(
"React hooks patterns",
num_results=10,
type="auto"
)
with_content = exa.search(
"Prisma examples",
num_results=5,
contents={"text": {"max_characters": 5000}}
)
Perplexity
Installation
npm install @perplexity-ai/perplexity_ai
pip install perplexityai
TypeScript
import { Perplexity } from '@perplexity-ai/perplexity_ai';
const client = new Perplexity({ apiKey: process.env.PERPLEXITY_API_KEY });
const response = await client.responses.create({
preset: 'low',
input: 'Compare tRPC vs GraphQL for Next.js',
});
const sonarResponse = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{ role: 'user', content: 'What are the latest React 19 features?' },
],
});
const searchResults = await client.search.create({
query: 'React 19 new features',
max_results: 5,
});
Python
from perplexity import Perplexity
client = Perplexity()
response = client.responses.create(
preset="low",
input="Compare tRPC vs GraphQL for Next.js"
)
sonar_response = client.chat.completions.create(
model="sonar-pro",
messages=[{"role": "user", "content": "React 19 features"}]
)
search_results = client.search.create(query="React 19 new features", max_results=5)
Jina
Jina's API is HTTP-based — no dedicated SDK package needed. Use fetch or requests directly.
TypeScript
const response = await fetch('https://r.jina.ai/https://nextjs.org/docs', {
headers: { 'Authorization': `Bearer ${process.env.JINA_API_KEY}` },
});
const markdown = await response.text();
const searchResponse = await fetch('https://s.jina.ai/?q=React+hooks', {
headers: {
'Authorization': `Bearer ${process.env.JINA_API_KEY}`,
'Accept': 'application/json',
},
});
const results = await searchResponse.json();
const embedResponse = await fetch('https://api.jina.ai/v1/embeddings', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.JINA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'jina-embeddings-v5-text-small',
input: ['text to embed'],
}),
});
Python
import requests
headers = {"Authorization": f"Bearer {os.environ['JINA_API_KEY']}"}
response = requests.get("https://r.jina.ai/https://example.com", headers=headers)
markdown = response.text
search = requests.get(
"https://s.jina.ai/",
params={"q": "React hooks"},
headers={**headers, "Accept": "application/json"}
)
results = search.json()
rerank = requests.post(
"https://api.jina.ai/v1/rerank",
headers={**headers, "Content-Type": "application/json"},
json={
"model": "jina-reranker-v3.5",
"query": "best database for real-time",
"documents": ["PostgreSQL", "Redis", "MongoDB"]
}
)
Best Practices
- Store API keys in environment variables, never in code
- Handle rate limits with exponential backoff
- Use the appropriate service for each task (see mcp-patterns routing table)
- Prefer SDK methods over raw HTTP when SDK is available
- Use TypeScript types for type safety when integrating search results