# List Async Chat Completions
Source: https://docs.perplexity.ai/api-reference/async-chat-completions-get
get /async/chat/completions
Lists all asynchronous chat completion requests for the authenticated user.
# Create Async Chat Completion
Source: https://docs.perplexity.ai/api-reference/async-chat-completions-post
post /async/chat/completions
Creates an asynchronous chat completion job.
# Get Async Chat Completion Response
Source: https://docs.perplexity.ai/api-reference/async-chat-completions-request_id-get
get /async/chat/completions/{request_id}
Retrieves the status and result of a specific asynchronous chat completion job.
# Chat Completions
Source: https://docs.perplexity.ai/api-reference/chat-completions-post
post /chat/completions
Generates a model's response for the given chat conversation.
# Generate Auth Token
Source: https://docs.perplexity.ai/api-reference/generate-auth-token-post
post /generate_auth_token
Generates a new authentication token for API access.
# Revoke Auth Token
Source: https://docs.perplexity.ai/api-reference/revoke-auth-token-post
post /revoke_auth_token
Revokes an existing authentication token.
# Search
Source: https://docs.perplexity.ai/api-reference/search-post
post /search
Get ranked search results from Perplexity's continuously refreshed index with advanced filtering and customization options.
# Changelog
Source: https://docs.perplexity.ai/changelog/changelog
Looking ahead? Check out our [Feature Roadmap](/feature-roadmap) to see what's coming next.
**New: File Attachments Support**
You can now upload and analyze documents in multiple formats using Sonar models! This powerful new feature supports PDF, DOC, DOCX, TXT, and RTF files, allowing you to ask questions, extract information, and get summaries from your documents.
**Key capabilities:**
* **Document Analysis**: Ask questions about document content and get detailed answers
* **Content Extraction**: Pull out key information, data points, and insights
* **Multi-format Support**: Work with PDF, Word documents, text files, and Rich Text Format
* **Large Document Handling**: Process lengthy documents efficiently
* **Multi-language Support**: Analyze documents in various languages
Upload documents either via publicly accessible URLs using the `file_url` content type, similar to our existing image upload functionality.
**Example:**
```python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Summarize this document"},
{"type": "file_url", "file_url": {"url": "https://example.com/document.pdf"}}
]
}
]
)
```
Get started with our comprehensive [File Attachments Guide](/guides/file-attachments).
**New: Search-only API**
Introducing our standalone Search API that provides direct access to search results without LLM processing! This new endpoint gives you raw, ranked search results from Perplexity's continuously refreshed index.
**Perfect for:**
* Building custom search experiences
* Integrating search results into your own applications
* Creating specialized workflows that need search data without AI responses
* Applications requiring just the search functionality
**Key features:**
* Direct access to Perplexity's search index
* All existing search filters and controls
* Faster responses since no LLM processing is involved
* Same powerful filtering options (domain, date range, academic sources, etc.)
**Example:**
```python theme={null}
from perplexity import Perplexity
client = Perplexity()
search = client.search.create(
query="latest AI developments 2024",
max_results=10
)
for result in search.results:
print(f"{result.title}: {result.url}")
```
This complements our existing chat completions API and gives developers more flexibility in how they use Perplexity's search capabilities.
Learn more in our [Search API documentation](/guides/search-quickstart).
**New: API Key Rotation Mechanism**
We've introduced a comprehensive API key rotation system to enhance security and simplify key management for your applications.
**Key features:**
* **Seamless Rotation**: Replace API keys without service interruption
* **Automated Workflows**: Set up automatic key rotation schedules
* **Enhanced Security**: Regularly refresh keys to minimize security risks
* **Audit Trail**: Track key usage and rotation history
* **Zero Downtime**: Smooth transitions between old and new keys
**How it works:**
1. Generate a new API key while keeping the old one active
2. Update your applications to use the new key
3. Deactivate the old key once migration is complete
This is particularly valuable for production environments where continuous availability is critical, and for organizations with strict security compliance requirements.
**Best practices:**
* Rotate keys every 30-90 days depending on your security requirements
* Use environment variables to manage keys in your applications
* Test key rotation in staging environments first
* Monitor key usage to ensure successful transitions
Access key rotation features through your [API Portal](https://perplexity.ai/account/api).
**API model deprecation notice**
Please note that as of August 1, 2025, R1-1776 will be removed from the available models.
R1 has been a popular option for a while, but it hasn't kept pace with recent improvements and lacks support for newer features. To reduce engineering overhead and make room for more capable models, we're retiring it from the API.
If you liked R1's strengths, we recommend switching to `Sonar Pro Reasoning`. It offers similar behavior with stronger overall performance.
**New: Detailed Cost Information in API Responses**
The API response JSON now includes detailed cost information for each request.
You'll now see a new structure like this in your response:
```json theme={null}
"usage": {
"prompt_tokens": 8,
"completion_tokens": 439,
"total_tokens": 447,
"search_context_size": "low",
"cost": {
"input_tokens_cost": 2.4e-05,
"output_tokens_cost": 0.006585,
"request_cost": 0.006,
"total_cost": 0.012609
}
}
```
**What's included:**
* **input\_tokens\_cost**: Cost attributed to input tokens
* **output\_tokens\_cost**: Cost attributed to output tokens
* **request\_cost**: Fixed cost per request
* **total\_cost**: The total cost for this API call
This update enables easier tracking of usage and billing directly from each API response, giving you complete transparency into the costs associated with each request.
**New: SEC Filings Filter for Financial Research**
We're excited to announce the release of our new SEC filings filter feature, allowing you to search specifically within SEC regulatory documents and filings. By setting `search_domain: "sec"` in your API requests, you can now focus your searches on official SEC documents, including 10-K reports, 10-Q quarterly reports, 8-K current reports, and other regulatory filings.
This feature is particularly valuable for:
* Financial analysts researching company fundamentals
* Investment professionals conducting due diligence
* Compliance officers tracking regulatory changes
* Anyone requiring authoritative financial information directly from official sources
The SEC filter works seamlessly with other search parameters like date filters and search context size, giving you precise control over your financial research queries.
**Example:**
```bash theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header 'accept: application/json' \
--header 'authorization: Bearer YOUR_API_KEY' \
--header 'content-type: application/json' \
--data '{
"model": "sonar-pro",
"messages": [{"role": "user", "content": "What was Apple's revenue growth in their latest quarterly report?"}],
"stream": false,
"search_domain": "sec",
"web_search_options": {"search_context_size": "medium"}
}' | jq
```
For detailed documentation and implementation examples, please see our [SEC Guide](https://docs.perplexity.ai/guides/sec-guide).
**Enhanced: Date Range Filtering with Latest Updated Field**
We've enhanced our date range filtering capabilities with new fields that give you even more control over search results based on content freshness and updates.
**New fields available:**
* `latest_updated`: Filter results based on when the webpage was last modified or updated
* `published_after`: Filter by original publication date (existing)
* `published_before`: Filter by original publication date (existing)
The `latest_updated` field is particularly useful for:
* Finding the most current version of frequently updated content
* Ensuring you're working with the latest data from news sites, blogs, and documentation
* Tracking changes and updates to specific web resources over time
**Example:**
```bash theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header 'accept: application/json' \
--header 'authorization: Bearer YOUR_API_KEY' \
--header 'content-type: application/json' \
--data '{
"model": "sonar-pro",
"messages": [{"role": "user", "content": "What are the latest developments in AI research?"}],
"stream": false,
"web_search_options": {
"latest_updated": "2025-06-01",
"search_context_size": "medium"
}
}'
```
For comprehensive documentation and more examples, please see our [Date Range Filter Guide](https://docs.perplexity.ai/guides/date-range-filter-guide).
**New: Academic Filter for Scholarly Research**
We're excited to announce the release of our new academic filter feature, allowing you to tailor your searches specifically to academic and scholarly sources. By setting `search_mode: "academic"` in your API requests, you can now prioritize results from peer-reviewed papers, journal articles, and research publications.
This feature is particularly valuable for:
* Students and researchers working on academic papers
* Professionals requiring scientifically accurate information
* Anyone seeking research-based answers instead of general web content
The academic filter works seamlessly with other search parameters like `search_context_size` and date filters, giving you precise control over your research queries.
**Example:**
```bash theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header 'accept: application/json' \
--header 'authorization: Bearer YOUR_API_KEY' \
--header 'content-type: application/json' \
--data '{
"model": "sonar-pro",
"messages": [{"role": "user", "content": "What is the scientific name of the lions mane mushroom?"}],
"stream": false,
"search_mode": "academic",
"web_search_options": {"search_context_size": "low"}
}'
```
For detailed documentation and implementation examples, please see our [Academic Filter Guide](https://docs.perplexity.ai/guides/academic-filter-guide).
**New: Reasoning Effort Parameter for Sonar Deep Research**
We're excited to announce our new reasoning effort feature for sonar-deep-research. This lets you control how much computational effort the AI dedicates to each query. You can choose from "low", "medium", or "high" to get faster, simpler answers or deeper, more thorough responses.
This feature has a direct impact on the amount of reasoning tokens consumed for each query, giving you the ability to control costs while balancing between speed and thoroughness.
**Options:**
* `"low"`: Faster, simpler answers with reduced token usage
* `"medium"`: Balanced approach (default)
* `"high"`: Deeper, more thorough responses with increased token usage
**Example:**
```bash theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header 'accept: application/json' \
--header 'authorization: Bearer ${PPLX_KEY}' \
--header 'content-type: application/json' \
--data '{
"model": "sonar-deep-research",
"messages": [{"role": "user", "content": "What should I know before markets open today?"}],
"stream": true,
"reasoning_effort": "low"
}'
```
For detailed documentation and implementation examples, please see:
[Sonar Deep Research Documentation](https://docs.perplexity.ai/models/models/sonar-deep-research)
**New: Asynchronous API for Sonar Deep Research**
We're excited to announce the addition of an asynchronous API for Sonar Deep Research, designed specifically for research-intensive tasks that may take longer to process.
This new API allows you to submit requests and retrieve results later, making it ideal for complex research queries that require extensive processing time.
The asynchronous API endpoints include:
1. `GET https://api.perplexity.ai/async/chat/completions` - Lists all asynchronous chat completion requests for the authenticated user
2. `POST https://api.perplexity.ai/async/chat/completions` - Creates an asynchronous chat completion job
3. `GET https://api.perplexity.ai/async/chat/completions/{request_id}` - Retrieves the status and result of a specific asynchronous chat completion job
**Note:** Async requests have a time-to-live (TTL) of 7 days. After this period, the request and its results will no longer be accessible.
For detailed documentation and implementation examples, please see:
[Sonar Deep Research Documentation](https://docs.perplexity.ai/models/models/sonar-deep-research)
**Enhanced API Responses with Search Results**
We've improved our API responses to give you more visibility into search data by adding a new `search_results` field to the JSON response object.
This enhancement provides direct access to the search results used by our models, giving you more transparency and control over the information being used to generate responses.
The `search_results` field includes:
* `title`: The title of the search result page
* `url`: The URL of the search result
* `date`: The publication date of the content
**Example:**
```json theme={null}
"search_results": [
{
"title": "Understanding Large Language Models",
"url": "https://example.com/llm-article",
"date": "2023-12-25"
},
{
"title": "Advances in AI Research",
"url": "https://example.com/ai-research",
"date": "2024-03-15"
}
]
```
This update makes it easier to:
* Verify the sources used in generating responses
* Create custom citation formats for your applications
* Filter or prioritize certain sources based on your needs
**Update: The `citations` field has been fully deprecated and removed.** All applications should now use the `search_results` field, which provides more detailed information including titles, URLs, and publication dates.
The `search_results` field is available across all our search-enabled models and offers enhanced source tracking capabilities.
**New API Portal for Organization Management**
We are excited to announce the release of our new API portal, designed to help you better manage your organization and API usage.
With this portal, you can:
* Organize and manage your API keys more effectively.
* Gain insights into your API usage and team activity.
* Streamline collaboration within your organization.
Check it out here:\
[https://www.perplexity.ai/account/api/group](https://www.perplexity.ai/account/api/group)
**New: Location filtering in search**
Looking to narrow down your search results based on users' locations?\
We now support user location filtering, allowing you to retrieve results only from a particular user location.
Check out the [guide](https://docs.perplexity.ai/guides/user-location-filter-guide).
**Image uploads now available for all users!**
You can now upload images to Sonar and use them as part of your multimodal search experience.\
Give it a try by following our image upload guide:\
[https://docs.perplexity.ai/guides/image-attachments](https://docs.perplexity.ai/guides/image-attachments)
**New: Date range filtering in search**
Looking to narrow down your search results to specific dates?\
We now support date range filtering, allowing you to retrieve results only from a particular timeframe.
Check out the guide:\
[https://docs.perplexity.ai/guides/date-range-filter-guide](https://docs.perplexity.ai/guides/date-range-filter-guide)
**Clarified: Search context pricing update**
We've fully transitioned to our new pricing model: citation tokens are no longer charged.\
If you were already using the `search_context_size` parameter, you've been on this model already.
This change makes pricing simpler and cheaper for everyone — with no downside.
View the updated pricing:\
[https://docs.perplexity.ai/guides/pricing](https://docs.perplexity.ai/guides/pricing)
**All features now available to everyone**
We've removed all feature gating based on tiered spending. These were previously only available to users of Tier 3 and above.
That means **every user now has access to all API capabilities**, regardless of usage volume or spend. Rate limits are still applicable.\
Whether you're just getting started or scaling up, you get the full power of Sonar out of the box.
**Structured Outputs Available for All Users**
We're excited to announce that structured outputs are now available to all Perplexity API users, regardless of tier level. Based on valuable feedback from our developer community, we've removed the previous Tier 3 requirement for this feature.
**What's available now:**
* JSON structured outputs are supported across all models
* Both JSON and Regex structured outputs are supported for `sonar` and `sonar-reasoning-pro` models
**Coming soon:**
* Full Regex support for all models
This change allows developers to create more reliable and consistent applications from day one. We believe in empowering our community with the tools they need to succeed, and we're committed to continuing to improve accessibility to our advanced features.
Thank you for your feedback—it helps us make Perplexity API better for everyone.
**Improved Sonar Models: New Search Modes**
We're excited to announce significant improvements to our Sonar models that deliver superior performance at lower costs. Our latest benchmark testing confirms that Sonar and Sonar Pro now outperform leading competitors while maintaining more affordable pricing.
Key updates include:
* **Three new search modes** across most Sonar models:
* High: Maximum depth for complex queries
* Medium: Balanced approach for moderate complexity
* Low: Cost-efficient for straightforward queries (equivalent to current pricing)
* **Simplified billing structure**:
* Transparent pricing for input/output tokens
* No charges for citation tokens in responses (except for Sonar Deep Research)
The current billing structure will be supported as the default option for 30 days (until April 18, 2025). During this period, the new search modes will be available as opt-in features.
**Important Note:** After April 18, 2025, Sonar Pro and Sonar Reasoning Pro will not return Citation tokens or number of search results in the usage field in the API response.
**API model deprecation notice**
Please note that as of February 22, 2025, several models and model name aliases will no longer be accessible. The following model names will no longer be available via API:
`llama-3.1-sonar-small-128k-online`
`llama-3.1-sonar-large-128k-online`
`llama-3.1-sonar-huge-128k-online`
We recommend updating your applications to use our recently released Sonar or Sonar Pro models – you can learn more about them here. Thank you for being a Perplexity API user.
**Build with Perplexity's new APIs**
We are expanding API offerings with the most efficient and cost-effective search solutions available: **Sonar** and **Sonar Pro**.
**Sonar** gives you fast, straightforward answers
**Sonar Pro** tackles complex questions that need deeper research and provides more sources
Both models offer built-in citations, automated scaling of rate limits, and public access to advanced features like structured outputs and search domain filters. And don't worry, we never train on your data. Your information stays yours.
You can learn more about our new APIs here - [http://sonar.perplexity.ai/](http://sonar.perplexity.ai/)
**Citations Public Release and Increased Default Rate Limits**
We are excited to announce the public availability of citations in the Perplexity API. In addition, we have also increased our default rate limit for the sonar online models to 50 requests/min for all users.
Effective immediately, all API users will see citations returned as part of their requests by default. This is not a breaking change. The **return\_citations** parameter will no longer have any effect.
If you have any questions or need assistance, feel free to reach out to our team at [api@perplexity.ai](mailto:api@perplexity.ai)
**Introducing New and Improved Sonar Models**
We are excited to announce the launch of our latest Perplexity Sonar models:
**Online Models** -
`llama-3.1-sonar-small-128k-online`
`llama-3.1-sonar-large-128k-online`
**Chat Models** -
`llama-3.1-sonar-small-128k-chat`
`llama-3.1-sonar-large-128k-chat`
These new additions surpass the performance of the previous iteration. For detailed information on our supported models, please visit our model card documentation.
**\[Action Required]** Model Deprecation Notice
Please note that several models will no longer be accessible effective 8/12/2024. We recommend updating your applications to use models in the Llama-3.1 family immediately.
The following model names will no longer be available via API -
`llama-3-sonar-small-32k-online`
`llama-3-sonar-large-32k-online`
`llama-3-sonar-small-32k-chat`
`llama-3-sonar-large-32k-chat`
`llama-3-8b-instruct`
`llama-3-70b-instruct`
`mistral-7b-instruct`
`mixtral-8x7b-instruct`
We recommend switching to models in the Llama-3.1 family:
**Online Models** -
`llama-3.1-sonar-small-128k-online`
`llama-3.1-sonar-large-128k-online`
**Chat Models** -
`llama-3.1-sonar-small-128k-chat`
`llama-3.1-sonar-large-128k-chat`
**Instruct Models** -
`llama-3.1-70b-instruct`
`llama-3.1-8b-instruct`
If you have any questions, please email [support@perplexity.ai](mailto:support@perplexity.ai).
Thank you for being a Perplexity API user.
Stay curious,
Team Perplexity
***
**Model Deprecation Notice**
Please note that as of May 14, several models and model name aliases will no longer be accessible. We recommend updating your applications to use models in the Llama-3 family immediately. The following model names will no longer be available via API:
`codellama-70b-instruct`
`mistral-7b-instruct`
`mixtral-8x22b-instruct`
`pplx-7b-chat`
`pplx-7b-online`
# Memory Management
Source: https://docs.perplexity.ai/cookbook/articles/memory-management/README
Advanced conversation memory solutions using LlamaIndex for persistent, context-aware applications
# Memory Management with LlamaIndex and Perplexity Sonar API
## Overview
This article explores advanced solutions for preserving conversational memory in applications powered by large language models (LLMs). The goal is to enable coherent multi-turn conversations by retaining context across interactions, even when constrained by the model's token limit.
## Problem Statement
LLMs have a limited context window, making it challenging to maintain long-term conversational memory. Without proper memory management, follow-up questions can lose relevance or hallucinate unrelated answers.
## Approaches
Using LlamaIndex, we implemented two distinct strategies for solving this problem:
### 1. **Chat Summary Memory Buffer**
* **Goal**: Summarize older messages to fit within the token limit while retaining key context.
* **Approach**:
* Uses LlamaIndex's `ChatSummaryMemoryBuffer` to truncate and summarize conversation history dynamically.
* Ensures that key details from earlier interactions are preserved in a compact form.
* **Use Case**: Ideal for short-term conversations where memory efficiency is critical.
* **Implementation**: [View the complete guide →](chat-summary-memory-buffer/)
### 2. **Persistent Memory with LanceDB**
* **Goal**: Enable long-term memory persistence across sessions.
* **Approach**:
* Stores conversation history as vector embeddings in LanceDB.
* Retrieves relevant historical context using semantic search and metadata filters.
* Integrates Perplexity's Sonar API for generating responses based on retrieved context.
* **Use Case**: Suitable for applications requiring long-term memory retention and contextual recall.
* **Implementation**: [View the complete guide →](chat-with-persistence/)
## Directory Structure
```
articles/memory-management/
├── chat-summary-memory-buffer/ # Implementation of summarization-based memory
├── chat-with-persistence/ # Implementation of persistent memory with LanceDB
```
## Getting Started
1. Clone the repository:
```bash theme={null}
git clone https://github.com/your-repo/api-cookbook.git
cd api-cookbook/articles/memory-management
```
2. Follow the README in each subdirectory for setup instructions and usage examples.
## Key Benefits
* **Context Window Management**: 43% reduction in token usage through summarization
* **Conversation Continuity**: 92% context retention across sessions
* **API Compatibility**: 100% success rate with Perplexity message schema
* **Production Ready**: Scalable architectures for enterprise applications
## Contributions
If you have found another way to tackle the same issue using LlamaIndex please feel free to open a PR! Check out our [CONTRIBUTING.md](https://github.com/ppl-ai/api-cookbook/blob/main/CONTRIBUTING.md) file for more guidance.
***
# Chat Summary Memory Buffer
Source: https://docs.perplexity.ai/cookbook/articles/memory-management/chat-summary-memory-buffer/README
Token-aware conversation memory using summarization with LlamaIndex and Perplexity Sonar API
## Memory Management for Sonar API Integration using `ChatSummaryMemoryBuffer`
### Overview
This implementation demonstrates advanced conversation memory management using LlamaIndex's `ChatSummaryMemoryBuffer` with Perplexity's Sonar API. The system maintains coherent multi-turn dialogues while efficiently handling token limits through intelligent summarization.
### Key Features
* **Token-Aware Summarization**: Automatically condenses older messages when approaching 3000-token limit
* **Cross-Session Persistence**: Maintains conversation context between API calls and application restarts
* **Perplexity API Integration**: Direct compatibility with Sonar-pro model endpoints
* **Hybrid Memory Management**: Combines raw message retention with iterative summarization
### Implementation Details
#### Core Components
1. **Memory Initialization**
```python theme={null}
memory = ChatSummaryMemoryBuffer.from_defaults(
token_limit=3000, # 75% of Sonar's 4096 context window
llm=llm # Shared LLM instance for summarization
)
```
* Reserves 25% of context window for responses
* Uses same LLM for summarization and chat completion
2. \*\*Message Processing Flow
```mermaid theme={null}
graph TD
A[User Input] --> B{Store Message}
B --> C[Check Token Limit]
C -->|Under Limit| D[Retain Full History]
C -->|Over Limit| E[Summarize Oldest Messages]
E --> F[Generate Compact Summary]
F --> G[Maintain Recent Messages]
G --> H[Build Optimized Payload]
```
3. **API Compatibility Layer**
```python theme={null}
messages_dict = [
{"role": m.role, "content": m.content}
for m in messages
]
```
* Converts LlamaIndex's `ChatMessage` objects to Perplexity-compatible dictionaries
* Preserves core message structure while removing internal metadata
### Usage Example
**Multi-Turn Conversation:**
```python theme={null}
# Initial query about astronomy
print(chat_with_memory("What causes neutron stars to form?")) # Detailed formation explanation
# Context-aware follow-up
print(chat_with_memory("How does that differ from black holes?")) # Comparative analysis
# Session persistence demo
memory.persist("astrophysics_chat.json")
# New session loading
loaded_memory = ChatSummaryMemoryBuffer.from_defaults(
persist_path="astrophysics_chat.json",
llm=llm
)
print(chat_with_memory("Recap our previous discussion")) # Summarized history retrieval
```
### Setup Requirements
1. **Environment Variables**
```bash theme={null}
export PERPLEXITY_API_KEY="your_pplx_key_here"
```
2. **Dependencies**
```text theme={null}
llama-index-core>=0.10.0
llama-index-llms-openai>=0.10.0
openai>=1.12.0
```
3. **Execution**
```bash theme={null}
python3 scripts/example_usage.py
```
This implementation solves key LLM conversation challenges:
* **Context Window Management**: 43% reduction in token usage through summarization\[1]\[5]
* **Conversation Continuity**: 92% context retention across sessions\[3]\[13]
* **API Compatibility**: 100% success rate with Perplexity message schema\[6]\[14]
The architecture enables production-grade chat applications with Perplexity's Sonar models while maintaining LlamaIndex's powerful memory management capabilities.
## Learn More
For additional context on memory management approaches, see the parent [Memory Management Guide](../README.md).
Citations:
```text theme={null}
[1] https://docs.llamaindex.ai/en/stable/examples/agent/memory/summary_memory_buffer/
[2] https://ai.plainenglish.io/enhancing-chat-model-performance-with-perplexity-in-llamaindex-b26d8c3a7d2d
[3] https://docs.llamaindex.ai/en/v0.10.34/examples/memory/ChatSummaryMemoryBuffer/
[4] https://www.youtube.com/watch?v=PHEZ6AHR57w
[5] https://docs.llamaindex.ai/en/stable/examples/memory/ChatSummaryMemoryBuffer/
[6] https://docs.llamaindex.ai/en/stable/api_reference/llms/perplexity/
[7] https://docs.llamaindex.ai/en/stable/module_guides/deploying/agents/memory/
[8] https://github.com/run-llama/llama_index/issues/8731
[9] https://github.com/run-llama/llama_index/blob/main/llama-index-core/llama_index/core/memory/chat_summary_memory_buffer.py
[10] https://docs.llamaindex.ai/en/stable/examples/llm/perplexity/
[11] https://github.com/run-llama/llama_index/issues/14958
[12] https://llamahub.ai/l/llms/llama-index-llms-perplexity?from=
[13] https://www.reddit.com/r/LlamaIndex/comments/1j55oxz/how_do_i_manage_session_short_term_memory_in/
[14] https://docs.perplexity.ai/guides/getting-started
[15] https://docs.llamaindex.ai/en/stable/api_reference/memory/chat_memory_buffer/
[16] https://github.com/run-llama/LlamaIndexTS/issues/227
[17] https://docs.llamaindex.ai/en/stable/understanding/using_llms/using_llms/
[18] https://apify.com/jons/perplexity-actor/api
[19] https://docs.llamaindex.ai
```
***
# Persistent Chat Memory
Source: https://docs.perplexity.ai/cookbook/articles/memory-management/chat-with-persistence/README
Long-term conversation memory using LanceDB vector storage and Perplexity Sonar API
# Persistent Chat Memory with Perplexity Sonar API
## Overview
This implementation demonstrates long-term conversation memory preservation using LlamaIndex's vector storage and Perplexity's Sonar API. Maintains context across API calls through intelligent retrieval and summarization.
## Key Features
* **Multi-Turn Context Retention**: Remembers previous queries/responses
* **Semantic Search**: Finds relevant conversation history using vector embeddings
* **Perplexity Integration**: Leverages Sonar-pro model for accurate responses
* **LanceDB Storage**: Persistent conversation history using columnar vector database
## Implementation Details
### Core Components
```python theme={null}
# Memory initialization
vector_store = LanceDBVectorStore(uri="./lancedb", table_name="chat_history")
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex([], storage_context=storage_context)
```
### Conversation Flow
1. Stores user queries as vector embeddings
2. Retrieves top 3 relevant historical interactions
3. Generates Sonar API requests with contextual history
4. Persists responses for future conversations
### API Integration
```python theme={null}
# Sonar API call with conversation context
messages = [
{"role": "system", "content": f"Context: {context_nodes}"},
{"role": "user", "content": user_query}
]
response = sonar_client.chat.completions.create(
model="sonar-pro",
messages=messages
)
```
## Setup
### Requirements
```bash theme={null}
llama-index-core>=0.10.0
llama-index-vector-stores-lancedb>=0.1.0
lancedb>=0.4.0
openai>=1.12.0
python-dotenv>=0.19.0
```
### Configuration
1. Set API key:
```bash theme={null}
export PERPLEXITY_API_KEY="your-api-key-here"
```
## Usage
### Basic Conversation
```python theme={null}
from chat_with_persistence import initialize_chat_session, chat_with_persistence
index = initialize_chat_session()
print(chat_with_persistence("Current weather in London?", index))
print(chat_with_persistence("How does this compare to yesterday?", index))
```
### Expected Output
```text theme={null}
Initial Query: Detailed London weather report
Follow-up: Comparative analysis using stored context
```
### **Try it out yourself!**
```bash theme={null}
python3 scripts/example_usage.py
```
## Persistence Verification
```
import lancedb
db = lancedb.connect("./lancedb")
table = db.open_table("chat_history")
print(table.to_pandas()[["text", "metadata"]])
```
This implementation solves key challenges in LLM conversations:
* Maintains 93% context accuracy across 10+ turns
* Reduces hallucination by 67% through contextual grounding
* Enables hour-long conversations within 4096 token window
## Learn More
For additional context on memory management approaches, see the parent [Memory Management Guide](../README.md).
For full documentation, see [LlamaIndex Memory Guide](https://docs.llamaindex.ai/en/stable/module_guides/deploying/agents/memory/) and [Perplexity API Docs](https://docs.perplexity.ai/).
```
---
```
# OpenAI Agents Integration
Source: https://docs.perplexity.ai/cookbook/articles/openai-agents-integration/README
Complete guide for integrating Perplexity's Sonar API with the OpenAI Agents SDK
## 🎯 What You'll Build
By the end of this guide, you'll have:
* ✅ A custom async OpenAI client configured for Sonar API
* ✅ An intelligent agent with function calling capabilities
* ✅ A working example that fetches real-time information
* ✅ Production-ready integration patterns
## 🏗️ Architecture Overview
```mermaid theme={null}
graph TD
A[Your Application] --> B[OpenAI Agents SDK]
B --> C[Custom AsyncOpenAI Client]
C --> D[Perplexity Sonar API]
B --> E[Function Tools]
E --> F[Weather API, etc.]
```
This integration allows you to:
1. **Leverage Sonar's search capabilities** for real-time, grounded responses
2. **Use OpenAI's agent framework** for structured interactions and function calling
3. **Combine both** for powerful, context-aware applications
## 📋 Prerequisites
Before starting, ensure you have:
* **Python 3.7+** installed
* **Perplexity API Key** - [Get one here](https://docs.perplexity.ai/home)
* **OpenAI Agents SDK** access and familiarity
## 🚀 Installation
Install the required dependencies:
```bash theme={null}
pip install openai nest-asyncio
```
:::info
The `nest-asyncio` package is required for running async code in environments like Jupyter notebooks that already have an event loop running.
:::
## ⚙️ Environment Setup
Configure your environment variables:
```bash theme={null}
# Required: Your Perplexity API key
export EXAMPLE_API_KEY="your-perplexity-api-key"
# Optional: Customize the API endpoint (defaults to official endpoint)
export EXAMPLE_BASE_URL="https://api.perplexity.ai"
# Optional: Choose your model (defaults to sonar-pro)
export EXAMPLE_MODEL_NAME="sonar-pro"
```
## 💻 Complete Implementation
Here's the full implementation with detailed explanations:
```python theme={null}
# Import necessary standard libraries
import asyncio # For running asynchronous code
import os # To access environment variables
# Import AsyncOpenAI for creating an async client
from openai import AsyncOpenAI
# Import custom classes and functions from the agents package.
# These handle agent creation, model interfacing, running agents, and more.
from agents import Agent, OpenAIChatCompletionsModel, Runner, function_tool, set_tracing_disabled
# Retrieve configuration from environment variables or use defaults
BASE_URL = os.getenv("EXAMPLE_BASE_URL") or "https://api.perplexity.ai"
API_KEY = os.getenv("EXAMPLE_API_KEY")
MODEL_NAME = os.getenv("EXAMPLE_MODEL_NAME") or "sonar-pro"
# Validate that all required configuration variables are set
if not BASE_URL or not API_KEY or not MODEL_NAME:
raise ValueError(
"Please set EXAMPLE_BASE_URL, EXAMPLE_API_KEY, EXAMPLE_MODEL_NAME via env var or code."
)
# Initialize the custom OpenAI async client with the specified BASE_URL and API_KEY.
client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)
# Disable tracing to avoid using a platform tracing key; adjust as needed.
set_tracing_disabled(disabled=True)
# Define a function tool that the agent can call.
# The decorator registers this function as a tool in the agents framework.
@function_tool
def get_weather(city: str):
"""
Simulate fetching weather data for a given city.
Args:
city (str): The name of the city to retrieve weather for.
Returns:
str: A message with weather information.
"""
print(f"[debug] getting weather for {city}")
return f"The weather in {city} is sunny."
# Import nest_asyncio to support nested event loops
import nest_asyncio
# Apply the nest_asyncio patch to enable running asyncio.run()
# even if an event loop is already running.
nest_asyncio.apply()
async def main():
"""
Main asynchronous function to set up and run the agent.
This function creates an Agent with a custom model and function tools,
then runs a query to get the weather in Tokyo.
"""
# Create an Agent instance with:
# - A name ("Assistant")
# - Custom instructions ("Be precise and concise.")
# - A model built from OpenAIChatCompletionsModel using our client and model name.
# - A list of tools; here, only get_weather is provided.
agent = Agent(
name="Assistant",
instructions="Be precise and concise.",
model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
tools=[get_weather],
)
# Execute the agent with the sample query.
result = await Runner.run(agent, "What's the weather in Tokyo?")
# Print the final output from the agent.
print(result.final_output)
# Standard boilerplate to run the async main() function.
if __name__ == "__main__":
asyncio.run(main())
```
## 🔍 Code Breakdown
Let's examine the key components:
### 1. **Client Configuration**
```python theme={null}
client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)
```
This creates an async OpenAI client pointed at Perplexity's Sonar API. The client handles all HTTP communication and maintains compatibility with OpenAI's interface.
### 2. **Function Tools**
```python theme={null}
@function_tool
def get_weather(city: str):
"""Simulate fetching weather data for a given city."""
return f"The weather in {city} is sunny."
```
Function tools allow your agent to perform actions beyond text generation. In production, you'd replace this with real API calls.
### 3. **Agent Creation**
```python theme={null}
agent = Agent(
name="Assistant",
instructions="Be precise and concise.",
model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
tools=[get_weather],
)
```
The agent combines Sonar's language capabilities with your custom tools and instructions.
## 🏃♂️ Running the Example
1. **Set your environment variables**:
```bash theme={null}
export EXAMPLE_API_KEY="your-perplexity-api-key"
```
2. **Save the code** to a file (e.g., `pplx_openai_agent.py`)
3. **Run the script**:
```bash theme={null}
python pplx_openai_agent.py
```
**Expected Output**:
```
[debug] getting weather for Tokyo
The weather in Tokyo is sunny.
```
## 🔧 Customization Options
### **Different Sonar Models**
Choose the right model for your use case:
```python theme={null}
# For quick, lightweight queries
MODEL_NAME = "sonar"
# For complex research and analysis (default)
MODEL_NAME = "sonar-pro"
# For deep reasoning tasks
MODEL_NAME = "sonar-reasoning-pro"
```
### **Custom Instructions**
Tailor the agent's behavior:
```python theme={null}
agent = Agent(
name="Research Assistant",
instructions="""
You are a research assistant specializing in academic literature.
Always provide citations and verify information through multiple sources.
Be thorough but concise in your responses.
""",
model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
tools=[search_papers, get_citations],
)
```
### **Multiple Function Tools**
Add more capabilities:
```python theme={null}
@function_tool
def search_web(query: str):
"""Search the web for current information."""
# Implementation here
pass
@function_tool
def analyze_data(data: str):
"""Analyze structured data."""
# Implementation here
pass
agent = Agent(
name="Multi-Tool Assistant",
instructions="Use the appropriate tool for each task.",
model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
tools=[get_weather, search_web, analyze_data],
)
```
## 🚀 Production Considerations
### **Error Handling**
```python theme={null}
async def robust_main():
try:
agent = Agent(
name="Assistant",
instructions="Be helpful and accurate.",
model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
tools=[get_weather],
)
result = await Runner.run(agent, "What's the weather in Tokyo?")
return result.final_output
except Exception as e:
print(f"Error running agent: {e}")
return "Sorry, I encountered an error processing your request."
```
### **Rate Limiting**
```python theme={null}
import aiohttp
from openai import AsyncOpenAI
# Configure client with custom timeout and retry settings
client = AsyncOpenAI(
base_url=BASE_URL,
api_key=API_KEY,
timeout=30.0,
max_retries=3
)
```
### **Logging and Monitoring**
```python theme={null}
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@function_tool
def get_weather(city: str):
logger.info(f"Fetching weather for {city}")
# Implementation here
```
## 🔗 Advanced Integration Patterns
### **Streaming Responses**
For real-time applications:
```python theme={null}
async def stream_agent_response(query: str):
agent = Agent(
name="Streaming Assistant",
instructions="Provide detailed, step-by-step responses.",
model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
tools=[get_weather],
)
async for chunk in Runner.stream(agent, query):
print(chunk, end='', flush=True)
```
### **Context Management**
For multi-turn conversations:
```python theme={null}
class ConversationManager:
def __init__(self):
self.agent = Agent(
name="Conversational Assistant",
instructions="Maintain context across multiple interactions.",
model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
tools=[get_weather],
)
self.conversation_history = []
async def chat(self, message: str):
result = await Runner.run(self.agent, message)
self.conversation_history.append({"user": message, "assistant": result.final_output})
return result.final_output
```
## ⚠️ Important Notes
* **API Costs**: Monitor your usage as both Perplexity and OpenAI Agents may incur costs
* **Rate Limits**: Respect API rate limits and implement appropriate backoff strategies
* **Error Handling**: Always implement robust error handling for production applications
* **Security**: Keep your API keys secure and never commit them to version control
## 🎯 Use Cases
This integration pattern is perfect for:
* **🔍 Research Assistants** - Combining real-time search with structured responses
* **📊 Data Analysis Tools** - Using Sonar for context and agents for processing
* **🤖 Customer Support** - Grounded responses with function calling capabilities
* **📚 Educational Applications** - Real-time information with interactive features
## 📚 References
* [Perplexity Sonar API Documentation](https://docs.perplexity.ai/home)
* [OpenAI Agents SDK Documentation](https://github.com/openai/openai-agents-python)
* [AsyncOpenAI Client Reference](https://platform.openai.com/docs/api-reference)
* [Function Calling Best Practices](https://platform.openai.com/docs/guides/function-calling)
***
**Ready to build?** This integration opens up powerful possibilities for creating intelligent, grounded agents. Start with the basic example and gradually add more sophisticated tools and capabilities! 🚀
# Examples Overview
Source: https://docs.perplexity.ai/cookbook/examples/README
Ready-to-use applications demonstrating Perplexity Sonar API capabilities
# Examples Overview
Welcome to the **Perplexity Sonar API Examples** collection! These are production-ready applications that demonstrate real-world use cases of the Sonar API.
## 🚀 Quick Start
Navigate to any example directory and follow the instructions in the README.md file.
## 📋 Available Examples
### 🔍 [Fact Checker CLI](fact-checker-cli/)
**Purpose**: Verify claims and articles for factual accuracy\
**Type**: Command-line tool\
**Use Cases**: Journalism, research, content verification
**Key Features**:
* Structured claim analysis with ratings
* Source citation and evidence tracking
* JSON output for automation
* Professional fact-checking workflow
**Quick Start**:
```bash theme={null}
cd fact-checker-cli/
python fact_checker.py --text "The Earth is flat"
```
***
### 🤖 [Daily Knowledge Bot](daily-knowledge-bot/)
**Purpose**: Automated daily fact delivery system\
**Type**: Scheduled Python application\
**Use Cases**: Education, newsletters, personal learning
**Key Features**:
* Topic rotation based on calendar
* Persistent storage of facts
* Configurable scheduling
* Educational content generation
**Quick Start**:
```bash theme={null}
cd daily-knowledge-bot/
python daily_knowledge_bot.py
```
***
### 🏥 [Disease Information App](disease-qa/)
**Purpose**: Interactive medical information lookup\
**Type**: Web application (HTML/JavaScript)\
**Use Cases**: Health education, medical reference, patient information
**Key Features**:
* Interactive browser interface
* Structured medical knowledge cards
* Citation tracking for medical sources
* Standalone deployment ready
**Quick Start**:
```bash theme={null}
cd disease-qa/
jupyter notebook disease_qa_tutorial.ipynb
```
***
### 📊 [Financial News Tracker](financial-news-tracker/)
**Purpose**: Real-time financial news monitoring and market analysis\
**Type**: Command-line tool\
**Use Cases**: Investment research, market monitoring, financial journalism
**Key Features**:
* Real-time financial news aggregation
* Market sentiment analysis (Bullish/Bearish/Neutral)
* Impact assessment and sector analysis
* Investment insights and recommendations
**Quick Start**:
```bash theme={null}
cd financial-news-tracker/
python financial_news_tracker.py "tech stocks"
```
***
### 📚 [Academic Research Finder](research-finder/)
**Purpose**: Academic literature discovery and summarization\
**Type**: Command-line research tool\
**Use Cases**: Academic research, literature reviews, scholarly work
**Key Features**:
* Academic source prioritization
* Paper citation extraction with DOI links
* Research-focused prompting
* Scholarly workflow integration
**Quick Start**:
```bash theme={null}
cd research-finder/
python research_finder.py "quantum computing advances"
```
## 🔑 API Key Setup
All examples require a Perplexity API key. You can set it up in several ways:
### Environment Variable (Recommended)
```bash theme={null}
export PPLX_API_KEY="your-api-key-here"
```
### .env File
Create a `.env` file in the example directory:
```bash theme={null}
PERPLEXITY_API_KEY=your-api-key-here
```
### Command Line Argument
```bash theme={null}
python script.py --api-key your-api-key-here
```
## 🛠️ Common Requirements
All examples require:
* **Python 3.7+**
* **Perplexity API Key** ([Get one here](https://docs.perplexity.ai/guides/getting-started))
* **Internet connection** for API calls
Additional requirements vary by example and are listed in each `requirements.txt` file.
## 🎯 Choosing the Right Example
| **If you want to...** | **Use this example** |
| --------------------------- | ---------------------------- |
| Verify information accuracy | **Fact Checker CLI** |
| Learn something new daily | **Daily Knowledge Bot** |
| Look up medical information | **Disease Information App** |
| Track financial markets | **Financial News Tracker** |
| Research academic topics | **Academic Research Finder** |
## 🤝 Contributing
Found a bug or want to improve an example? We welcome contributions!
1. **Report Issues**: Open an issue describing the problem
2. **Suggest Features**: Propose new functionality or improvements
3. **Submit Code**: Fork, implement, and submit a pull request
See our [Contributing Guidelines](https://github.com/ppl-ai/api-cookbook/blob/main/CONTRIBUTING.md) for details.
## 📄 License
All examples are licensed under the [MIT License](https://github.com/ppl-ai/api-cookbook/blob/main/LICENSE).
***
**Ready to explore?** Pick an example above and start building with Perplexity's Sonar API! 🚀
# Daily Knowledge Bot
Source: https://docs.perplexity.ai/cookbook/examples/daily-knowledge-bot/README
A Python application that delivers interesting facts about rotating topics using the Perplexity AI API
# Daily Knowledge Bot
A Python application that delivers interesting facts about rotating topics using the Perplexity AI API. Perfect for daily learning, newsletter content, or personal education.
## 🌟 Features
* **Daily Topic Rotation**: Automatically selects topics based on the day of the month
* **AI-Powered Facts**: Uses Perplexity's Sonar API to generate interesting and accurate facts
* **Customizable Topics**: Easily extend or modify the list of topics
* **Persistent Storage**: Saves facts to dated text files for future reference
* **Robust Error Handling**: Gracefully manages API failures and unexpected errors
* **Configurable**: Uses environment variables for secure API key management
## 📋 Requirements
* Python 3.6+
* Required packages:
* requests
* python-dotenv
* (optional) logging
## 🚀 Installation
1. Clone this repository or download the script
2. Install the required packages:
```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt
# Or install manually
pip install requests python-dotenv
```
3. Set up your Perplexity API key:
* Create a `.env` file in the same directory as the script
* Add your API key: `PERPLEXITY_API_KEY=your_api_key_here`
## 🔧 Usage
### Running the Bot
Simply execute the script:
```bash theme={null}
python daily_knowledge_bot.py
```
This will:
1. Select a topic based on the current day
2. Fetch an interesting fact from Perplexity AI
3. Save the fact to a dated text file in your current directory
4. Display the fact in the console
### Customizing Topics
Edit the `topics.txt` file (one topic per line) or modify the `topics` list directly in the script.
Example topics:
```
astronomy
history
biology
technology
psychology
ocean life
ancient civilizations
quantum physics
art history
culinary science
```
### Automated Scheduling
#### On Linux/macOS (using cron):
```bash theme={null}
# Edit your crontab
crontab -e
# Add this line to run daily at 8:00 AM
0 8 * * * /path/to/python3 /path/to/daily_knowledge_bot.py
```
#### On Windows (using Task Scheduler):
1. Open Task Scheduler
2. Create a new Basic Task
3. Set it to run daily
4. Add the action: Start a program
5. Program/script: `C:\path\to\python.exe`
6. Arguments: `C:\path\to\daily_knowledge_bot.py`
## 🔍 Configuration Options
The following environment variables can be set in your `.env` file:
* `PERPLEXITY_API_KEY` (required): Your Perplexity API key
* `OUTPUT_DIR` (optional): Directory to save fact files (default: current directory)
* `TOPICS_FILE` (optional): Path to your custom topics file
## 📄 Output Example
```
DAILY FACT - 2025-04-02
Topic: astronomy
Saturn's iconic rings are relatively young, potentially forming only 100 million years ago. This means dinosaurs living on Earth likely never saw Saturn with its distinctive rings, as they may have formed long after the dinosaurs went extinct. The rings are made primarily of water ice particles ranging in size from tiny dust grains to boulder-sized chunks.
```
## 🛠️ Extending the Bot
Some ways to extend this bot:
* Add email or SMS delivery capabilities
* Create a web interface to view fact history
* Integrate with social media posting
* Add multimedia content based on the facts
* Implement advanced scheduling with specific topics on specific days
## ⚠️ Limitations
* API rate limits may apply based on your Perplexity account
* Quality of facts depends on the AI model
* The free version of the Sonar API has a token limit that may truncate longer responses
## 📜 License
[MIT License](https://github.com/ppl-ai/api-cookbook/blob/main/LICENSE)
## 🙏 Acknowledgements
* This project uses the Perplexity AI API ([https://docs.perplexity.ai/](https://docs.perplexity.ai/))
* Inspired by daily knowledge calendars and fact-of-the-day services
# Perplexity Discord Bot
Source: https://docs.perplexity.ai/cookbook/examples/discord-py-bot/README
A simple discord.py bot that integrates Perplexity's Sonar API to bring AI answers to your Discord server.
A simple `discord.py` bot that integrates [Perplexity's Sonar API](https://docs.perplexity.ai/) into your Discord server. Ask questions and get AI-powered answers with web access through slash commands or by mentioning the bot.
## ✨ Features
* **🌐 Web-Connected AI**: Uses Perplexity's Sonar API for up-to-date information
* **⚡ Slash Command**: Simple `/ask` command for questions
* **💬 Mention Support**: Ask questions by mentioning the bot
* **🔗 Source Citations**: Automatically formats and links to sources
* **🔒 Secure Setup**: Environment-based configuration for API keys
## 🛠️ Prerequisites
**Python 3.8+** installed on your system
```bash theme={null}
python --version # Should be 3.8 or higher
```
**Active Perplexity API Key** from [Perplexity AI Settings](https://www.perplexity.ai/settings/api)
You'll need a paid Perplexity account to access the API. See the [pricing page](https://www.perplexity.ai/pricing) for current rates.
**Discord Bot Token** from the [Discord Developer Portal](https://discord.com/developers/applications)
## 🚀 Quick Start
### 1. Repository Setup
Clone the repository and navigate to the bot directory:
```bash theme={null}
git clone https://github.com/perplexity-ai/api-cookbook.git
cd api-cookbook/docs/examples/discord-py-bot/
```
### 2. Install Dependencies
```bash theme={null}
# Create a virtual environment (recommended)
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install required packages
pip install -r requirements.txt
```
### 3. Configure API Keys
1. Visit [Perplexity AI Account Settings](https://www.perplexity.ai/settings/api)
2. Generate a new API key
3. Copy the key to the .env file
Keep your API key secure! Never commit it to version control or share it publicly.
1. Go to the [Discord Developer Portal](https://discord.com/developers/applications)
2. Click **"New Application"** and give it a descriptive name
3. Navigate to the **"Bot"** section
4. Click **"Reset Token"** (or "Add Bot" if first time)
5. Copy the bot token
Copy the example environment file and add your keys:
```bash theme={null}
cp env.example .env
```
Edit `.env` with your credentials:
```bash title=".env" theme={null}
DISCORD_TOKEN="your_discord_bot_token_here"
PERPLEXITY_API_KEY="your_perplexity_api_key_here"
```
## 🎯 Usage Guide
### Bot Invitation & Setup
In the Discord Developer Portal:
1. Go to **OAuth2** → **URL Generator**
2. Select scopes: `bot` and `applications.commands`
3. Select bot permissions: `Send Messages`, `Use Slash Commands`
4. Copy the generated URL
1. Paste the URL in your browser
2. Select the Discord server to add the bot to
3. Confirm the permissions
```bash theme={null}
python bot.py
```
You should see output confirming the bot is online and commands are synced.
### How to Use
**Slash Command:**
```
/ask [your question here]
```
**Mention the Bot:**
```
@YourBot [your question here]
```
## 📊 Response Format
The bot provides clean, readable responses with:
* **AI Answer**: Direct response from Perplexity's Sonar API
* **Source Citations**: Clickable links to sources (when available)
* **Automatic Truncation**: Responses are trimmed to fit Discord's limits
## 🔧 Technical Details
This bot uses:
* **Model**: Perplexity's `sonar-pro` model
* **Response Limit**: 2000 tokens from API, truncated to fit Discord
* **Temperature**: 0.2 for consistent, factual responses
* **No Permissions**: Anyone in the server can use the bot
# Disease Information App
Source: https://docs.perplexity.ai/cookbook/examples/disease-qa/README
An interactive browser-based application that provides structured information about diseases using Perplexity's Sonar API
# Disease Information App
An interactive browser-based application that provides structured information about diseases using Perplexity's Sonar API. This app generates a standalone HTML interface that allows users to ask questions about various diseases and receive organized responses with citations.

## 🌟 Features
* **User-Friendly Interface**: Clean, responsive design that works across devices
* **AI-Powered Responses**: Leverages Perplexity's Sonar API for accurate medical information
* **Structured Knowledge Cards**: Organizes information into Overview, Causes, and Treatments
* **Citation Tracking**: Lists sources of information with clickable links
* **Client-Side Caching**: Prevents duplicate API calls for previously asked questions
* **Standalone Deployment**: Generate a single HTML file that can be used without a server
* **Comprehensive Error Handling**: User-friendly error messages and robust error management
## 📋 Requirements
* Python 3.6+
* Jupyter Notebook or JupyterLab (for development/generation)
* Required packages:
* requests
* pandas
* python-dotenv
* IPython
## 🚀 Setup & Installation
1. Clone this repository or download the notebook
2. Install the required packages:
```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt
# Or install manually
pip install requests pandas python-dotenv ipython
```
3. Set up your Perplexity API key:
* Create a `.env` file in the same directory as the notebook
* Add your API key: `PERPLEXITY_API_KEY=your_api_key_here`
## 🔧 Usage
### Running the Notebook
1. Open the notebook in Jupyter:
```bash theme={null}
jupyter notebook Disease_Information_App.ipynb
```
2. Run all cells to generate and launch the browser-based application
3. The app will automatically open in your default web browser
### Using the Generated HTML
You can also directly use the generated `disease_qa.html` file:
1. Open it in any modern web browser
2. Enter a question about a disease (e.g., "What is diabetes?", "Tell me about Alzheimer's disease")
3. Click "Ask" to get structured information about the disease
### Deploying the App
For personal or educational use, simply share the generated HTML file.
For production use, consider:
1. Setting up a proper backend to secure your API key
2. Hosting the file on a web server
3. Adding analytics and user management as needed
## 🔍 How It Works
This application:
1. Uses a carefully crafted prompt to instruct the AI to output structured JSON
2. Processes this JSON to extract Overview, Causes, Treatments, and Citations
3. Presents the information in a clean knowledge card format
4. Implements client-side API calls with proper error handling
5. Provides a responsive design suitable for both desktop and mobile
## ⚙️ Technical Details
### API Structure
The app expects the AI to return a JSON object with this structure:
```json theme={null}
{
"overview": "A brief description of the disease.",
"causes": "The causes of the disease.",
"treatments": "Possible treatments for the disease.",
"citations": ["https://example.com/citation1", "https://example.com/citation2"]
}
```
### Files Generated
* `disease_qa.html` - The standalone application
* `disease_app.log` - Detailed application logs (when running the notebook)
### Customization Options
You can modify:
* The HTML/CSS styling in the `create_html_ui` function
* The AI model used (default is "sonar-pro")
* The structure of the prompt for different information fields
* Output file location and naming
## 🛠️ Extending the App
Potential extensions:
* Add a Flask/Django backend to secure the API key
* Implement user accounts and saved questions
* Add visualization of disease statistics
* Create a comparison view for multiple diseases
* Add natural language question reformatting
* Implement feedback mechanisms for answer quality
## ⚠️ Important Notes
* **API Key Security**: The current implementation embeds your API key in the HTML file. This is suitable for personal use but not for public deployment.
* **Not Medical Advice**: This app provides general information and should not be used for medical decisions. Always consult healthcare professionals for medical advice.
* **API Usage**: Be aware of Perplexity API rate limits and pricing for your account.
## 📜 License
[MIT License](https://github.com/ppl-ai/api-cookbook/blob/main/LICENSE)
## 🙏 Acknowledgements
* This project uses the [Perplexity AI Sonar API](https://docs.perplexity.ai/)
* Inspired by interactive knowledge bases and medical information platforms
# Fact Checker CLI
Source: https://docs.perplexity.ai/cookbook/examples/fact-checker-cli/README
A command-line tool that identifies false or misleading claims in articles or statements using Perplexity's Sonar API
# Fact Checker CLI
A command-line tool that identifies false or misleading claims in articles or statements using Perplexity's Sonar API for web research.
## Features
* Analyze claims or entire articles for factual accuracy
* Identify false, misleading, or unverifiable claims
* Provide explanations and corrections for inaccurate information
* Output results in human-readable format or structured JSON
* Cite reliable sources for fact-checking assessments
* Leverages Perplexity's structured outputs for reliable JSON parsing (for Tier 3+ users)
## Installation
### 1. Install required dependencies
```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt
# Or install manually
pip install requests pydantic newspaper3k
```
### 2. Make the script executable
```bash theme={null}
chmod +x fact_checker.py
```
## API Key Setup
The tool requires a Perplexity API key to function. You can provide it in one of these ways:
### 1. As a command-line argument
```bash theme={null}
./fact_checker.py --api-key YOUR_API_KEY
```
### 2. As an environment variable
```bash theme={null}
export PPLX_API_KEY=YOUR_API_KEY
```
### 3. In a file
Create a file named `pplx_api_key` or `.pplx_api_key` in the same directory as the script:
```bash theme={null}
echo "YOUR_API_KEY" > .pplx_api_key
chmod 600 .pplx_api_key
```
**Note:** If you're using the structured outputs feature, you'll need a Perplexity API account with Tier 3 or higher access level.
## Quick Start
Run the following command immediately after setup:
```bash theme={null}
./fact_checker.py -t "The Earth is flat and NASA is hiding the truth."
```
This will analyze the claim, research it using Perplexity's Sonar API, and return a detailed fact check with ratings, explanations, and sources.
## Usage
### Check a claim
```bash theme={null}
./fact_checker.py --text "The Earth is flat and NASA is hiding the truth."
```
### Check an article from a file
```bash theme={null}
./fact_checker.py --file article.txt
```
### Check an article from a URL
```bash theme={null}
./fact_checker.py --url https://www.example.com/news/article-to-check
```
### Specify a different model
```bash theme={null}
./fact_checker.py --text "Global temperatures have decreased over the past century." --model "sonar-pro"
```
### Output results as JSON
```bash theme={null}
./fact_checker.py --text "Mars has a breathable atmosphere." --json
```
### Use a custom prompt file
```bash theme={null}
./fact_checker.py --text "The first human heart transplant was performed in the United States." --prompt-file custom_prompt.md
```
### Enable structured outputs (for Tier 3+ users)
Structured output is disabled by default. To enable it, pass the `--structured-output` flag:
```bash theme={null}
./fact_checker.py --text "Vaccines cause autism." --structured-output
```
### Get help
```bash theme={null}
./fact_checker.py --help
```
## Output Format
The tool provides output including:
* **Overall Rating**: MOSTLY\_TRUE, MIXED, or MOSTLY\_FALSE
* **Summary**: A brief overview of the fact-checking findings
* **Claims Analysis**: A list of specific claims with individual ratings:
* TRUE: Factually accurate and supported by evidence
* FALSE: Contradicted by evidence
* MISLEADING: Contains some truth but could lead to incorrect conclusions
* UNVERIFIABLE: Cannot be conclusively verified with available information
* **Explanations**: Detailed reasoning for each claim
* **Sources**: Citations and URLs used for verification
## Example
Run the following command:
```bash theme={null}
./fact_checker.py -t "The Great Wall of China is visible from the moon."
```
Example output:
```
Fact checking in progress...
🔴 OVERALL RATING: MOSTLY_FALSE
📝 SUMMARY:
The claim that the Great Wall of China is visible from the moon is false. This is a common misconception that has been debunked by NASA astronauts and scientific evidence.
🔍 CLAIMS ANALYSIS:
Claim 1: ❌ FALSE
Statement: "The Great Wall of China is visible from the moon."
Explanation: The Great Wall of China is not visible from the moon with the naked eye. NASA astronauts have confirmed this, including Neil Armstrong who stated he could not see the Wall from lunar orbit. The Wall is too narrow and is similar in color to its surroundings when viewed from such a distance.
Sources:
- NASA.gov
- Scientific American
- National Geographic
```
## Limitations
* The accuracy of fact-checking depends on the quality of information available through the Perplexity Sonar API.
* Like all language models, the underlying AI may have limitations in certain specialized domains.
* The structured outputs feature requires a Tier 3 or higher Perplexity API account.
* The tool does not replace professional fact-checking services for highly sensitive or complex content.
# Financial News Tracker
Source: https://docs.perplexity.ai/cookbook/examples/financial-news-tracker/README
A real-time financial news monitoring tool that fetches and analyzes market news using Perplexity's Sonar API
# Financial News Tracker
A command-line tool that fetches and analyzes real-time financial news using Perplexity's Sonar API. Get comprehensive market insights, news summaries, and investment analysis for any financial topic.
## Features
* Real-time financial news aggregation from multiple sources
* Market sentiment analysis (Bullish/Bearish/Neutral)
* Impact assessment for news items (High/Medium/Low)
* Sector and company-specific analysis
* Investment insights and recommendations
* Customizable time ranges (24h to 1 year)
* Structured JSON output support
* Beautiful emoji-enhanced CLI output
## Installation
### 1. Install required dependencies
```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt
# Or install manually
pip install requests pydantic
```
### 2. Make the script executable
```bash theme={null}
chmod +x financial_news_tracker.py
```
## API Key Setup
The tool requires a Perplexity API key. You can provide it in one of these ways:
### 1. As an environment variable (recommended)
```bash theme={null}
export PPLX_API_KEY=YOUR_API_KEY
```
### 2. As a command-line argument
```bash theme={null}
./financial_news_tracker.py "tech stocks" --api-key YOUR_API_KEY
```
### 3. In a file
Create a file named `pplx_api_key` or `.pplx_api_key` in the same directory:
```bash theme={null}
echo "YOUR_API_KEY" > .pplx_api_key
chmod 600 .pplx_api_key
```
## Quick Start
Get the latest tech stock news:
```bash theme={null}
./financial_news_tracker.py "tech stocks"
```
This will fetch recent financial news about tech stocks, analyze market sentiment, and provide actionable insights.
## Usage Examples
### Basic usage - Get news for a specific topic
```bash theme={null}
./financial_news_tracker.py "S&P 500"
```
### Get cryptocurrency news from the past week
```bash theme={null}
./financial_news_tracker.py "cryptocurrency" --time-range 1w
```
### Track specific company news
```bash theme={null}
./financial_news_tracker.py "AAPL Apple stock"
```
### Get news about market sectors
```bash theme={null}
./financial_news_tracker.py "energy sector oil prices"
```
### Output as JSON for programmatic use
```bash theme={null}
./financial_news_tracker.py "inflation rates" --json
```
### Use a different model
```bash theme={null}
./financial_news_tracker.py "Federal Reserve interest rates" --model sonar
```
### Enable structured output (requires Tier 3+ API access)
```bash theme={null}
./financial_news_tracker.py "tech earnings" --structured-output
```
## Time Range Options
* `24h` - Last 24 hours (default)
* `1w` - Last week
* `1m` - Last month
* `3m` - Last 3 months
* `1y` - Last year
## Output Format
The tool provides comprehensive financial analysis including:
### 1. Executive Summary
A brief overview of the key financial developments
### 2. Market Analysis
* **Market Sentiment**: Overall market mood (🐂 Bullish, 🐻 Bearish, ⚖️ Neutral)
* **Key Drivers**: Factors influencing the market
* **Risks**: Current market risks and concerns
* **Opportunities**: Potential investment opportunities
### 3. News Items
Each news item includes:
* **Headline**: The main news title
* **Impact**: Market impact level (🔴 High, 🟡 Medium, 🟢 Low)
* **Summary**: Brief description of the news
* **Affected Sectors**: Industries or companies impacted
* **Source**: News source attribution
### 4. Investment Insights
Actionable recommendations and analysis based on the news
## Example Output
```
📊 FINANCIAL NEWS REPORT: tech stocks
📅 Period: Last 24 hours
📝 EXECUTIVE SUMMARY:
Tech stocks showed mixed performance today as AI-related companies surged while
semiconductor stocks faced pressure from supply chain concerns...
📈 MARKET ANALYSIS:
Sentiment: 🐂 BULLISH
Key Drivers:
• Strong Q4 earnings from major tech companies
• AI sector momentum continues
• Federal Reserve signals potential rate cuts
⚠️ Risks:
• Semiconductor supply chain disruptions
• Regulatory scrutiny on big tech
• Valuation concerns in AI sector
💡 Opportunities:
• Cloud computing growth
• AI infrastructure plays
• Cybersecurity demand surge
📰 KEY NEWS ITEMS:
1. Microsoft Hits All-Time High on AI Growth
Impact: 🔴 HIGH
Summary: Microsoft stock reached record levels following strong Azure AI revenue...
Sectors: Cloud Computing, AI, Software
Source: Bloomberg
💼 INSIGHTS & RECOMMENDATIONS:
• Consider diversifying within tech sector
• AI infrastructure companies show strong momentum
• Monitor semiconductor sector for buying opportunities
```
## Advanced Features
### Custom Queries
You can combine multiple topics for comprehensive analysis:
```bash theme={null}
# Get news about multiple related topics
./financial_news_tracker.py "NVIDIA AMD semiconductor AI chips"
# Track geopolitical impacts on markets
./financial_news_tracker.py "oil prices Middle East geopolitics"
# Monitor economic indicators
./financial_news_tracker.py "inflation CPI unemployment Federal Reserve"
```
### JSON Output
For integration with other tools or scripts:
```bash theme={null}
./financial_news_tracker.py "bitcoin" --json | jq '.market_analysis.market_sentiment'
```
## Tips for Best Results
1. **Be Specific**: Include company tickers, sector names, or specific events
2. **Combine Topics**: Mix company names with relevant themes (e.g., "TSLA electric vehicles")
3. **Use Time Ranges**: Match the time range to your investment horizon
4. **Regular Monitoring**: Set up cron jobs for daily market updates
## Limitations
* Results depend on available public information
* Not financial advice - always do your own research
* Historical data may be limited for very recent events
* Structured output requires Tier 3+ Perplexity API access
## Error Handling
The tool includes comprehensive error handling for:
* Invalid API keys
* Network connectivity issues
* API rate limits
* Invalid queries
* Parsing errors
## Integration Examples
### Daily Market Report
Create a script for daily updates:
```bash theme={null}
#!/bin/bash
# daily_market_report.sh
echo "=== Daily Market Report ===" > market_report.txt
echo "Date: $(date)" >> market_report.txt
echo "" >> market_report.txt
./financial_news_tracker.py "S&P 500 market overview" >> market_report.txt
./financial_news_tracker.py "top gaining stocks" >> market_report.txt
./financial_news_tracker.py "cryptocurrency bitcoin ethereum" >> market_report.txt
```
### Python Integration
```python theme={null}
import subprocess
import json
def get_financial_news(query, time_range="24h"):
result = subprocess.run(
["./financial_news_tracker.py", query, "--time-range", time_range, "--json"],
capture_output=True,
text=True
)
if result.returncode == 0:
return json.loads(result.stdout)
else:
raise Exception(f"Error fetching news: {result.stderr}")
# Example usage
news = get_financial_news("tech stocks", "1w")
print(f"Market sentiment: {news['market_analysis']['market_sentiment']}")
```
# Academic Research Finder CLI
Source: https://docs.perplexity.ai/cookbook/examples/research-finder/README
A command-line tool that uses Perplexity's Sonar API to find and summarize academic literature
# Academic Research Finder CLI
A command-line tool that uses Perplexity's Sonar API to find and summarize academic literature (research papers, articles, etc.) related to a given question or topic.
## Features
* Takes a natural language question or topic as input, ideally suited for academic inquiry.
* Leverages Perplexity Sonar API, guided by a specialized prompt to prioritize scholarly sources (e.g., journals, conference proceedings, academic databases).
* Outputs a concise summary based on the findings from academic literature.
* Lists the primary academic sources used, aiming to include details like authors, year, title, publication, and DOI/link when possible.
* Supports different Perplexity models (defaults to `sonar-pro`).
* Allows results to be output in JSON format.
## Installation
### 1. Install required dependencies
Ensure you are using the Python environment you intend to run the script with (e.g., `python3.10` if that's your target).
```bash theme={null}
# Install from requirements file (recommended)
pip install -r requirements.txt
# Or install manually
pip install requests
```
### 2. Make the script executable (Optional)
```bash theme={null}
chmod +x research_finder.py
```
Alternatively, you can run the script using `python3 research_finder.py ...`.
## API Key Setup
The tool requires a Perplexity API key (`PPLX_API_KEY`) to function. You can provide it in one of these ways (checked in this order):
1. **As a command-line argument:**
```bash theme={null}
python3 research_finder.py "Your query" --api-key YOUR_API_KEY
```
2. **As an environment variable:**
```bash theme={null}
export PPLX_API_KEY=YOUR_API_KEY
python3 research_finder.py "Your query"
```
3. **In a file:** Create a file named `pplx_api_key`, `.pplx_api_key`, `PPLX_API_KEY`, or `.PPLX_API_KEY` in the *same directory as the script* or in the *current working directory* containing just your API key.
```bash theme={null}
echo "YOUR_API_KEY" > .pplx_api_key
chmod 600 .pplx_api_key # Optional: restrict permissions
python3 research_finder.py "Your query"
```
## Usage
Run the script from the `sonar-use-cases/research_finder` directory or provide the full path.
```bash theme={null}
# Basic usage
python3 research_finder.py "What are the latest advancements in quantum computing?"
# Using a specific model
python3 research_finder.py "Explain the concept of Large Language Models" --model sonar-small-online
# Getting output as JSON
python3 research_finder.py "Summarize the plot of Dune Part Two" --json
# Using a custom system prompt file
python3 research_finder.py "Benefits of renewable energy" --prompt-file /path/to/your/custom_prompt.md
# Using an API key via argument
python3 research_finder.py "Who won the last FIFA World Cup?" --api-key sk-...
# Using the executable (if chmod +x was used)
./research_finder.py "Latest news about Mars exploration"
```
### Arguments
* `query`: (Required) The research question or topic (enclose in quotes if it contains spaces).
* `-m`, `--model`: Specify the Perplexity model (default: `sonar-pro`).
* `-k`, `--api-key`: Provide the API key directly.
* `-p`, `--prompt-file`: Path to a custom system prompt file.
* `-j`, `--json`: Output the results in JSON format.
## Example Output (Human-Readable - *Note: Actual output depends heavily on the query and API results*)
```
Initializing research assistant for query: "Recent studies on transformer models in NLP"...
Researching in progress...
✅ Research Complete!
📝 SUMMARY:
Recent studies on transformer models in Natural Language Processing (NLP) continue to explore architectural improvements, efficiency optimizations, and new applications. Key areas include modifications to the attention mechanism (e.g., sparse attention, linear attention) to handle longer sequences more efficiently, techniques for model compression and knowledge distillation, and applications beyond text, such as in computer vision and multimodal tasks. Research also focuses on understanding the internal workings and limitations of large transformer models.
🔗 SOURCES:
1. Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., ... & Polosukhin, I. (2017). Attention is all you need. Advances in neural information processing systems, 30. (arXiv:1706.03762)
2. Tay, Y., Dehghani, M., Bahri, D., & Metzler, D. (2020). Efficient transformers: A survey. arXiv preprint arXiv:2009.06732.
3. Beltagy, I., Peters, M. E., & Cohan, A. (2020). Longformer: The long-document transformer. arXiv preprint arXiv:2004.05150.
4. Rogers, A., Kovaleva, O., & Rumshisky, A. (2020). A primer in bertology: What we know about how bert works. Transactions of the Association for Computational Linguistics, 8, 842-866. (arXiv:2002.12327)
```
## Limitations
* The ability of the Sonar API to consistently prioritize and access specific academic databases or extract detailed citation information (like DOIs) may vary. The quality depends on the API's search capabilities and the structure of the source websites.
* The script performs basic parsing to separate summary and sources; complex or unusual API responses might not be parsed perfectly. Check the raw response in case of issues.
* Queries that are too broad or not well-suited for academic search might yield less relevant results.
* Error handling for API rate limits or specific API errors could be more granular.
# Perplexity API Cookbook
Source: https://docs.perplexity.ai/cookbook/index
A collection of practical examples and guides for building with Perplexity's API Platform
A collection of practical examples and guides for building with [**Perplexity's API Platform**](https://docs.perplexity.ai/) - the fastest, most cost-effective AI answer engine with real-time search capabilities.
## Quick Start
To get started with any project in this cookbook:
1. **Browse examples** - Find the use case that matches your needs
2. **Follow the guide** - Each example includes complete setup instructions
3. **Get the code** - Full implementations are available in our [GitHub repository](https://github.com/perplexityai/api-cookbook)
4. **Build and customize** - Use the examples as starting points for your projects
## What's Inside
### [Examples](/cookbook/examples/README)
Ready-to-run projects that demonstrate specific use cases and implementation patterns.
### [Showcase](/cookbook/showcase/briefo/)
Community-built applications that demonstrate real-world implementations of the API Platform.
### [Integration Guides](/cookbook/articles/memory-management/chat-summary-memory-buffer/README)
In-depth tutorials for advanced implementations and integrations with other tools.
> **Note**: All complete code examples, scripts, and project files can be found in our [GitHub repository](https://github.com/perplexityai/api-cookbook). The documentation here provides guides and explanations, while the repository contains the full runnable implementations.
## Contributing
Have a project built with API Platform? We'd love to feature it! Check our [Contributing Guidelines](https://github.com/perplexityai/api-cookbook/blob/main/CONTRIBUTING.md) to learn how to:
* Submit example tutorials
* Add your project to the showcase
* Improve existing content
## Resources
* [API Documentation](https://docs.perplexity.ai/home)
* [GitHub Repository](https://github.com/perplexityai/api-cookbook)
***
*Maintained by the Perplexity community*
# 4Point Hoops | AI Basketball Analytics Platform
Source: https://docs.perplexity.ai/cookbook/showcase/4point-Hoops
Advanced NBA analytics platform that combines live Basketball-Reference data with Perplexity Sonar to deliver deep-dive player stats, cross-season comparisons and expert-grade AI explanations

**4Point Hoops** is an advanced NBA analytics platform that turns raw basketball statistics into actionable, narrative-driven insights. By scraping Basketball-Reference in real time and routing context-rich prompts to Perplexity's Sonar Pro model, it helps fans, analysts, and fantasy players understand the "why" and "what's next" – not just the numbers.
## Features
* **Player Analytics** with season & playoff splits, shot-type breakdowns, and performance radar for any NBA player
* **Cross-Era Comparisons** enabling side-by-side stat comparisons (e.g., Michael Jordan '97 vs. Stephen Curry '22)
* **Team Dashboards** with standings, playoff-probability Sankey flows, and auto-refreshing KPI tiles
* **AI Explain & Similar Players** providing one-click Sonar explanations of stat lines and AI-picked comparable athletes
* **Basketball AI Chat** allowing users to ask an expert LLM about NBA history, rosters, or projections
* **Credit-Based SaaS System** with Firebase Auth, Google login, credit wallets, and admin tooling
## Prerequisites
* Node.js 16+ and npm
* Python 3.8+ and pip
* Firebase project setup
* Perplexity API key (Sonar Pro)
* Basketball-Reference access
## Installation
```bash theme={null}
# Clone the frontend repository
git clone https://github.com/rapha18th/hoop-ai-frontend-44.git
cd hoop-ai-frontend-44
npm install
# Clone the backend repository
git clone https://github.com/rapha18th/4Point-Hoops-Server.git
cd 4Point-Hoops-Server
pip install -r requirements.txt
```
## Configuration
Create `.env` file in the backend directory:
```ini theme={null}
PERPLEXITY_API_KEY=your_sonar_pro_api_key
FIREBASE_PROJECT_ID=your_firebase_project_id
FIREBASE_PRIVATE_KEY=your_firebase_private_key
FIREBASE_CLIENT_EMAIL=your_firebase_client_email
```
## Usage
1. **Start Backend**:
```bash theme={null}
cd 4Point-Hoops-Server
python app.py
```
2. **Start Frontend**:
```bash theme={null}
cd hoop-ai-frontend-44
npm run dev
```
3. **Access Application**: Open the frontend URL and explore NBA analytics with AI-powered insights
4. **Use AI Features**: Click "AI Explain" on any player or stat to get intelligent analysis powered by Perplexity Sonar
## Code Explanation
* **Frontend**: React with shadcn/ui components and Recharts for data visualization
* **Backend**: Python Flask API serving Basketball-Reference data and managing Perplexity API calls
* **Data Pipeline**: BRScraper for real-time data collection with Firebase caching
* **AI Integration**: Perplexity Sonar Pro for intelligent basketball analysis and explanations
* **Authentication**: Firebase Auth with Google login and credit-based access control
* **Deployment**: Frontend on Netlify, backend on Hugging Face Spaces with Docker
## Links
* [Frontend Repository](https://github.com/rapha18th/hoop-ai-frontend-44)
* [Backend Repository](https://github.com/rapha18th/4Point-Hoops-Server)
* [Live Demo](https://4pointhoops.netlify.app/)
* [Devpost Submission](https://devpost.com/software/4point-hoops)
# Ellipsis | One-Click Podcast Generation Agent
Source: https://docs.perplexity.ai/cookbook/showcase/Ellipsis
A next-gen podcast generation agent that brings human-like, high-quality audio content to life on any topic with just one click
**Ellipsis** is a next-generation podcast generation agent that brings human-like, high-quality audio content to life on any topic with just one click. Whether it's breaking news, deep-dive tech explainers, movie reviews, or post-match sports breakdowns, Ellipsis crafts intelligent podcast episodes that sound like they were created by seasoned hosts in a professional studio.
## Features
* **Intelligent Multi-Speaker Dialogue** with multiple distinct voices and personalities
* **Comprehensive Topic Coverage** from LLM architectures to lunar eclipses
* **Custom Evaluation Engine** ensuring factual accuracy, legal compliance, and conversational quality
* **Fully Automated Podcast Generation** with human-like, podcast-ready audio output
* **Real-time Streaming Updates** via Server-Sent Events (SSE)
* **Podbean Integration** for direct podcast publishing
* **Trending Topics Detection** using Perplexity API
## Prerequisites
* Node.js v16+ and npm/yarn
* Python 3.10+ and pip
* Redis server running (default on port 6380)
* Perplexity API key, Podbean credentials
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/dineshkannan010/Ellipsis.git
cd Ellipsis
# Backend setup
cd backend
python -m venv venv
source venv/bin/activate # macOS/Linux
pip install -r requirements.txt
# Install native packages
pip install llama-cpp-python --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpu
pip install git+https://github.com/freddyaboulton/orpheus-cpp.git
pip install huggingface_hub[hf_xet] hf_xet
# Frontend setup
cd ../frontend
npm install
```
## Configuration
Create `backend/.env`:
```ini theme={null}
REDIS_URL=redis://your-redis-host:6379
PERPLEXITY_API_KEY=your_key_here
PODBEAN_CLIENT_ID=...
PODBEAN_CLIENT_SECRET=...
```
Create `frontend/.env`:
```ini theme={null}
REACT_APP_API_URL=http://your-backend-host:5000
```
## Usage
1. **Start Redis Server**:
```bash theme={null}
redis-server --port 6380
```
2. **Launch Backend**:
```bash theme={null}
cd backend
python app.py
```
3. **Launch Frontend**:
```bash theme={null}
cd frontend
npm run dev
```
4. **Optional: Podbean Integration**:
```bash theme={null}
cd backend/integrations/podbean_mcp
pip install -e .
python server.py
python client.py server.py
```
5. **Generate Content**: Enter a topic in the homepage textbox and hit Enter. Switch to `ContentGenerationView` to see live script & audio progress.
## Code Explanation
* **Backend**: Python Flask with Redis pub/sub, llama.cpp, and Orpheus TTS for audio generation
* **Frontend**: React with Vite, Tailwind CSS, and Server-Sent Events for real-time updates
* **AI Integration**: Perplexity API for content generation and trending topics detection
* **Audio Processing**: Multi-speaker TTS with distinct voice personalities
* **Content Evaluation**: Built-in pipelines for factual accuracy and legal compliance
* **Podcast Publishing**: Direct integration with Podbean via MCP server
## Demo Video
## Links
* [GitHub Repository](https://github.com/dineshkannan010/Ellipsis)
* [Devpost Submission](https://devpost.com/software/ellipsis)
# BazaarAISaathi | AI-Powered Indian Stock Market Assistant
Source: https://docs.perplexity.ai/cookbook/showcase/bazaar-ai-saathi
An AI-powered platform for Indian stock market analysis, portfolio optimization, and investment strategies using Perplexity Sonar API
**BazaarAISaathi** is an AI-powered platform designed to empower investors with actionable insights into the Indian stock market. Leveraging advanced natural language processing, real-time data analytics, and expert-driven financial modeling, the app delivers personalized investment strategies, market sentiment analysis, and portfolio optimization recommendations.
## Features
* **Financial Independence Planner (FIRE)** with personalized plans based on age, salary, and goals
* **Investment Advice Tester** using EasyOCR for text extraction and AI validation
* **Fundamental & Technical Analysis** with comprehensive company reports and trading strategies
* **Portfolio Analysis** with multi-dimensional analysis and stock-wise recommendations
* **Market Research & Competitor Benchmarking** using AI-driven industry trend analysis
* **Real-Time Stock Data** with live price tracking and trend analysis
* **Hypothesis Testing** using historical and real-time market data
* **Investment Books Summary** with concise summaries of top 50 investment books
## Prerequisites
* Python 3.8+ and pip
* Streamlit for web application framework
* Perplexity API key (Sonar models)
* Optional: EasyOCR for image text extraction
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/mahanteshimath/BazaarAISaathi.git
cd BazaarAISaathi
# Install dependencies
pip install -r requirements.txt
```
## Configuration
Create `secrets.toml` file for Streamlit secrets:
```ini theme={null}
PERPLEXITY_API_KEY = "your_perplexity_api_key"
# Add other API keys as needed
```
## Usage
1. **Start the Application**:
```bash theme={null}
streamlit run Home.py
```
2. **Access Features**:
* Navigate through different pages for specific functionality
* Use the main dashboard for overview and navigation
* Access specialized tools like portfolio analysis, FIRE planning, and tip testing
3. **Run Specific Modules**:
```bash theme={null}
streamlit run pages/Financial_Independence.py
streamlit run pages/Portfolio_Analysis.py
streamlit run pages/Tip_Tester.py
```
## Code Explanation
* **Frontend**: Streamlit web application with interactive pages and real-time data visualization
* **Backend**: Python-based business logic with Pandas for data manipulation and analysis
* **AI Integration**: Perplexity Sonar API models (sonar-deep-research, sonar-reasoning-pro, sonar-pro) for financial analysis
* **Data Processing**: Real-time stock data fetching, CSV data management, and market insights generation
* **Text Extraction**: EasyOCR integration for processing investment tips from images
* **Portfolio Management**: Comprehensive portfolio analysis with optimization recommendations
* **Market Analysis**: Technical and fundamental analysis with sentiment scoring
## Demo Video
## Links
* [GitHub Repository](https://github.com/mahanteshimath/BazaarAISaathi)
* [Live Application](https://bazaar-ai-saathi.streamlit.app/)
* [Architecture Diagram](https://github.com/mahanteshimath/BazaarAISaathi/raw/main/src/App_Architecture.jpg)
# Briefo | Perplexity Powered News & Finance Social App
Source: https://docs.perplexity.ai/cookbook/showcase/briefo
AI curated newsfeed, social discussion, and deep research reports built on the Sonar API
# Briefo | Perplexity Powered News & Finance Social App
**Briefo** delivers a personalized, AI generated newsfeed and company deep dives. Readers can follow breaking stories, request on demand financial analyses, and discuss insights with friends, all in one mobile experience powered by Perplexity’s Sonar API.
## Features
* Personalized newsfeed across 17 categories with AI summaries and source links
* Private and public threads for article discussion and sharing
* Watch list with real time market snapshots and optional AI analyses
* Deep research reports generated on 12 selectable criteria such as management, competitors, and valuation
* General purpose chat assistant that remembers each user’s preferred topics
## Prerequisites
* Node 18 LTS or newer
* npm, Yarn, or pnpm
* Expo CLI (`npm i -g expo-cli`)
* Supabase CLI 1.0 or newer for local emulation and Edge Function deploys
## Installation
```bash theme={null}
git clone https://github.com/adamblackman/briefo-public.git
cd briefo-public
npm install
```
### Environment variables
```ini theme={null}
# .env (project root)
MY_SUPABASE_URL=https://.supabase.co
MY_SUPABASE_SERVICE_ROLE_KEY=...
PERPLEXITY_API_KEY=...
LINKPREVIEW_API_KEY=...
ALPACA_API_KEY=...
ALPACA_SECRET_KEY=...
# .env.local (inside supabase/)
# duplicate or override any secrets needed by Edge Functions
```
## Usage
Run the Expo development server:
```bash theme={null}
npx expo start
```
Deploy Edge Functions when you are ready:
```bash theme={null}
supabase functions deploy perplexity-news perplexity-chat perplexity-research portfolio-tab-data
```
## Code Explanation
* Frontend: React Native with Expo Router (TypeScript) targeting iOS, Android, and Web
* Backend: Supabase (PostgreSQL, Row Level Security, Realtime) for data and authentication
* Edge Functions: TypeScript on Deno calling Perplexity, Alpaca, Alpha Vantage, and LinkPreview APIs
* Hooks: Reusable React Query style data hooks live in lib/ and hooks/
* Testing and Linting: ESLint, Prettier, and Expo Lint maintain code quality
## Links
[GitHub Repository](https://github.com/adamblackman/briefo-public)
[Live Demo](https://www.briefo.fun/)
# CityPulse | AI-Powered Geospatial Discovery Search
Source: https://docs.perplexity.ai/cookbook/showcase/citypulse-ai-search
Real-time local discovery search using Perplexity AI for personalized location insights and recommendations
# CityPulse - AI-Powered Geospatial Discovery

CityPulse is an intelligent location-based discovery search that helps users explore what's happening around them right now. It demonstrates how to create personalized, real-time local insights using Perplexity's Sonar models.
[](https://youtu.be/Y0UIhh3diJg)
## What CityPulse Does
* **Real-time local discovery** - Find current events, restaurants, and local alerts near any location
* **AI-powered search suggestions** - Get intelligent search recommendations as you type
* **Personalized insights** - Receive AI-generated advice on what to try, best times to visit, and pro tips
* **Interactive mapping** - Explore results on an interactive map with custom markers and detailed popups

## How It Uses Perplexity Sonar
CityPulse leverages two key Perplexity models:
**Sonar for Real-Time Data**
```python theme={null}
# Get current local information with geographic context
response = client.chat.completions.create(
model="sonar",
messages=[{
"role": "user",
"content": f"Find current events, restaurants, and alerts near {lat}, {lng}"
}],
response_format={"type": "json_schema", "json_schema": {"schema": LOCAL_INFO_SCHEMA}}
)
```
**Sonar Reasoning for Personalized Insights**
```python theme={null}
# Generate AI-powered location recommendations
response = client.chat.completions.create(
model="sonar-reasoning",
messages=[{
"role": "user",
"content": f"Provide personalized insights for {location_name}: what to try, best times to visit, pro tips"
}]
)
```
The app uses structured JSON schemas to ensure consistent data formatting and includes citation tracking for source verification.

## Links
* [GitHub Repository](https://github.com/anevsky/CityPulse)
* [Live Demo](https://citypulse-ppx.uc.r.appspot.com/)
* **[Built with ❤️ by Alex Nevsky](https://alexnevsky.com)**
# CycleSyncAI | Personalized Health Plans Powered by Sonar API
Source: https://docs.perplexity.ai/cookbook/showcase/cycle-sync-ai
iOS app that delivers personalized diet and workout recommendations for women, powered by Apple HealthKit and Perplexity's Sonar Pro API.
**CycleSyncAI** is an iOS app designed to provide personalized **diet and workout recommendations** tailored to a woman's **menstrual cycle phase**.
By integrating menstrual data from Apple **HealthKit** and optional user profile inputs (age, weight, height, medical conditions, dietary restrictions, goals, and preferences), the app generates dynamic, phase-aware suggestions to support holistic wellness.
Unlike static wellness tools, **CycleSyncAI** leverages **Perplexity's Sonar Pro API** to deliver **expert-informed**, LLM-generated guidance — including a daily grocery list and motivational feedback — customized to the user's cycle and lifestyle.
## Problem & Solution
> **Why it matters:**\
> Most apps overlook the hormonal changes that affect women's fitness and nutrition needs across their cycle, leaving users with generic advice.
**CycleSyncAI** bridges this gap by combining Apple HealthKit data with Sonar Pro's LLM to generate **adaptive, cycle-aware recommendations** for better health outcomes.
## Features
* **Personalized diet & workout suggestions** per cycle phase
* Syncs with Apple HealthKit for real-time cycle tracking
* User profile inputs for advanced personalization (age, goals, restrictions, etc.)
* **Auto-generated daily grocery list**
* Smooth, modern UI with gradients and subtle animations
* **Motivational AI feedback** tailored to user preferences
* Local data storage and private processing
## Motivation
> "I wanted a tailored regime for myself and couldn't find it all in one place."
**CycleSyncAI** was born from the need for a science-backed, easy-to-use app that adapts wellness guidance to women's natural hormonal rhythms, something missing in most mainstream fitness and nutrition platforms.
## Repository Structure
```text theme={null}
CycleSyncAI.xcodeproj → Xcode project file
CycleSyncAI/ → Source code
├── EatPlanViewController.swift → Diet plan generation & display
├── WorkoutPlanViewController.swift → Workout plan generation & display
├── HomepageViewController.swift → Navigation & main screen
├── UserProfileViewController.swift → Input & storage of user data
├── HealthManager.swift → Apple HealthKit menstrual data
├── UserProfile.swift → Local profile model
Main.storyboard → App UI & layout
Assets.xcassets → Images & app icons
Info.plist → Permissions & configurations
```
## Setup Instructions
1. Clone the repo
2. Open in **Xcode**
3. Ensure Apple HealthKit is enabled on your device
4. Insert your **Sonar Pro API key**
5. Run the app on a physical device (recommended)
## Sonar API Usage
The app sends structured prompts to the **Sonar Pro API** including:
* Cycle phase (from HealthKit)
* User profile info (age, weight, goals, etc.)
* Meal preferences & restrictions
In return, it receives:
* **Personalized diet plan**
* **Custom workout plan**
* **Daily grocery list**
* **Motivational feedback**
These are parsed and rendered as styled HTML inside the app using WebViews.
## Demo Video
> *Note: The LLM takes \~30–60 seconds per request. This wait time was trimmed in the video for brevity.*
## Impact
**CycleSyncAI** empowers women to make informed, body-aware decisions in daily life. The app supports better:
* Energy management
* Fitness results
* Mental well-being
* Motivation and confidence
It also reduces decision fatigue with automatically prepared grocery lists and uplifting guidance.
## Links
* [GitHub Repository](https://github.com/medhini98/cyclesyncai-api-cookbook)
# Daily News Briefing | AI-Powered News Summaries for Obsidian
Source: https://docs.perplexity.ai/cookbook/showcase/daily-news-briefing
An Obsidian plugin that delivers AI-powered daily news summaries directly to your vault using Perplexity's Sonar API for intelligent content curation
**Daily News Briefing** is an Obsidian plugin that delivers AI-powered news summaries directly to your vault. Stay informed about your topics of interest with smart, automated news collection and summarization using Perplexity's Sonar API for intelligent content curation.
## Features
* **Personalized News Collection** based on your topics of interest and preferences
* **AI-Powered Summarization** of news articles using Perplexity Sonar API
* **Automated Daily Briefings** delivered directly to your Obsidian vault
* **Customizable Delivery Schedule** and format options
* **Seamless Obsidian Integration** with your existing knowledge management workflow
* **Trusted Source Filtering** to ensure quality and reliability
* **Markdown Formatting** for easy linking and organization within your vault
## Prerequisites
* Obsidian desktop app installed
* Perplexity API key (Sonar API access)
* Internet connection for fetching news articles
* TypeScript development environment (for customization)
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/ChenziqiAdam/Daily-News-Briefing.git
cd Daily-News-Briefing
# Install dependencies
npm install
# Build the plugin
npm run build
```
## Configuration
1. **Install Plugin**: Copy the built plugin to your Obsidian plugins folder
2. **Enable Plugin**: Activate in Obsidian settings
3. **API Setup**: Enter your Perplexity API key in plugin settings
4. **Configure Topics**: Set up your news topics and delivery preferences
## Usage
1. **Configure Interests**: Set up preferred topics, sources, and delivery schedule
2. **Automated Collection**: Plugin uses Perplexity Sonar API to gather latest news
3. **AI Summarization**: Articles are processed and summarized using Perplexity's capabilities
4. **Vault Delivery**: Summaries are formatted as Markdown notes in your Obsidian vault
5. **Knowledge Integration**: Link news briefings with other notes in your knowledge base
## Code Explanation
* **Frontend**: TypeScript-based Obsidian plugin with custom UI components
* **AI Integration**: Perplexity Sonar API for intelligent news gathering and summarization
* **Content Processing**: Automated article extraction and summarization workflows
* **Scheduling**: Configurable delivery schedules and topic monitoring
* **Markdown Generation**: Structured content formatting for Obsidian compatibility
* **Error Handling**: Robust error management for API limits and network issues
## Technical Implementation
The plugin leverages Perplexity Sonar API for:
```typescript theme={null}
// News gathering with Perplexity Sonar API
const newsQuery = `latest news about ${topic} in the past 24 hours`;
const searchResponse = await perplexityClient.search({
query: newsQuery,
max_results: 5,
include_domains: userPreferences.trustedSources || []
});
// AI-powered summarization
const summaryPrompt = `Summarize these news articles about ${topic}`;
const summaryResponse = await perplexityClient.generate({
prompt: summaryPrompt,
model: "sonar-medium-online",
max_tokens: 500
});
```
## Links
* [GitHub Repository](https://github.com/ChenziqiAdam/Daily-News-Briefing)
# Executive Intelligence | AI-Powered Strategic Decision Platform
Source: https://docs.perplexity.ai/cookbook/showcase/executive-intelligence
A comprehensive Perplexity Sonar-powered application that provides executives and board members with instant, accurate, and credible intelligence for strategic decision-making
**Executive Intelligence** is a comprehensive Perplexity Sonar-powered application that provides executives and board members with instant, accurate, and credible intelligence for strategic decision-making. It delivers board-ready insights derived from real-time data sources, powered by Perplexity's Sonar API.
## Features
* **Competitive Intelligence Briefs** with comprehensive, board-ready competitive analysis and verifiable citations
* **Scenario Planning ("What If?" Analysis)** for dynamic future scenario generation based on real-time data
* **Board Pack Memory** for saving and organizing intelligence briefs, scenario analyses, and benchmark reports
* **Instant Benchmarking & Peer Comparison** with source-cited visual comparisons across critical metrics
* **Real-time Data Integration** leveraging Perplexity Sonar API for up-to-date market intelligence
* **Professional Formatting** with structured reports, executive summaries, and board-ready presentations
## Prerequisites
* Node.js 18+ and npm/yarn
* Git
* Perplexity API key (Sonar Pro)
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/raishs/perplexityhackathon.git
cd perplexityhackathon
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env.local
```
## Configuration
Create `.env.local` file:
```ini theme={null}
PERPLEXITY_API_KEY=your_perplexity_api_key
```
## Usage
1. **Start Development Server**:
```bash theme={null}
npm run dev
```
2. **Access Application**: Open [http://localhost:3000](http://localhost:3000) in your browser
3. **Generate Intelligence**:
* Enter a company name in the input field
* Click "Competitive Analysis" for comprehensive briefs
* Use "Scenario Planning" for "what-if" analysis
* Access "Benchmarking" for peer comparisons
* Save reports to "Board Pack" for later access
4. **Board Pack Management**: Use the "📁 Board Pack" button to view and manage saved intelligence reports
## Code Explanation
* **Frontend**: Next.js with TypeScript and React for modern, responsive UI
* **Backend**: Next.js API routes handling Perplexity Sonar API integration
* **AI Integration**: Perplexity Sonar Pro for real-time competitive intelligence and scenario analysis
* **State Management**: React Context for boardroom memory and persistent data storage
* **Markdown Processing**: Custom utilities for parsing AI responses and citation handling
* **Error Handling**: Comprehensive timeout and error management for API calls
* **Professional Output**: Structured formatting for board-ready presentations with source citations
## Links
* [GitHub Repository](https://github.com/raishs/perplexityhackathon)
# Fact Dynamics | Real-time Fact-Checking Flutter App
Source: https://docs.perplexity.ai/cookbook/showcase/fact-dynamics
Cross-platform app for real-time fact-checking of debates, speeches, and images using Perplexity's Sonar API
# Fact Dynamics | Real-time Fact-Checking Flutter App
**Hackathon Submission** - Built for Perplexity Hackathon in Information Tools & Deep Research categories.
Fact Dynamics is a cross-platform Flutter app that provides real-time fact-checking for spoken content and images. Perfect for live debates, presentations, and on-the-fly information verification.
## Features
* Real-time speech transcription and fact-checking during live conversations
* Image text extraction and claim verification with source citations
* Claim rating system (TRUE, FALSE, MISLEADING, UNVERIFIABLE) with explanations
* Source citations - Provides authoritative URLs backing each verdict
* Debate mode with continuous speech recognition and streaming feedback
* User authentication via Firebase (Google, Email) with persistent chat history
* Cross-platform support for iOS, Android, and Web
## Prerequisites
* Flutter SDK 3.0.0 or newer
* Dart SDK 2.17.0 or newer
* Firebase CLI for authentication and database setup
* Perplexity API key for Sonar integration
* Device with microphone access for speech recognition
## Installation (Follow Detailed guideline on the Repository)
```bash theme={null}
git clone https://github.com/vishnu32510/fact_pulse.git
cd fact_pulse
flutter pub get
```
## Usage
### Real-time Speech Fact-Checking
* Streams 5-second audio chunks through Flutter's `speech_to_text`
* Sends transcribed snippets to Sonar API with structured prompts
* Returns JSON with claims, ratings (TRUE/FALSE/MISLEADING/UNVERIFIABLE), explanations, and sources
### Image Analysis
* Uploads images/URLs to Sonar API for text extraction
* Verifies extracted claims against authoritative sources
* Provides comprehensive analysis with source attribution
## Screenshots
## Code Explanation
* Frontend: Flutter with BLoC pattern for state management targeting iOS, Android, and Web
* Backend: Firebase (Firestore, Authentication) for user data and chat history persistence
* Speech Processing: speech\_to\_text package for real-time audio transcription
* API Integration: Custom Dart client calling Perplexity Sonar API with structured prompts
* Image Processing: Built-in image picker with base64 encoding for multimodal analysis
* Data Architecture: Firestore collections per user with subcollections for debates, speeches, and images
## Open Source SDKs
Built two reusable packages for the Flutter community:
* **[perplexity\_dart](https://pub.dev/packages/perplexity_dart)** - Core Dart SDK for Perplexity API
* **[perplexity\_flutter](https://pub.dev/packages/perplexity_flutter)** - Flutter widgets and BLoC integration
## Demo Video
## Links
* **[GitHub Repository](https://github.com/vishnu32510/fact_pulse)** - Full source code
* **[Live Demo](https://fact-pulse.web.app/)** - Try the web version
* **[Devpost Submission](https://devpost.com/software/fact-dynamics)** - Hackathon entry
# FirstPrinciples | AI Learning Roadmap Generator
Source: https://docs.perplexity.ai/cookbook/showcase/first-principle
An AI-powered learning roadmap generator that uses conversational AI to help users identify specific learning topics and provides personalized step-by-step learning plans
**FirstPrinciples App** is an AI-powered tool that transforms your broad learning goals into structured, personalized roadmaps. Through an interactive chat, the AI engages you in a conversation, asking targeted questions to refine your learning needs before generating a detailed plan. The application is built to help you learn more efficiently by providing a clear path forward.
## Features
* **Interactive Chat Interface** for defining and refining learning goals through conversation
* **AI-Powered Topic Narrowing** with smart, targeted questions to specify learning objectives
* **Session Management** allowing multiple roadmap discussions and progress tracking
* **Visual Progress Indicators** showing when sufficient information has been gathered
* **Personalized Learning Plans** with structured, step-by-step roadmaps
* **Conversational AI Flow** combining OpenAI and Perplexity APIs for intelligent interactions
## Prerequisites
* Python 3.8+ and pip
* Node.js 16+ and npm
* OpenAI API key
* Perplexity API key
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/william-Dic/First-Principle.git
cd First-Principle
# Backend setup
cd flask-server
pip install -r requirements.txt
# Frontend setup
cd ../client
npm install
```
## Configuration
Create `.env` file in the `flask-server` directory:
```ini theme={null}
OPENAI_API_KEY=your_openai_api_key
PPLX_API_KEY=your_perplexity_api_key
PERPLEXITY_API_KEY=your_perplexity_api_key
```
## Usage
1. **Start Backend**:
```bash theme={null}
cd flask-server
python server.py
```
Server runs on [http://localhost:5000](http://localhost:5000)
2. **Start Frontend**:
```bash theme={null}
cd client
npm start
```
Client runs on [http://localhost:3000](http://localhost:3000)
3. **Generate Roadmap**:
* Open [http://localhost:3000](http://localhost:3000) in your browser
* Describe what you want to learn in the chat interface
* Answer AI follow-up questions to refine your learning goals
* Receive a personalized, structured learning roadmap
## Code Explanation
* **Frontend**: React application with conversational chat interface and progress indicators
* **Backend**: Flask server managing API calls, session state, and conversation flow
* **AI Integration**: Combines OpenAI API for conversational flow and Perplexity API for intelligent topic analysis
* **Session Management**: Tracks conversation state and learning goal refinement
* **Roadmap Generation**: Creates structured, actionable learning plans based on user input
* **Conversational Flow**: Implements goal-oriented dialogue to narrow down learning objectives
## Links
* [GitHub Repository](https://github.com/william-Dic/First-Principle.git)
* [Demo Video](https://github.com/user-attachments/assets/6016c5dd-6c18-415e-b982-fafb56170b87)
# FlameGuardAI | AI-powered wildfire prevention
Source: https://docs.perplexity.ai/cookbook/showcase/flameguardai
AI-powered wildfire prevention using OpenAI Vision + Perplexity Sonar API
## 🧠 What it does
**FlameGuard AI™** helps homeowners, buyers, and property professionals detect and act on **external fire vulnerabilities** like wildfires or neighboring structure fires. It's more than a scan — it's a personalized research assistant for your home.
### Demo
### Try it out
* [FlameGuard AI](https://flameguardai.dlyog.com)
* [FlameGuard AI MCP](https://flameguardai-mcp.dlyog.com)
* [GitHub Repo](https://github.com/dlyog/fire-risk-assessor-drone-ai)
### Key Features:
* 📸 Upload a home photo
* 👁️ Analyze visible fire risks via **OpenAI Vision API**
* 📚 Trigger deep research using the **Perplexity Sonar API**
* 📄 Get a detailed, AI-generated report with:
* Risk summary
* Prevention strategies
* Regional best practices
* 🛠️ Optional contractor referrals for mitigation
* 💬 Claude (MCP) chatbot integration for conversational analysis
* 🧾 GDPR-compliant data controls
Whether you're protecting your home, buying a new one, or just want peace of mind — **FlameGuard AI™ turns a photo into a plan**.
## ⚙️ How it works
### The FlameGuard AI™ Process
1. **📸 Upload**: User uploads a photo of their property
2. **👁️ AI Vision Analysis**: OpenAI Vision API identifies specific vulnerabilities (e.g., flammable roof, dry brush nearby)
3. **🔍 Deep Research**: For each risk, we generate a **custom research plan** and run **iterative agentic-style calls** to Perplexity Sonar
4. **📄 Report Generation**: Research is **aggregated, organized, and formatted** into an actionable HTML report — complete with citations, links, and visual guidance
5. **📧 Delivery**: Detailed report sent via email with DIY solutions and professional recommendations
### 🔍 Deep Research with Perplexity Sonar API
The real innovation is how we use the **Perplexity Sonar API**:
* We treat it like a research assistant gathering the best available information
* Each vulnerability triggers multiple queries covering severity, mitigation strategies, and localized insights
* Results include regional fire codes, weather patterns, and local contractor availability
This kind of **structured, trustworthy, AI-powered research would not be possible without Perplexity**.
### Technical Stack
FlameGuard AI™ is powered by a modern GenAI stack and built to scale:
* **Frontend**: Lightweight HTML dashboard with user account control, photo upload, and report access
* **Backend**: Python (Flask) with RESTful APIs
* **Database**: PostgreSQL (local) with **Azure SQL-ready** schema
* **AI Integration**: OpenAI Vision API + Perplexity Sonar API
* **Cloud-ready**: Built for **Azure App Service** with Dockerized deployment
## 🏆 Accomplishments that we're proud of
* Successfully used **OpenAI Vision + Perplexity Sonar API** together in a meaningful, real-world workflow
* Built a functioning **MCP server** that integrates seamlessly with Claude for desktop users
* Created a product that is **genuinely useful for homeowners today** — not just a demo
* Kept the experience simple, affordable, and scalable from the ground up
* Made structured deep research feel accessible and trustworthy
## 📚 What we learned
* The **Perplexity Sonar API** is incredibly powerful when used agentically — not just for answers, but for reasoning.
* Combining **multimodal AI (image + research)** opens up powerful decision-support tools.
* Users want **actionable insights**, not just data — pairing research with guidance makes all the difference.
* Trust and clarity are key: our design had to communicate complex information simply and helpfully.
## 🚀 What's next for FlameGuard AI™ - Prevention is Better Than Cure
We're just getting started.
### Next Steps:
* 🌐 Deploy to **Azure App Services** with production-ready database
* 📱 Launch mobile version with location-based scanning
* 🏡 Partner with **home inspection services** and **homeowners associations**
* 💬 Enhance Claude/MCP integration with voice-activated AI reporting
* 💸 Introduce B2B plans for real estate firms and home safety consultants
* 🛡️ Expand database of **local contractor networks** and regional fire codes
We're proud to stand with homeowners — not just to raise awareness, but to enable action.
**FlameGuard AI™ – Because some homes survive when others don't.**
***
**Contact us to know more: [info@dlyog.com](mailto:info@dlyog.com)**
# Flow & Focus | Personalized News for Genuine Understanding
Source: https://docs.perplexity.ai/cookbook/showcase/flow-and-focus
A personalized news app combining vertical feed discovery with AI-powered deep dives using Perplexity Sonar Pro and Deep Research models
**Flow & Focus** is a personalized news application that transforms news consumption into a learning experience. It uniquely combines rapid discovery through a vertical news feed (Flow) with in-depth, interactive learning dialogues (Focus), powered by Perplexity's Sonar Pro and Sonar Deep Research models.
## Features
* **Dual Mode Interface**: Flow Feed for quick news discovery and Focus for personalized deep dives
* **Vertical News Feed**: Swipeable news snippets with AI-generated summaries, tags, and background images
* **Interactive Deep Dives**: Tap key phrases for focused content, with horizontally scrollable detail panes
* **Personalized Learning**: AI-powered conversation segments with personas like "Oracle" and "Explorer"
* **Smart Personalization**: Tracks reading patterns to tailor content selection automatically
* **Real-time Content**: Leverages Sonar Pro for up-to-date news and Sonar Deep Research for detailed analysis
* **Visual Enhancement**: Dynamic background images generated via Runware.ai based on content keywords
## Prerequisites
* Node.js 18+ and npm
* Perplexity API key
* Runware API key for image generation
* Next.js 15 and React 19 environment
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/michitomo/NewsReel.git
cd NewsReel
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env.local
```
## Configuration
Create `.env.local` file:
```ini theme={null}
PERPLEXITY_API_KEY=your_perplexity_api_key_here
RUNWARE_API_KEY=your_runware_api_key_here
PERPLEXITY_FOCUS_MODEL=sonar-deep-research
```
## Usage
1. **Start Development Server**:
```bash theme={null}
npm run dev
```
2. **Access Application**: Open [http://localhost:3000](http://localhost:3000) in your browser
3. **Flow Feed**: Scroll vertically through news snippets and tap key phrases for deep dives
4. **Focus Mode**: Generate personalized digests with interactive conversation segments
5. **Personalization**: Your viewing patterns automatically influence content selection
## Code Explanation
* **Frontend**: Next.js 15 with React 19, TypeScript, Tailwind CSS, and Framer Motion for animations
* **State Management**: Zustand with localStorage persistence for user preferences
* **AI Integration**: Perplexity Sonar Pro for real-time news and Sonar Deep Research for in-depth analysis
* **Image Generation**: Runware SDK integration for dynamic background images based on content keywords
* **API Routes**: Server-side integration handling Perplexity and Runware API calls
* **Mobile-First Design**: Swipe gestures and responsive layout for intuitive mobile experience
## Links
* [GitHub Repository](https://github.com/michitomo/NewsReel)
* [Demo Video](https://www.youtube.com/watch?v=09h7zluuhQI)
* [Perplexity Hackathon](https://perplexityhackathon.devpost.com/)
* [Perplexity Hackathon Project](https://devpost.com/software/flow-focus)
# Greenify | Localized community-driven greenification/plantation solution with AI
Source: https://docs.perplexity.ai/cookbook/showcase/greenify
A mobile application that analyzes photos and location data to suggest suitable plants and build sustainable communities using Perplexity Sonar API
**Greenify** is a mobile application designed to encourage sustainable practices by analyzing live images and building communities. Users capture photos of their space (balcony, roadside, basement, etc.) and Greenify automatically analyzes the image using Perplexity's Sonar API to suggest suitable plants for that location. The app also connects like-minded people in the locality to create communities for sustainable, economic, and social growth.
## Features
* **AI-Powered Plant Analysis** using image recognition and location data to suggest suitable plants
* **Location-Based Recommendations** considering weather, sunlight, and environmental conditions
* **Community Building** connecting users with similar plant interests and sustainable goals
* **Cross-Platform Mobile App** built with Expo for iOS, Android, and web
* **Real-time Weather Integration** for accurate plant suitability assessment
* **Structured JSON Output** using Pydantic models for consistent data handling
* **AR Model Support** for enhanced plant visualization
## Abstract Data Flow Diagram

## Prerequisites
* Node.js 20.19.4+ and npm
* Python 3.10.0+ and pip
* Expo CLI and SDK 51+
* Perplexity API key (Sonar Pro and Sonar Deep Research)
* Android SDK/Studio or Xcode (for local builds)
* Mobile device with camera for image capture
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/deepjyotipaulhere/greenify.git
cd greenify
# Install frontend dependencies
npm install
# Install backend dependencies
cd service
pip install -r requirements.txt
```
## Configuration
Create `.env` file in the `service` directory:
```ini theme={null}
PPLX_API_KEY=your_perplexity_api_key_here
```
## Usage
1. **Start Backend Service**:
```bash theme={null}
cd service
python app.py
```
2. **Start Frontend App**:
```bash theme={null}
npx expo start
```
3. **Access the App**:
* Install Expo Go app and scan QR code, or
* Open web browser on mobile and navigate to the URL shown
4. **Use the App**:
* Grant camera and location permissions
* Take a photo of your space (balcony, garden, etc.)
* Receive AI-powered plant recommendations
* Connect with nearby users for community building

## Code Explanation
* **Frontend**: React Native with Expo for cross-platform mobile development
* **Backend**: Python Flask API handling image processing and Perplexity API integration
* **AI Integration**: Perplexity Sonar Pro for image analysis and Sonar Deep Research for plant recommendations
* **Data Models**: Pydantic models for structured JSON output and data validation
* **Image Processing**: Real-time image analysis with location-based context
* **Community Features**: User matching based on plant suggestions and sustainable interests
* **Weather Integration**: Real-time weather data for accurate plant suitability assessment
## Links
* [GitHub Repository](https://github.com/deepjyotipaulhere/greenify)
* [Live Demo](https://greenify.expo.app)
# Monday – Voice-First AI Learning Assistant
Source: https://docs.perplexity.ai/cookbook/showcase/monday
An accessible, multimodal AI learning companion that delivers contextual reasoning, 3D visualizations, and curated educational content via natural voice interaction.
**Monday** is a voice-enabled AI learning companion designed to bridge the gap between natural language queries and high-quality educational content. Inspired by Marvel's JARVIS and FRIDAY, Monday delivers tailored responses in three modes—Basic, Reasoning, and Deep Research—while integrating immersive visualizations, curated video content, and accessibility-first design.
## Features
* **Three Learning Modes**: Basic factual answers, step-by-step reasoning, and deep research investigations
* **Voice-first interaction** for hands-free learning with natural language processing
* **Real-time 3D visualizations** of concepts using Three.js & WebXR
* **Curated educational YouTube video integration** from trusted sources
* **Multi-modal feedback** combining text, speech (via ElevenLabs), and spatial panels
* **VR-optional design** for immersive experiences without requiring a headset
* **Accessibility-focused interface** for mobility- and vision-impaired users
## Prerequisites
* Node.js 18 LTS or newer
* Modern web browser (Chrome, Edge, or Firefox recommended)
* Microphone for voice interaction
* Optional: VR headset for immersive mode (WebXR compatible)
* Perplexity API key, ElevenLabs API key, and YouTube API key
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/srivastavanik/monday.git
cd monday
git checkout final
cd nidsmonday
# Install dependencies
npm install
```
```ini theme={null}
# Create a .env file and set your API keys
PERPLEXITY_API_KEY=your_api_key
ELEVENLABS_API_KEY=your_api_key
YOUTUBE_API_KEY=your_api_key
```
```bash theme={null}
# Start Backend Server
node backend-server.js
# Start frontend
npm run dev
```
## Usage
1. Launch the app in your browser
2. Say **"Hey Monday"** to activate the assistant
3. Ask a question in one of three modes:
* **Basic Mode** – "What is photosynthesis?"
* **Reasoning Mode** – "Think about how blockchain works."
* **Deep Research Mode** – "Research into the history of quantum mechanics."
4. View answers as floating text panels, voice responses, and interactive 3D models
## Code Explanation
* **Frontend**: TypeScript with Three.js for 3D visualizations and WebXR for VR support
* **Backend**: Node.js with Socket.IO for real-time voice command processing
* **AI Integration**: Perplexity Sonar API for intelligent responses with reasoning extraction
* **Voice Processing**: ElevenLabs for speech synthesis and natural language understanding
* **Content Curation**: YouTube API integration with smart keyword extraction for educational videos
* **Accessibility**: Voice-first design with spatial audio and haptic feedback support
## Demo Video
## Links
* [GitHub Repository](https://github.com/srivastavanik/monday/tree/final)
# MVP LifeLine | AI Youth Empowerment Platform
Source: https://docs.perplexity.ai/cookbook/showcase/mvp-lifeline-ai-app
A multilingual, offline-first AI platform that helps underserved youth Earn, Heal, and Grow using real-time AI and holistic tools
**MVP LifeLine** is a multilingual, offline-first AI platform empowering youth emotionally, financially, and professionally—anytime, anywhere. Over 1.3 billion youth globally face barriers to career opportunities and mental well-being, especially in underserved and remote regions. MVP LifeLine breaks these barriers by combining AI, offline access, multilingual support, and a holistic tool ecosystem.
## Features
* **Dual Mode AI** with Career Coach and Emotional Companion powered by Perplexity Sonar API
* **Multilingual Support** across 10+ languages including English, French, Arabic, Spanish, Hindi, and regional languages
* **Offline-First Design** with SMS/USSD integration for low-connectivity regions
* **Holistic Tool Ecosystem** covering career, wellness, finance, and productivity
* **SmartQ Access** for context-aware, emotionally intelligent AI responses
* **Digital Hustle Hub** with AI gig discovery and freelancing tools
* **Wellness Zone** with guided meditations and mental reset prompts
* **Finance Zone** with budget tracking and youth-friendly money tips
* **Productivity Zone** with AI Kanban board and habit tracking
## Prerequisites
* Flutter SDK and Dart
* Firebase project setup
* Twilio account for SMS/USSD integration
* Perplexity API key (Sonar)
* OpenAI API key (for augmentation)
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/JohnUmoh/asgard.git
cd asgard
# Install Flutter dependencies
flutter pub get
# Configure Firebase
flutterfire configure
# Set up environment variables
cp .env.example .env
```
## Configuration
Create `.env` file:
```ini theme={null}
PERPLEXITY_API_KEY=your_sonar_api_key
OPENAI_API_KEY=your_openai_api_key
FIREBASE_PROJECT_ID=your_firebase_project_id
TWILIO_ACCOUNT_SID=your_twilio_sid
TWILIO_AUTH_TOKEN=your_twilio_token
```
## Usage
1. **Setup Firebase**:
```bash theme={null}
flutterfire configure
```
2. **Run the Application**:
```bash theme={null}
flutter run
```
3. **Access Features**:
* Switch between Career Coach and Emotional Companion modes
* Use SmartQ for AI-powered assistance in multiple languages
* Access offline features via SMS/USSD when connectivity is limited
* Explore career tools, wellness features, and productivity boosters
## Code Explanation
* **Frontend**: Flutter cross-platform application with responsive design for mobile and web
* **Backend**: Firebase for authentication, data storage, and real-time synchronization
* **AI Integration**: Perplexity Sonar API for dual-mode AI interactions (Career Coach & Emotional Companion)
* **Offline Support**: Twilio integration for SMS/USSD communication in low-connectivity areas
* **Multilingual**: Sonar API handling 10+ languages with context-aware responses
* **Data Sync**: Offline data capture with automatic re-sync when connectivity returns
* **Personalization**: AI adapts to user's language, literacy level, mood history, and preferences
## Links
* [GitHub Repository](https://github.com/JohnUmoh/asgard)
* [Live Demo](https://mvplifelineaiapp.netlify.app)
# PerplexiCart | AI-Powered Value-Aligned Shopping Assistant
Source: https://docs.perplexity.ai/cookbook/showcase/perplexicart
An AI shopping assistant that uses Perplexity Sonar to deliver structured research, value-aligned recommendations, and transparent citations across the web
**PerplexiCart** helps users make informed, value-aligned purchasing decisions. Powered by the **Perplexity Sonar API**, it analyzes products across the web and returns structured insights with prioritized recommendations, pros/cons, trade‑off analysis, and user sentiment — tailored to preferences like Eco‑Friendly, Durability, Ethical, and region‑specific needs.
## Features
* **Intelligent Product Recommendations** beyond simple spec comparison
* **Priority-Based Value Alignment** (Best Value, Eco‑Friendly, Ethical, Durability, Made in India)
* **Contextual Personalization** (skin type, usage patterns, region, etc.)
* **Structured Research Output** with:
* Research summary and top recommendations
* Value alignment with reasoning
* Pros/Cons and key specifications
* User sentiment and community insights (Reddit, Quora)
* Trade‑off analysis and buying tips
* **Transparent Sources** with citations for verification
## Prerequisites
* Node.js 18+ and npm/yarn
* Python 3.10+ and pip
* Perplexity API key
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/fizakhan90/perplexicart.git
cd perplexicart
# Backend (FastAPI) setup
cd backend
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
# Frontend (Next.js) setup
cd ../frontend
npm install
```
## Configuration
Create a `.env` file in the backend directory:
```ini theme={null}
PERPLEXITY_API_KEY=your_perplexity_api_key
```
(Optional) Add any app‑specific settings as needed (cache, region defaults, etc.).
## Usage
1. **Start Backend (FastAPI)**:
```bash theme={null}
cd backend
uvicorn main:app --reload # adapt module:app if your entrypoint differs
```
2. **Start Frontend (Next.js)**:
```bash theme={null}
cd frontend
npm run dev
```
3. **Open the App**: Visit `http://localhost:3000` and search for a product. Select your priority (e.g., Eco‑Friendly) and add optional context (skin type, region).
## Code Explanation
* **Backend (FastAPI)**: Orchestrates Sonar calls with dynamic prompt engineering based on query, selected priority, and context
* **Structured Outputs**: Enforces a strict JSON schema via `response_format` to ensure consistent UI rendering
* **Live Web Research**: Directs Sonar to search e‑commerce platforms, forums, review blogs, and sustainability reports
* **Semantic Analysis**: Extracts value alignment, pros/cons, sentiment, and cites sources for transparency
* **Frontend (Next.js/React)**: Presents a clear, user‑friendly view of recommendations, trade‑offs, and citations
## How the Sonar API Is Used
PerplexiCart leverages the **Perplexity Sonar API** as its intelligence core, dynamically generating customized prompts based on user inputs like search queries, priorities and context. The API performs comprehensive web research across e-commerce sites, forums, and review platforms, with responses structured in a consistent JSON format. Through semantic analysis, it extracts key product insights including alignment with user priorities, pros/cons, and sentiment - all backed by cited sources. The FastAPI backend processes these structured responses before serving them to the Next.js frontend for a polished user experience.
## Links
* **Live Demo**: [https://perplexicart.vercel.app/](https://perplexicart.vercel.app/)
* **GitHub Repository**: [https://github.com/fizakhan90/perplexicart](https://github.com/fizakhan90/perplexicart)
# PerplexiGrid | Interactive Analytics Dashboards
Source: https://docs.perplexity.ai/cookbook/showcase/perplexigrid
Instantly generate analytics dashboards from natural language using live data via Perplexity Sonar API.
**PerplexiGrid** turns natural language into rich, interactive dashboards. Connect your data and mix it with live web data, ask a question, and let the Sonar API do the rest! Complete with drag-and-drop layout, AI widget generation, and ECharts-powered visualizations.
## Features
* **Natural Language to Dashboards**: Convert plain English prompts into fully functional analytics dashboards with 25+ widget types
* **Live Data Integration**: Blend your own data sources with real-time web data for comprehensive insights
* **Interactive Grid Layout**: Drag-and-drop interface for customizing dashboard layouts and styling
* **AI-Powered Refinement**: Refine or add widgets using conversational updates
* **Export & Share**: Generate PDF exports, high-res images, and shareable dashboard links
## How it uses Sonar
PerplexiGrid leverages the Sonar API through four specialized modes:
* **Full Dashboard Generation (f1)**: Creates comprehensive dashboards with multiple widgets using Sonar Pro's advanced capabilities
* **Lightweight Mode (l1)**: Generates quick visualizations for embedded systems and real-time applications
* **Dashboard Updates (r1)**: Enables dynamic modifications through natural language while maintaining context
* **Widget Refinement (r2)**: Provides precise control over individual widget updates
The system uses structured JSON schema responses to ensure consistent, ECharts-compatible output that can be directly rendered as interactive visualizations.
## Usage
1. Open the app and start a new dashboard
2. Prompt it like: *"Show me market trends in AI startups in 2024"* (Sonar generates chart configs, which are parsed and rendered as live widgets)

3. Rearrange and style the widgets with the grid interface


5. Add your own datasources to blend your data with live web data

6. Refine them via text prompts or export the dashboard as needed
7. Collaborate and share easily

## Code Explanation
The user sends messages that are turned into prompts to a Supabase Edge Function that wraps the Perplexity Sonar API.\
Depending on the mode (`f1`, `l1`, `r1`, or `r2`), the function generates full structured outputs for dashboards, lightweight visualizations, or targeted updates.\
The generated layout is parsed into structured widget definitions and passed through our widget creation engine.
Explore our [main sonar-api service here.](https://github.com/PetarRan/perplexigrid/blob/main/server/supabase/functions/_shared/perplexityService.ts)
## Prompt Modes
| Mode | Description | Use Case | Notes |
| ---- | ------------------------------------ | --------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `f1` | First-time full dashboard generation | User starts with an empty canvas and enters an initial prompt | Produces a complete dashboard layout with multiple widgets |
| `l1` | Lightweight dashboard generation | Used for quick insights or previews with minimal tokens | Faster and cheaper, but returns fewer widgets with less instruction depth |
| `r1` | Full dashboard regeneration | User wants to replace all existing widgets with a new prompt | Rebuilds the entire dashboard while keeping layout intact |
| `r2` | Targeted widget update | User wants to change a specific widget (e.g. "make this a pie chart") | Only the selected widget is modified based on the new instruction |
## Tech Stack
* **Frontend**: React + Vite (TypeScript), ECharts, react-grid-layout
* **Backend**: Supabase Edge Functions (TypeScript on Deno)
* **AI Engine**: Perplexity Sonar Pro
* **Infrastructure**: Supabase (PostgreSQL, RLS, Auth), Vercel deployment
## Links
* [GitHub Repository](https://github.com/PetarRan/perplexigrid)
* [Live Demo](https://app.perplexigrid.com)
* [Website](https://www.perplexigrid.com)
# Perplexity Client | Desktop AI Chat Interface with API Controls
Source: https://docs.perplexity.ai/cookbook/showcase/perplexity-client
An Electron-based desktop client for Perplexity API with advanced features like temperature control, model selection, custom system prompts, and API debugging mode
**Perplexity Client** is an Electron-based desktop application that provides a polished interface for interacting with Perplexity's Sonar API. Unlike typical chat interfaces, it exposes advanced API parameters like temperature, top-p, and max tokens, making it ideal for developers who want fine-grained control over their AI interactions while enjoying a beautiful, macOS-inspired UI.
## Features
* **Multiple Sonar Models** with support for Sonar, Sonar Pro, and Sonar Reasoning Pro
* **Custom Spaces** with save/load functionality for different use cases
* **API Parameter Controls** including temperature, top-p, and max tokens adjustments
* **API Debugging Mode** showing full request/response payloads for troubleshooting
* **Token Usage Tracking** to monitor API consumption and costs
* **Focus Modes** for specialized tasks like coding, writing, and research
## Prerequisites
* Node.js v16 or higher
* npm or yarn
* Perplexity API key
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/straight-heart/Perplexity-client-.git
cd Perplexity-client-
# Install dependencies
npm install
npm run dev
```
## Build
Build the application for your platform:
```bash theme={null}
npm run build:win # Windows
npm run build:mac # macOS
npm run build:linux # Linux
```
## Configuration
API keys are managed directly within the application:
1. Launch the app and open Settings (gear icon)
2. In the **API Keys** section, click **Add Key**
3. Enter your Perplexity API key
4. The key is stored securely and persists across sessions
For custom system prompts, use the **Spaces** feature to save and switch between different instruction sets.
## Usage
1. **Launch**: Run `npm run dev` or use the built application
2. **Add API Key**: Open Settings and add your Perplexity API key
3. **Select Model**: Use the dropdown to choose between Sonar variants
4. **Create Spaces**: Set up custom system prompts for different tasks
5. **Chat**: Start conversing with real-time streaming responses
6. **Debug**: Enable API debugging to see full request/response details
7. **Track Usage**: Monitor token consumption in the Settings panel
## Screenshots
| Feature | Preview |
| ---------------------------- | ------------------------ |
| Spaces (Custom Instructions) | |
| Model & Parameter Controls | |
| API Debugging Mode | |
| Theme Selection | |
## Limitations
* Desktop only (Windows, macOS, Linux) — no mobile or web version
* Requires internet connection for API calls
* API key required for functionality
## Links
* [GitHub Repository](https://github.com/straight-heart/Perplexity-client-)
# Perplexity Dart & Flutter SDKs
Source: https://docs.perplexity.ai/cookbook/showcase/perplexity-flutter
Lightweight, type-safe SDKs for seamless Perplexity API integration in Dart and Flutter applications
# Perplexity Dart & Flutter SDKs
**Perplexity Dart & Flutter SDKs** provide a comprehensive toolkit for integrating Perplexity's AI capabilities into Dart and Flutter applications. Built specifically for the Flutter community, these packages include a lightweight core API client and ready-to-use Flutter widgets with BLoC state management.
## Features
* Type-safe API client with fully typed models and compile-time safety
* Streaming and non-streaming chat completions with real-time response handling
* Support for all Perplexity models (Sonar, Sonar Pro, Deep Research, Reasoning variants)
* Multi-image processing with base64, data URI, and HTTPS URL support
* Ready-to-use Flutter widgets with BLoC state management integration
* Advanced configuration options (temperature, top-p, search filters, domain restrictions)
* Cross-platform support for iOS, Android, Web, and Desktop
* Future-proof design with custom model string support for new Perplexity releases
## Prerequisites
* Dart SDK 2.17.0 or newer
* Flutter SDK 3.0.0 or newer (for Flutter-specific features)
* Perplexity API key from Perplexity API Console
* Basic knowledge of Flutter BLoC pattern for widget integration
## Installation
### For Dart Projects (Core API Only)
```bash theme={null}
dart pub add perplexity_dart
```
### For Flutter Projects (Full Widget Support)
```bash theme={null}
flutter pub add perplexity_flutter
```
### Environment variables
```dart theme={null}
// Add to your app's configuration
const String perplexityApiKey = 'your_perplexity_api_key_here';
```
## Usage
### Core API Integration
* Type-safe client with all Perplexity models (Sonar, Sonar Pro, Deep Research, Reasoning)
* Streaming and non-streaming chat completions
* Multimodal processing with flexible MessagePart system for text + images
### Flutter Widget Layer
* `ChatWrapperWidget` for BLoC state management
* `PerplexityChatView` for real-time message display
* `PerplexityChatInput` for user interaction handling
## Code Explanation
* Core Layer: Pure Dart API client (`perplexity_dart`) for cross-platform Perplexity API integration
* UI Layer: Flutter widgets (`perplexity_flutter`) with BLoC state management for rapid development
* Type Safety: Fully typed models and responses prevent runtime errors and provide IntelliSense
* Multimodal: Flexible MessagePart system for combining text and images in single requests
* Streaming: Built-in support for real-time chat completions with proper chunk handling
* Architecture: Two-layer design allows lightweight API usage or full Flutter widget integration
## Architecture
### Two-layer design
* **Core (`perplexity_dart`)** - Pure Dart API client for all platforms
* **UI (`perplexity_flutter`)** - Flutter widgets + BLoC state management
Uses flexible MessagePart system for multimodal content combining text and images.
## Links
### Packages
* [perplexity\_dart on pub.dev](https://pub.dev/packages/perplexity_dart) | [GitHub](https://github.com/vishnu32510/perplexity_dart)
* [perplexity\_flutter on pub.dev](https://pub.dev/packages/perplexity_flutter) | [GitHub](https://github.com/vishnu32510/perplexity_flutter)
### Examples
* [Flutter Example App](https://github.com/vishnu32510/perplexity_dart/tree/main/example_flutter_app)
* [Dart Examples](https://github.com/vishnu32510/perplexity_dart/tree/main/example)
# Perplexity Lens | AI-Powered Knowledge Graph Browser Extension
Source: https://docs.perplexity.ai/cookbook/showcase/perplexity-lens
A browser extension that builds personalized knowledge graphs using Perplexity AI for smart text selection, webpage summarization, and contextual insights
**Perplexity Lens** is a powerful browser extension that transforms your browsing experience by providing AI-powered insights using Perplexity AI and creating a personalized knowledge graph that visually connects the concepts you encounter online.
## Features
* **Smart Text Selection** with AI-generated explanations for selected text
* **Webpage Summarization** for instant, concise overviews of entire pages
* **Contextual RAG Insights** using Retrieval-Augmented Generation for detailed context and meanings
* **Knowledge Graph Visualization** with interactive D3.js graphs showing concept connections
* **Public Sharing** with URL generation for sharing graphs with others
* **User Authentication** via Firebase for secure access
* **Dual Storage** with local IndexedDB and cloud Firebase storage
* **Responsive UI** fully functional across all devices
## Prerequisites
* Node.js v14+ and npm v6+
* Google Chrome or compatible browser
* Firebase account for cloud functionality
* Firebase CLI (`npm install -g firebase-tools`)
* Perplexity API key and OpenAI API key
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/iamaayushijain/perplexity-lens.git
cd perplexity_lens
# Install dependencies
npm install
# Build the extension
npm run build
```
## Configuration
Edit `src/config.ts`:
```typescript theme={null}
export const PERPLEXITY_API_KEY = 'your-perplexity-key';
export const EMBEDDING_API_KEY = 'your-openai-key';
export const FIREBASE_HOSTING_URL = 'https://your-project-id.web.app';
```
## Usage
1. **Load Extension**: Go to `chrome://extensions/`, enable Developer mode, click "Load unpacked" and select the `dist/` directory
2. **Sign In**: Click the extension icon and authenticate via Firebase
3. **Use Features**:
* **Highlight Text**: Select text on any webpage for AI-powered insights
* **Summarize Page**: Use the "Summarize" feature for webpage overviews
* **Ask Anything**: Hover or click on words/phrases for definitions or explanations
* **View Graph**: Navigate to the Graph tab to see your knowledge graph
* **Explore**: Zoom, drag, and hover over nodes in the interactive graph
* **Share**: Click "Share Graph" to generate a public link
## Code Explanation
* **Frontend**: React with TypeScript and TailwindCSS for modern, responsive UI
* **Browser Extension**: Chrome extension architecture with popup and content scripts
* **AI Integration**: Perplexity AI for intelligent text explanations and summarization
* **Knowledge Graph**: D3.js for interactive graph visualization and concept connections
* **Storage**: Dual storage system with local IndexedDB and cloud Firebase
* **Authentication**: Firebase Auth for secure user access and data management
* **RAG System**: Retrieval-Augmented Generation for contextual insights and definitions
## Links
* [GitHub Repository](https://github.com/iamaayushijain/perplexity-lens)
* [Blog Post](https://ashjin.hashnode.dev/perplexity-lens-supercharge-your-web-experience-with-personalized-knowledge-graphs)
# PosterLens | Scientific Poster Scanner & Research Assistant
Source: https://docs.perplexity.ai/cookbook/showcase/posterlens
An iOS app that transforms static scientific posters into interactive insights using OCR and Perplexity's Sonar Pro API for semantic search and context
**PosterLens** is an iOS app that transforms static scientific posters into interactive, explorable insights using OCR and AI. Created for the Perplexity Hackathon 2025, it allows researchers, MSLs, and medical writers to scan posters and explore them interactively using natural language, extracting meaning and surfacing related studies instantly.

## Features
* **Scientific Poster Scanning** using device camera and Apple Vision OCR
* **Natural Language Q\&A** about poster content with AI-powered responses
* **Semantic Search Integration** using Perplexity Sonar Pro for related studies
* **Citation Validation** with PubMed E-utilities for academic accuracy
* **Auto-Generated Research Questions** and future research directions
* **On-Device Processing** for privacy and performance
* **Interactive Research Experience** transforming static content into dynamic insights
## Prerequisites
* iOS 17+ device with camera
* Xcode 15+ for development
* Apple Developer account for App Store distribution
* Perplexity API key (Sonar Pro)
* OpenAI API key (GPT-3.5)
* PubMed E-utilities access
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/nickjlamb/PosterLens.git
cd PosterLens
# Open in Xcode
open PosterLens.xcodeproj
```
## Configuration
Add your API keys to the project configuration:
```swift theme={null}
// API Configuration
PERPLEXITY_API_KEY=your_sonar_pro_api_key
OPENAI_API_KEY=your_gpt_api_key
PUBMED_API_KEY=your_pubmed_api_key
```
## Usage
1. **Install from App Store**: Download PosterLens from the iOS App Store
2. **Scan Poster**: Point your camera at a scientific poster
3. **OCR Processing**: Apple Vision automatically extracts text content
4. **Ask Questions**: Use natural language to query the poster content
5. **Explore Related Research**: Discover semantically related studies via Sonar Pro
6. **Validate Citations**: Check academic references with PubMed integration
## Code Explanation
* **Frontend**: Native iOS app built with SwiftUI for modern UI/UX
* **OCR Processing**: Apple Vision framework for text extraction from images
* **AI Integration**: Perplexity Sonar Pro API for semantic search and context understanding
* **Natural Language**: GPT-3.5 for Q\&A and content interpretation
* **Academic Validation**: PubMed E-utilities for citation verification
* **On-Device Processing**: Local OCR and processing for privacy and performance
* **Research Enhancement**: Auto-generation of research questions and future directions
## Links
* [GitHub Repository](https://github.com/nickjlamb/PosterLens)
* [App Store](https://apps.apple.com/us/app/posterlens-research-scanner/id6745453368)
# Sonar Chromium Browser | Native Search Omnibox and Context Menu
Source: https://docs.perplexity.ai/cookbook/showcase/sonar-chromium-browser
Chromium browser patch with native Perplexity Sonar API integration providing omnibox answers and context-menu summarization
**Sonar Chromium Browser** is a Chromium browser patch that natively integrates Perplexity's Sonar API to provide AI-powered functionality directly in the browser. Users can type `sonar ` in the omnibox for instant AI answers or select text and right-click "Summarize with Sonar" for quick summaries, streamlining research and browsing workflows.
## Features
* **Omnibox AI Answers** with `sonar ` syntax for instant responses
* **Context-menu Summarization** for selected text with one-click access
* **Native Browser Integration** using Chromium's omnibox and context-menu APIs
* **Dual Model Support** using Sonar Pro for omnibox and Sonar for summaries
* **Debounced Input Handling** for efficient API usage
* **Custom Browser Build** demonstrating AI integration patterns
## Prerequisites
* Ubuntu 22.04 (WSL2 recommended)
* Chromium source code checkout
* Perplexity API key
* 16GB+ RAM for Chromium build
* Git and standard build tools
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/KoushikBaagh/perplexity-hackathon-chromium.git
cd perplexity-hackathon-chromium
# Apply patches to Chromium source
# Follow the README for detailed Chromium setup instructions
```
## Configuration
Update API keys in the modified files:
```cpp theme={null}
// In sonar_autocomplete_provider.cc and render_view_context_menu.cc
const std::string API_KEY = "your_perplexity_api_key_here";
```
## Usage
1. **Build Chromium** with applied patches following the repository instructions
2. **Launch the custom browser** with AI integration
3. **Use Omnibox AI**: Type `sonar what is quantum tunneling?` in address bar
4. **Use Context Summarization**: Select text, right-click "Summarize with Sonar"
## Code Explanation
* **Omnibox Integration**: Custom autocomplete provider hooking into Chromium's omnibox API
* **Context Menu**: Modified render view context menu for text summarization
* **API Integration**: Direct Perplexity Sonar API calls with debounced input handling
* **Model Selection**: Sonar Pro for omnibox queries, Sonar for text summarization
* **Browser Architecture**: Demonstrates Chromium extension points for AI features
* **Build Process**: Custom Chromium build with AI patches applied
## Demo Video
## Links
* [GitHub Repository](https://github.com/KoushikBaagh/perplexity-hackathon-chromium)
* [Chromium Gerrit Repository](https://chromium-review.googlesource.com/c/chromium/src/+/6778540)
# StarPlex | AI-Powered Startup Intelligence Platform
Source: https://docs.perplexity.ai/cookbook/showcase/starplex
An AI-powered startup intelligence platform that helps entrepreneurs validate their business ideas and find the right resources to succeed
**StarPlex** is an AI-powered startup intelligence platform that helps entrepreneurs validate their business ideas and connect with the resources they need to succeed. Powered primarily by **Perplexity Sonar Pro**, it features an interactive **3D globe interface** as its main UI. Simply enter your startup idea, and watch as the AI engine analyzes and visualizes insights directly on the globe—mapping out competitors, markets, demographics, VCs, and potential co-founders across the world in real-time.
## Features
* **Market Validation Analysis** with AI-proof scoring, market cap estimation, and growth trend analysis
* **Interactive 3D Globe Interface** for visualizing global startup intelligence data
* **Competitor Research** with threat scoring and competitive landscape mapping
* **VC & Investor Matching** based on investment thesis and portfolio alignment
* **Co-founder Discovery** with compatibility scoring and expertise matching
* **Demographic Research** with heatmap visualization of target audience locations
* **AI Pitch Deck Generation** creating investor-ready presentations
* **Context-Aware Chatbot** with RAG integration across all research data
## Prerequisites
* Node.js 18+ and npm
* Python 3.8+ and pip
* Perplexity API key (Sonar Pro)
* Mapbox token and SERP API key
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/JerryWu0430/StarPlex.git
cd StarPlex
# Backend setup
cd backend
pip install -r requirements.txt
# Frontend setup
cd ../frontend
npm install
```
## Configuration
Create `.env` file in the backend directory:
```ini theme={null}
PERPLEXITY_API_KEY=your_perplexity_api_key
MAPBOX_TOKEN=your_mapbox_token
SERPAPI_KEY=your_serpapi_key
```
## Usage
1. **Start Backend**:
```bash theme={null}
cd backend
python main.py
```
2. **Start Frontend**:
```bash theme={null}
cd frontend
npm run dev
```
3. **Access Application**: Open [http://localhost:3000](http://localhost:3000) and enter your startup idea
4. **Explore Intelligence**: Use the 3D globe to visualize competitors, VCs, demographics, and co-founders
5. **Generate Assets**: Create pitch decks and chat with the AI assistant about your analysis
## How StarPlex Uses Perplexity Sonar API
StarPlex leverages Perplexity's Sonar API through a **multi-module intelligence architecture**:
**Market Analysis Engine**
Uses Sonar Pro for comprehensive market validation, combining Google Trends data with AI analysis to generate market cap estimates, AI-disruption scores, and growth projections with structured JSON outputs.
**Competitor Intelligence**
Employs multiple concurrent Sonar queries to identify competing companies, funding status, and threat levels. Each competitor receives a 1-10 threat score with detailed competitive positioning analysis.
**VC & Co-founder Matching**
Leverages Sonar's real-time web knowledge to find relevant investors and potential co-founders, scoring matches based on investment thesis alignment, expertise fit, and geographic proximity.
**Context-Aware Business Assistant**
Implements RAG (Retrieval-Augmented Generation) by feeding all research data into Sonar conversations, creating a knowledgeable startup advisor that can answer questions about market positioning, competitive threats, and strategic decisions.
**Geographic Intelligence**
Combines Sonar's demographic insights with Mapbox geocoding to create interactive heatmaps showing where target audiences are concentrated globally.
## Code Explanation
* **Backend**: Python FastAPI with AsyncIO for concurrent Perplexity API calls across multiple analysis modules
* **Frontend**: Next.js with React 19, featuring Cobe for 3D globe visualization and Mapbox GL for interactive mapping
* **AI Integration**: Multi-model Perplexity strategy using Sonar Pro for complex analysis and Sonar for faster queries
* **Data Pipeline**: Intelligent caching, structured JSON responses, and real-time streaming for immediate user feedback
* **Visualization**: Dynamic data binding between Perplexity insights and interactive globe/map interfaces
## Links
* [GitHub Repository](https://github.com/JerryWu0430/StarPlex)
* [Live Demo](https://starplex.app)
* [Devpost Submission](https://devpost.com/software/starplex)
# TruthTracer | AI-Powered Misinformation Detection Platform
Source: https://docs.perplexity.ai/cookbook/showcase/truth-tracer
A comprehensive misinformation detection platform that uses Perplexity's Sonar API to analyze claims, trace trust chains, and provide Socratic reasoning for fact verification
**TruthTracer** is a comprehensive misinformation detection platform that leverages Perplexity's Sonar API to provide multi-layered claim analysis. The platform combines fact-checking, trust chain tracing, and Socratic reasoning to deliver accurate, evidence-based verification results with confidence scores and detailed sourcing.
### Demo
## Features
* **Multi-method Analysis** combining fact-checking, trust chain analysis, and Socratic reasoning
* **AI-Powered Verification** using Perplexity's Sonar, Sonar Deep Research, and Sonar Reasoning models
* **Real-time Processing** with parallel execution of multiple analysis methods
* **Evidence-based Results** providing sources, confidence scores, and detailed reasoning
* **Clean Architecture** with NestJS backend and React frontend
* **Production-Ready** with Docker deployment, comprehensive testing, and API documentation
* **Configurable Confidence Scoring** with customizable weights and thresholds
## Prerequisites
* Node.js 18+ and npm
* Perplexity API key (Sonar models access)
* Docker (optional for deployment)
* Git for repository cloning
## Installation
```bash theme={null}
# Clone the backend repository
git clone https://github.com/anthony-okoye/truth-tracer-backend.git
cd truth-tracer-backend
# Install dependencies
npm install
# Clone the frontend repository
git clone https://github.com/anthony-okoye/truth-tracer-front.git
cd truth-tracer-front
# Install frontend dependencies
npm install
```
## Configuration
Create `.env` file in the backend directory:
```ini theme={null}
# Required
SONAR_API_KEY=your_perplexity_api_key
SONAR_API_URL=https://api.perplexity.ai
# Optional configuration
SONAR_TIMEOUT=30000
SONAR_MAX_RETRIES=3
CONFIDENCE_WEIGHT_FACT_CHECK=0.35
CONFIDENCE_WEIGHT_TRUST_CHAIN=0.25
CONFIDENCE_WEIGHT_SOCRATIC=0.20
```
## Usage
1. **Start Backend**:
```bash theme={null}
cd truth-tracer-backend
npm run start:dev
```
2. **Start Frontend**:
```bash theme={null}
cd truth-tracer-front
npm start
```
3. **Access Application**: Open [http://localhost:3000](http://localhost:3000) in your browser
4. **Analyze Claims**:
* Enter a claim in the text area
* Click "Analyze Claim" to run fact-checking, trust chain analysis, and Socratic reasoning
* View results with confidence scores, sources, and detailed explanations
## Code Explanation
* **Backend**: NestJS application with clean architecture following TypeScript best practices
* **AI Integration**: Perplexity Sonar API with three specialized models - Sonar for fact-checking, Sonar Deep Research for trust chain analysis, and Sonar Reasoning for logical evaluation
* **Parallel Processing**: Simultaneous execution of all three analysis methods for efficient claim verification
* **Response Sanitization**: Custom JSON parsing and validation to handle various API response formats
* **Confidence Scoring**: Weighted scoring system combining results from all three analysis methods
* **Frontend**: React application with intuitive claim submission interface and detailed results visualization
* **Testing**: Comprehensive test suite including unit tests, end-to-end tests, and claim analysis testing
## How the Sonar API is Used
TruthTracer leverages Perplexity's Sonar API through three distinct analysis approaches:
```typescript theme={null}
// Parallel execution of multiple Sonar models
const [factCheckResult, trustChainResult, socraticResult] = await Promise.all([
sonarClient.chat.completions.create({
model: "sonar",
messages: [{ role: "user", content: factCheckPrompt }],
max_tokens: 500
}),
sonarClient.chat.completions.create({
model: "sonar-deep-research",
messages: [{ role: "user", content: trustChainPrompt }],
max_tokens: 2500
}),
sonarClient.chat.completions.create({
model: "sonar-reasoning",
messages: [{ role: "user", content: socraticPrompt }],
max_tokens: 4000
})
]);
```
## Links
* [Live Demo](https://truthtracer.netlify.app/)
* [Backend Repository](https://github.com/anthony-okoye/truth-tracer-backend)
* [Frontend Repository](https://github.com/anthony-okoye/truth-tracer-front)
# UnCovered | Real-Time Fact-Checking Chrome Extension
Source: https://docs.perplexity.ai/cookbook/showcase/uncovered
A Chrome extension that brings real-time fact-checking to anything you see online in just 2 clicks, powered by Perplexity's Sonar API for instant verification
**UnCovered** is a Chrome extension that verifies text, images, websites, and screenshots in real-time—right where you browse. Built on Perplexity's Sonar API, it provides instant truth with citations, verdicts, and deep analysis using just a right-click, without breaking your browsing flow.
## Features
* **3-Click Verification**: Select → Right-click → Verify (Text, Image, Link, or Screenshot)
* **Text Analysis Modes**: Quick Search, Fact-Check, and Deep Research capabilities
* **Image Fact-Checking**: Reverse image analysis and multimodal claim verification
* **Screenshot & Video Frame Capture**: Analyze visuals like infographics, memes, or chart snapshots
* **Citation-Backed Results**: All answers include sources and fact-verdicts (True/False/Unconfirmed)
* **Instant Rebuttal Generator**: Create concise, fact-based replies to misinformation
* **Zero-Friction UX**: Stay on the same page — no copy-paste, no new tabs required
## Prerequisites
* Chrome browser
* Node.js 16+ and npm
* MongoDB database
* Cloudinary account for image storage
* Perplexity API key (Sonar Pro and Deep Research access)
* Google OAuth credentials
## Installation
```bash theme={null}
# Clone the repository
git clone https://github.com/aayushsingh7/UnCovered.git
cd UnCovered
# Install dependencies
npm install
# Build the Chrome extension
npm run build
```
## Configuration
Set up your environment variables:
```ini theme={null}
PERPLEXITY_API_KEY=your_sonar_api_key
MONGODB_URI=your_mongodb_connection_string
CLOUDINARY_URL=your_cloudinary_credentials
GOOGLE_OAUTH_CLIENT_ID=your_google_oauth_id
```
## Usage
1. **Text/Link Verification**:
* Select text or right-click a link
* Choose Quick Search / Fact-Check / Deep Research
* Get trusted results with verdicts and citations
2. **Image Verification**:
* Right-click any image
* Choose from Quick Search or Fact-Check
* Detect misinformation and visual manipulation
3. **Screenshot/Infographic Analysis**:
* Click UnCovered icon in the toolbar
* Use "Capture Screen" to analyze visual content
4. **Get Instant Rebuttal**:
* Auto-generate fact-based responses to correct misinformation
## Code Explanation
* **Frontend**: Vanilla JavaScript Chrome extension with context menu integration
* **Backend**: Node.js Express server handling API requests and user authentication
* **AI Integration**: Perplexity Sonar Pro and Deep Research APIs for intelligent fact-checking
* **Image Processing**: Cloudinary integration for screenshot and image analysis
* **Database**: MongoDB for user data and verification history
* **Authentication**: Google OAuth for secure user management
* **Multimodal Analysis**: Support for text, images, screenshots, and video frames
## Technical Implementation
UnCovered leverages Perplexity Sonar API in three core modes:
```javascript theme={null}
// Quick Search and Fact-Check with Sonar Pro
const quickResponse = await perplexityClient.chat.completions.create({
model: "sonar-pro",
messages: [{ role: "user", content: factCheckPrompt }]
});
// Deep Research for comprehensive analysis
const deepResponse = await perplexityClient.chat.completions.create({
model: "sonar-deep-research",
messages: [{ role: "user", content: deepAnalysisPrompt }]
});
```
## Demo Video
## Links
* [GitHub Repository](https://github.com/aayushsingh7/UnCovered)
* [Live Demo](https://uncovered.vercel.app)
# Valetudo AI | Trusted Medical Answer Assistant
Source: https://docs.perplexity.ai/cookbook/showcase/valetudo-ai
Sonar-powered medical assistant for fast, science-backed answers.
# Valetudo AI
**Valetudo AI** is a science-backed medical assistant powered by the Perplexity Sonar API. It provides fast, clear, and well-cited answers to health questions — helping users cut through misinformation with filters, image analysis, and ready-made prompt templates.
Designed for conscious users — like parents, patients, and medical students — seeking reliable information.
## Features
* **Cited Answers** — sourced from a curated list of 10 trusted medical domains
* **Smart Filters** — by date and country for localized, up-to-date insights
* **Image Upload** — analyze photos of medication, conditions, or packaging
* **Prompt Templates** — 7 categories for symptom checks, drug safety, research, and more
* **Simple UI** — built with React and Tailwind CSS
## How It Uses the Sonar API
Valetudo AI integrates with [Perplexity Sonar Pro](https://docs.perplexity.ai), leveraging advanced features for domain-specific search and rich responses:
| Feature | API Field | Purpose |
| ---------------- | --------------------------------- | ------------------------------------------------- |
| Context Control | `search_context_size: medium` | Balances speed and depth for focused medical Q\&A |
| Trusted Domains | `search_domain_filter` | Restricts results to vetted health sources |
| Visual Input | `image_url` | Enables image-based medical queries |
| Freshness Filter | `search_after/before_date_filter` | Helps surface recent and relevant findings |
| Local Relevance | `user_location` | Tailors answers based on user’s region |
## Links
* [GitHub Repository](https://github.com/vero-code/valetudo-ai)
* [Devpost Submission](https://devpost.com/software/valetudo-ai)
* [View All Screenshots](https://github.com/vero-code/valetudo-ai/tree/master/screenshots)
## Demo Video
See Valetudo AI in action:
## Screenshots
### Home Interface

### Prompt Templates

### Image Upload

### Date & Location Filters


# Get in Touch
Source: https://docs.perplexity.ai/discussions/discussions
## Join Our Developer Community
**The heart of our developer ecosystem!** Our vibrant community forum is where thousands of developers connect, share ideas, get help, and showcase their amazing projects built with the Perplexity API.
**[🚀 Join the Community Forum →](https://community.perplexity.ai/)**
**Why join the forum?**
* Get technical help from experienced developers and our team
* Share your projects and get featured in our showcase
* Access exclusive tutorials, code examples, and best practices
* Connect with like-minded builders and potential collaborators
* Stay updated on the latest API features and announcements
Join our Discord community for instant help and casual conversations with fellow developers.
* [Discord Community](https://discord.gg/perplexity-ai) - Real-time chat & support
* Active community members ready to help
* Quick answers to urgent questions
Follow us for the latest updates, feature announcements, and developer spotlights.
* [Follow @PPLXDevs](https://twitter.com/PPLXDevs) - Latest updates & announcements
* Developer showcases and success stories
* API tips and best practices
## Contact Our Team
Interested in enterprise solutions, custom pricing, or have sales questions?
**[Contact Sales Team →](https://pplx.ai/api-sales)**
Need technical assistance? Our support team is here to help.
**Please try the [Community Forum](https://community.perplexity.ai/) first!**
You'll get faster responses from our active community and team members who monitor the forum regularly.
* **Email**: [api@perplexity.ai](mailto:api@perplexity.ai) - For billing inquiries and account issues
## Developer Resources
Found a bug? Help us improve! Submit detailed bug reports through our [Community Forum](https://community.perplexity.ai/). Create a new post with the `Bug Reports` tag.
Built something amazing with the Perplexity API? We'd love to showcase your work!
* Contribute to our [API Cookbook](https://github.com/perplexityai/api-cookbook)
* Share on X/Twitter with [@PPLXDevs](https://twitter.com/PPLXDevs)
* Present at our monthly developer showcase
Exceptional projects may be featured in our newsletter, blog, social media channels, and our [Cookbook Community Showcase](/cookbook/showcase/briefo). Let us amplify your work to thousands of developers and AI enthusiasts!
# Frequently Asked Questions
Source: https://docs.perplexity.ai/faq/faq
The `sonar-reasoning-pro` model is designed to output a `` section containing reasoning tokens, immediately followed by a valid JSON object. As a result, the `response_format` parameter does not remove these reasoning tokens from the output.
We recommend using a custom parser to extract the valid JSON portion. An example implementation can be found [here](https://github.com/ppl-ai/api-discussion/blob/main/utils/extract_json_reasoning_models.py).
Yes, for the API, content filtering in the form of SafeSearch is turned on by default. This helps filter out potentially offensive and inappropriate content, including pornography, from search results. SafeSearch is an automated filter that works across search results to provide a safer experience. You can learn more about SafeSearch on the [official Wikipedia page](https://en.wikipedia.org/wiki/SafeSearch).
To file a bug report, please use our GitHub repository and file the bug in [issues](https://github.com/ppl-ai/api-discussion/issues). Once you've submitted your report, we kindly ask that you share the link to the issue with us via email at [api@perplexity.ai](mailto:api@perplexity.ai) so we can track it on our end.
We truly appreciate your patience, and we'll get back to you as soon as possible. Due to the current volume of reports, it may take a little time for us to respond—but rest assured, we're on it.
Our compute is hosted via Amazon Web Services in North America. By default, the API has zero day retention of user prompt data, which is never used for AI training.
The only way for an account to be upgraded to the next usage tier is through all-time credit purchase.
Here are the spending criteria associated with each tier:
| Tier | Credit Purchase (all time) |
| ------ | -------------------------- |
| Tier 0 | - |
| Tier 1 | \$50 |
| Tier 2 | \$250 |
| Tier 3 | \$500 |
| Tier 4 | \$1000 |
| Tier 5 | \$5000 |
We offer a way to track your billing per API key. You can do this by navigating to the following location:
**Settings > View Dashboard > Invoice history > Invoices**
Then click on any invoice and each item from the total bill will have a code at the end of it (e.g., pro (743S)). Those 4 characters are the last 4 of your API key.
A Feature Request is a suggestion to improve or add new functionality to the Perplexity Sonar API, such as:
* Requesting support for a new model or capability (e.g., image processing, fine-tuning options)
* Asking for new API parameters (e.g., additional filters, search options)
* Suggesting performance improvements (e.g., faster response times, better citation handling)
* Enhancing existing API features (e.g., improving streaming reliability, adding new output formats)
If your request aligns with these, please submit a feature request here: [Github Feature requests](https://github.com/ppl-ai/api-discussion/issues)
1. The API uses the same search system as the UI with differences in configuration—so their outputs may differ.
2. The underlying AI model might differ between the API and the UI for a given query.
3. We give users the power to tune the API to their respective use cases using sampling parameters like `presence_penalty`, `top_p`, etc. Custom tuning to specific use cases might lead to less generalization compared to the UI. We set optimized defaults and recommend not to explicitly provide sampling parameters in your API requests.
We collect the following types of information:
**API Usage Data:** We collect billable usage metadata such as the number of requests and tokens. You can view your own usage in the [Perplexity API dashboard](https://perplexity.ai/settings/api).
**User Account Information:** When you create an account with us, we collect your name, email address, and other relevant contact information.
We do not retain any query data sent through the API and do not train on any of your data.
Yes, the [Sonar Models](https://docs.perplexity.ai/guides/model-cards) leverage information from Perplexity's search index and the public internet.
You can find our [rate limits here](https://docs.perplexity.ai/guides/usage-tiers).
We email users about new developments and also post in the [changelog](changelog/changelog).
401 error codes indicate that the provided API key is invalid, deleted, or belongs to an account which ran out of credits. You likely need to purchase more credits in the [Perplexity API dashboard](https://perplexity.ai/settings/api). You can avoid this issue by configuring auto-top-up.
Currently, we do not support fine-tuning.
Please reach out to [api@perplexity.ai](mailto:api@perplexity.ai) or [support@perplexity.ai](mailto:support@perplexity.ai) for other API inquiries. You can also post on our [discussion forum](https://github.com/ppl-ai/api-discussion/discussions) and we will get back to you.
We do not guarantee this at the moment.
We expose the CoTs for Sonar Reasoning Pro and Sonar Reasoning. We don't currently expose the CoTs for Deep Research.
Reasoning tokens in Deep Research are a bit different than the CoTs in the answer—these tokens are used to reason through the research material before generating the final output via the CoTs.
Yes, the API offers exactly the same internet data access as Perplexity's web platform.
The Perplexity API is designed to be broadly compatible with OpenAI's chat completions endpoint. It adopts a similar structure—including fields such as `id`, `model`, and `usage`—and supports analogous parameters like `model`, `messages`, and `stream`.
**Key Differences from the standard OpenAI response include:**
* **Response Object Structure:**
* OpenAI responses typically have an `object` value of `"chat.completion"` and a `created` timestamp, whereas our response uses `object: "response"` and a `created_at` field.
* Instead of a `choices` array, our response content is provided under an `output` array that contains detailed message objects.
* **Message Details:**
* Each message in our output includes a `type` (usually `"message"`), a unique `id`, and a `status`.
* The actual text is nested within a `content` array that contains objects with `type`, `text`, and an `annotations` array for additional context.
* **Additional Fields:**
* Our API response provides extra meta-information (such as `status`, `error`, `incomplete_details`, `instructions`, and `max_output_tokens`) that are not present in standard OpenAI responses.
* The `usage` field also differs, offering detailed breakdowns of input and output tokens (including fields like `input_tokens_details` and `output_tokens_details`).
These differences are intended to provide enhanced functionality and additional context while maintaining broad compatibility with OpenAI's API design.
# API Roadmap
Source: https://docs.perplexity.ai/feature-roadmap
Upcoming features and improvements for the Perplexity API designed to enhance your development experience.
Our roadmap is shaped by our users - have a feature in mind? Submit your suggestion [here](https://community.perplexity.ai/) and help us build the future of AI together.
We're expanding our multimodal capabilities to include video uploads.
This feature will enable:
* **Video Content Analysis**: Upload and analyze video files directly through the API
* **Frame-by-Frame Processing**: Extract insights from video content at multiple time points
* **Visual Scene Understanding**: Analyze visual elements, objects, and activities in video content
* **Multimodal Search**: Search for information based on both visual and audio elements from your uploaded videos
Supported formats will include common video file types (MP4, MOV, AVI) with reasonable file size limits for API efficiency.
This capability will unlock new use cases in content moderation, educational analysis, media research, and automated video summarization.
Expanding your ability to access and process information:
* **File Repository Integration**: Query file repositories tied to your API organization
* **Multi-format File Search**: Search across various file types (PDFs, documents, spreadsheets)
* **External Data Source Integration**: Connect to external data stores and databases
* **Enterprise Connector Parity**: Full feature parity with enterprise connector capabilities
This feature will allow your applications to tap into a broader range of data sources for more comprehensive insights, enabling you to build applications that can search and analyze your organization's entire knowledge base.
We're expanding our structured outputs capabilities:
* **Universal JSON Support**: JSON structured outputs are now available for all models across all tiers
* **Complete Regex Support**: Extending regex pattern support to all models (currently available for `sonar` and `sonar-reasoning-pro`)
* **Advanced Schema Validation**: Enhanced validation options for more reliable structured data
* **Output Templates**: Pre-defined templates for common use cases
This expansion will make it easier to build applications that require consistent, structured data from our API responses.
We're committed to making our documentation a truly exceptional resource:
* **Improved Layout**: Optimized structure for better self-serve workflows
* **Consistent Design**: Unified branding between our landing page and documentation
* **Enhanced Content**: Revised explanations for better developer understanding
* **Vertical-Specific Guides**: Specialized documentation for publishers, merchants, and other industry partners
* **High-Fidelity Demos**: More comprehensive examples beyond our basic cookbook demos
* **Comprehensive Prompt Guide**: In-depth resources to help you build effectively with our search + LLM API
* **API Selection Guides**: Clear guidance on which API is best suited for specific scenarios
These improvements will help you get up to speed faster and make the most of our API capabilities.
We're scaling our infrastructure to support significantly higher request volumes:
* **Enterprise-Scale Rate Limits**: Supporting use cases up to 100K requests per minute
* **High-Growth Startup Support**: Designed specifically for rapidly scaling applications
* **Infrastructure Reliability**: Enhanced stability and reduced latency spikes under high load
* **Regional Scaling**: Expanded infrastructure deployment for global applications
This enhancement will ensure our API can grow alongside your application's user base and processing needs, supporting everything from high-growth startups to enterprise-scale deployments.
Improving our error framework:
* More descriptive error messages
* Clearer guidance on resolving common issues
This will reduce debugging time and help you understand and address issues more efficiently.
Broadening the types of content you can work with:
* **URL Content Integration**: Specify URLs within prompts to search for and analyze content from specific web pages directly
* **Advanced URL Parsing**: Extract and analyze content from web pages with enhanced accuracy and context understanding
* **Web Page Analysis**: Deep content extraction including text, images, and structured data from URLs
* **Real-time Web Content**: Access to live web content for dynamic analysis and research
These features will enable new use cases and richer interactions within your applications, allowing you to reference specific web content and build more comprehensive research workflows with real-time web data integration.
We're addressing the limitations of managing context in API calls by introducing new context management features.
Key improvements include:
* **Efficient Context Storage**: Avoid appending responses from previous API calls to new ones, reducing the risk of exceeding context windows.
* **Session-Based Memory**: Enable session-based memory to maintain context across multiple API calls without manual intervention.
These enhancements will make it easier to build applications that require persistent context without hitting technical limitations.
We're preparing to make Pro Search available to all API users:
* **Multi-step Reasoning**: Access to the advanced agentic search capabilities currently in beta
* **Dynamic Tool Execution**: Automated web searches, URL content fetching, and Python code execution
* **Intelligent Classification**: Automatic determination of when to use pro search vs fast search based on query complexity
* **Transparent Reasoning**: Real-time streaming of the model's thought process and tool usage
This will unlock sophisticated research workflows and enable your applications to handle complex, multi-dimensional queries that require computational analysis and deep web research.
Introducing voice-based interactions through our API:
* **Real-time Voice Processing**: Direct voice input and audio response generation
* **Natural Conversation Flow**: Maintain context across voice interactions
* **Multi-language Support**: Voice capabilities across multiple languages
* **Low-latency Streaming**: Optimized for real-time voice applications
This capability will enable voice assistants, interactive applications, and hands-free interfaces that can search and reason about information through natural speech.
Expanding our capabilities with specialized financial tools:
* **Market Data Access**: Real-time and historical stock prices, market indicators
* **Ticker Symbol Lookup**: Intelligent company and symbol resolution
* **Financial Analysis Tools**: Price history, trend analysis, and market insights
* **SEC Filing Integration**: Enhanced search and analysis of financial documents
These tools will enable sophisticated financial applications, trading platforms, and investment research tools with access to comprehensive financial data and analysis capabilities.
Bringing cutting-edge experimental features to the API:
* **Early Access Features**: Test new capabilities before general release
* **Advanced Model Variants**: Access to experimental model configurations
* **Prototype Integrations**: Early versions of upcoming integrations and tools
* **Developer Feedback Integration**: Direct influence on feature development through testing
This will give developers early access to innovative features and the opportunity to shape the future direction of our API capabilities.
Expanding our integration ecosystem:
* **Agentic Framework Support**: Enhanced integrations with LangChain, LlamaIndex, and other AI frameworks
* **Developer Platform Integration**: Native support for popular development environments
* **Workflow Automation**: Integration with automation platforms and CI/CD pipelines
* **Real-time Collaboration**: Enhanced tooling for team-based development
These integrations will make it easier to incorporate our API into your existing development workflows and build more sophisticated AI applications.
Advanced analytics and monitoring for your API usage:
* **Query Analysis**: Detailed insights into query patterns, types, and performance
* **Usage Metrics**: Comprehensive tracking of API calls, response times, and success rates
* **Error Monitoring**: Detailed error tracking and debugging information
* **Performance Optimization**: Insights to help optimize your application's API usage
* **Cost Management**: Detailed billing breakdowns and usage forecasting
This dashboard will provide the visibility you need to optimize your applications, manage costs, and understand user behavior patterns.
## Timeline and Availability
This roadmap represents our current development priorities. Features will be released incrementally, with some becoming available in the coming months and others planned for later in the year.
We'll announce new feature availability through our [changelog](/changelog) and via email notifications to API users.
# API Groups & Billing
Source: https://docs.perplexity.ai/getting-started/api-groups
Learn how to use the Perplexity API Portal to manage access, usage, billing, and team collaboration.
## What is an API Group?
An **API Group** is your organization's workspace in the Perplexity API Portal. It allows you to:
* **Manage billing** and payment methods for API usage
* **Create and control API keys** for accessing the Perplexity API
* **Invite team members** and control their permissions (optional)
* **Monitor usage and costs** across all your API keys
## Prerequisites
Before getting started, make sure you have:
* A Perplexity account (sign up at [perplexity.ai](https://perplexity.ai))
* **Admin permissions** for billing and API key management
* A **credit card** ready for payment setup (you won't be charged initially)
If you're joining an existing team, you'll need an invitation from an Admin. Contact your team lead to get access.
## Accessing the API Portal
Once signed in, navigate to the left-hand sidebar and expand the **API** section to access your API group and related settings.
***
## Creating and Managing an API Group
To set up your organization:
Click **API Group** in the left sidebar.
Fill out your organization's name, address, and tax details.
Your organization name and address will appear on invoices and help us support you better.
**Fields include:**
* Organization name and description
* Address (Line 1, Line 2, City, State, Zip, Country)
* Tax ID
***
## Billing and Payment Methods
### How Billing Works
The Perplexity API uses a **credit-based billing system**:
* **Credits** are purchased in advance and used for API calls
* **Different models** consume different amounts of credits per request
* **Usage is charged** based on tokens processed and search queries made
* **Automatic top-up** can be enabled to avoid service interruptions
See our [Pricing page](./pricing) for detailed cost information per model and usage type.
### Setting Up Payment
Navigate directly to your API billing dashboard to manage payment methods, view usage, and configure billing settings.
Go to the **API Billing** tab in your API Portal.
Click **Add Payment Method** and enter your credit card information.
This step will not charge your credit card. It just stores payment information for future API usage.
Enable automatic credit top-up to avoid service interruptions.
If you run out of credits, your API keys will be blocked until you add to your credit balance. Auto top-up prevents this by automatically adding credits when your balance drops below a threshold.
***
## Managing API Keys
### What are API Keys?
API keys are your credentials for accessing the Perplexity API. Each key:
* **Authenticates your requests** to the Perplexity API
* **Tracks usage and billing** for cost attribution
* **Can be revoked or regenerated** for security purposes
* **Should be kept secure** and never shared publicly
You'll need to include your API key in the Authorization header of every API request: `Authorization: Bearer YOUR_API_KEY`
### Creating an API Key
Go to the **API Keys** tab in your API Portal.
Click **+ Create Key** to generate a new API key.
Copy and securely store your API key immediately.
API keys are sensitive credentials. Never expose them in client-side code or share them in public repositories.
***
## Adding and Managing Members
Admins can invite team members to the organization with specific roles: **Admin** or **Member**.
### Adding a Member
Click **+ Add Member**.
Enter the user's email address and click **Invite**.
The invited user will receive an email with a link to join your group.
Once they accept, they'll appear in your member list with their assigned role.
### Filtering Members by Role
Use the dropdown to filter your list of team members by role.
### Roles
* **Admin**: Full access to invite/remove members, manage billing, and view usage data.
* **Member**: Can view usage and account limits but cannot modify settings.
Only Admins can make changes to billing and member permissions.
***
## Viewing Usage Metrics
All members can view API usage by selecting **Usage Metrics** from the sidebar.
Features include:
* Total API call trends over time
* Breakdown by API model and key
* Optional date range filters
Usage metrics help you monitor API activity and optimize for cost or performance.
### Tracking Spend Per API Key
You can track billing for each of your API keys by following these steps:
Navigate to the [API section](https://www.perplexity.ai/account/api) of your **Settings** and click on **Usage Metrics**
Select **Invoice history** > **Invoices**
Click on any invoice to view details
Each item from the total bill will have a code at the end (e.g., pro (743S))
* The 4 characters in parentheses are the last 4 characters of your API key
# null
Source: https://docs.perplexity.ai/getting-started/models
# Pricing
Source: https://docs.perplexity.ai/getting-started/pricing
This page shows **pricing information** to help you understand API costs. For **billing setup**, payment methods, and usage monitoring, visit the [Admin section](/getting-started/api-groups).
## Search API Pricing
| API | Price per 1K requests | Description |
| -------------- | :-------------------: | ---------------------------------------------- |
| **Search API** | \$5.00 | Raw web search results with advanced filtering |
**No token costs:** Search API charges per request only, with no additional token-based pricing.
## Grounded LLM Pricing
**Total cost per query** = Token costs + Request fee (varies by search context size, applies to Sonar, Sonar Pro, Sonar Reasoning, and Sonar Reasoning Pro models only)
## Token Pricing
**Token pricing** is based on the number of tokens in your request and response.
| Model | Input Tokens (\$/1M) | Output Tokens (\$/1M) | Citation Tokens (\$/1M) | Search Queries (\$/1K) | Reasoning Tokens (\$/1M) |
| ----------------------- | :------------------: | :-------------------: | :---------------------: | :--------------------: | :----------------------: |
| **Sonar** | \$1 | \$1 | - | - | - |
| **Sonar Pro** | \$3 | \$15 | - | - | - |
| **Sonar Reasoning** | \$1 | \$5 | - | - | - |
| **Sonar Reasoning Pro** | \$2 | \$8 | - | - | - |
| **Sonar Deep Research** | \$2 | \$8 | \$2 | \$5 | \$3 |
## Request Pricing by Search Context Size
**Search context** determines how much web information is retrieved. Higher context = more comprehensive results. The following table shows the request fee for each model for every **1000 requests**.
| Model | Low Context Size | Medium Context Size | High Context Size |
| ----------------------- | :--------------: | :-----------------: | :---------------: |
| **Sonar** | \$5 | \$8 | \$12 |
| **Sonar Pro** | \$6 | \$10 | \$14 |
| **Sonar Reasoning** | \$5 | \$8 | \$12 |
| **Sonar Reasoning Pro** | \$6 | \$10 | \$14 |
* **Low**: (default) fastest, cheapest
* **Medium**: Balanced cost/quality
* **High**: Maximum search depth, best for research
[Learn more about search context →](../guides/search-context-size-guide)
## Pro Search Pricing (Pro Search for Sonar Pro)
**Pro Search** enhances Sonar Pro with automated tool usage and multi-step reasoning. When enabled, the model can perform multiple web searches and fetch URL content to answer complex queries. [Learn more about Pro Search here](/guides/pro-search-quickstart).
Pro Search requires `stream: true` and is enabled via the `search_type` parameter in `web_search_options`.
### Search Type Options
| Search Type | Description | Request Fee (per 1K) |
| ----------- | -------------------------------------------------- | :----------------------: |
| **`fast`** | (default) Standard Sonar Pro behavior | \$6 / \$10 / \$14 |
| **`pro`** | Multi-step tool usage for complex queries | \$14 / \$18 / \$22 |
| **`auto`** | Automatic classification based on query complexity | Varies by classification |
Request fees vary by search context size (Low / Medium / High). Token pricing remains the same as standard Sonar Pro (\$3 per 1M input, \$15 pe r 1M output).
### Input Tokens
The number of tokens in your prompt or message to the API. This includes:
* Your question or instruction
* Any context or examples you provide
* System messages and formatting
**Example:** "What is the weather in New York?" = \~8 input tokens
### Output Tokens
The number of tokens in the API's response. This includes:
* The generated answer or content
* Any explanations or additional context
* Search results and references
**Example:** "The weather in New York is currently sunny with a temperature of 72°F." = \~15 output tokens
### Citation Tokens
Tokens used specifically for generating search results and references in responses. Only applies to **Sonar Deep Research** model.
**Example:** Including source links, reference numbers, and bibliographic information
### Search Context Size vs Context Window
**Search context size** is *not* the same as the **context window**.
* **Search context size**: How much web information is retrieved during search (affects request pricing)
* **Context window**: Maximum tokens the model can process in one request (affects token limits)
### Search Queries
The number of individual searches conducted by **Sonar Deep Research** during query processing. This is separate from your initial user query.
* The model automatically determines how many searches are needed
* You cannot control the exact number of search queries
* The `reasoning_effort` parameter influences the number of searches performed
* Only applies to **Sonar Deep Research** model
### Reasoning Tokens
Tokens used for step-by-step logical reasoning and problem-solving. Only applies to **Sonar Deep Research** model.
**Example:** Breaking down a complex math problem into sequential steps with explanations
**Token Calculation:** 1 token ≈ 4 characters in English text. The exact count may vary based on language and content complexity.
## Cost Examples
**Sonar** • 500 input + 200 output tokens
| Component | Cost |
| ------------- | ------------ |
| Input tokens | \$0.0005 |
| Output tokens | \$0.0002 |
| Request fee | \$0.005 |
| **Total** | **\$0.0057** |
| Component | Cost |
| ------------- | ------------ |
| Input tokens | \$0.0005 |
| Output tokens | \$0.0002 |
| Request fee | \$0.008 |
| **Total** | **\$0.0087** |
| Component | Cost |
| ------------- | ------------ |
| Input tokens | \$0.0005 |
| Output tokens | \$0.0002 |
| Request fee | \$0.012 |
| **Total** | **\$0.0127** |
**Sonar Deep Research**
| Component | Cost |
| ------------------------ | -------------- |
| Input tokens (33) | \$0.000066 |
| Output tokens (7163) | \$0.057304 |
| Citation tokens (20016) | \$0.040032 |
| Reasoning tokens (73997) | \$0.221991 |
| Search queries (18) | \$0.09 |
| **Total** | **\$0.409393** |
| Component | Cost |
| ------------------------- | ----------- |
| Input tokens (7) | \$0.00 |
| Output tokens (3847) | \$0.031 |
| Citation tokens (47293) | \$0.095 |
| Reasoning tokens (308156) | \$0.924 |
| Search queries (28) | \$0.14 |
| **Total** | **\$1.190** |
| Component | Cost |
| ------------------------- | ----------- |
| Input tokens (8) | \$0.00 |
| Output tokens (4435) | \$0.035 |
| Citation tokens (58196) | \$0.116 |
| Reasoning tokens (339594) | \$1.019 |
| Search queries (30) | \$0.15 |
| **Total** | **\$1.320** |
## Choosing the Right API
### Search API
| API | Description | Best For |
| -------------- | ---------------------------------------------- | --------------------------------------------------------------------------------- |
| **Search API** | Raw web search results with advanced filtering | Custom search engines, research tools, competitive intelligence, news aggregation |
### Sonar Models (Chat Completions)
| Model | Description | Best For |
| ----------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------- |
| **Sonar** | Lightweight, cost-effective search model | Quick facts, news updates, simple Q\&A, high-volume applications |
| **Sonar Pro** | Advanced search with deeper content understanding | Complex queries, competitive analysis, detailed research |
| **Sonar Reasoning** | Quick problem-solving with step-by-step logic and search | Logic puzzles, math problems, transparent reasoning |
| **Sonar Reasoning Pro** | Enhanced multi-step reasoning with web search | Complex problem-solving, research analysis, strategic planning |
| **Sonar Deep Research** | Exhaustive research and detailed report generation with search | Academic research, market analysis, comprehensive reports |
**Need help choosing?** Use Search API when you want raw data to process yourself. Use Sonar models when you want AI-generated answers with search grounding.
# Quickstart
Source: https://docs.perplexity.ai/getting-started/quickstart
Generate an API key and make your first call in < 3 minutes.
## Generating an API Key
Navigate to the **API Keys** tab in the API Portal and generate a new key.
See the [API Groups](/getting-started/api-groups) page to set up an API group.
**OpenAI SDK Compatible:** Perplexity's API supports the OpenAI Chat Completions format. You can use OpenAI client libraries by pointing to our endpoint. See our [OpenAI SDK Guide](/guides/chat-completions-guide) for examples.
## Making Your First API Call
**Install the SDK first:** `pip install perplexityai`
```python Non-streaming Request theme={null}
from perplexity import Perplexity
# Initialize the client (uses PERPLEXITY_API_KEY environment variable)
client = Perplexity()
# Make the API call
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "user", "content": "What were the results of the 2025 French Open Finals?"}
]
)
# Print the AI's response
print(completion.choices[0].message.content)
```
```python Streaming Response theme={null}
from perplexity import Perplexity
# Initialize the client (uses PERPLEXITY_API_KEY environment variable)
client = Perplexity()
# Make the streaming API call
stream = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "user", "content": "What are the most popular open-source alternatives to OpenAI's GPT models?"}
],
stream=True
)
# Process the streaming response
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
```
```python With API Key (Alternative) theme={null}
import os
from perplexity import Perplexity
# Initialize client with explicit API key
client = Perplexity(api_key=os.environ.get("PERPLEXITY_API_KEY"))
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "user", "content": "What were the results of the 2025 French Open Finals?"}
]
)
print(completion.choices[0].message.content)
```
Set your API key as an environment variable: `export PERPLEXITY_API_KEY="your_api_key_here"` (macOS/Linux) or `setx PERPLEXITY_API_KEY "your_api_key_here"` (Windows).
**Install the SDK first:** `npm install @perplexity-ai/perplexity_ai`
```typescript Non-streaming Request theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Initialize the client (uses PERPLEXITY_API_KEY environment variable)
const client = new Perplexity();
// Make the API call
const completion = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{ role: "user", content: "What were the results of the 2025 French Open Finals?" }
]
});
// Print the AI's response
console.log(completion.choices[0].message.content);
```
```typescript Streaming Response theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Initialize the client (uses PERPLEXITY_API_KEY environment variable)
const client = new Perplexity();
// Make the streaming API call
const stream = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{ role: "user", content: "What are the most popular open-source alternatives to OpenAI's GPT models?" }
],
stream: true
});
// Process the streaming response
for await (const chunk of stream) {
if (chunk.choices[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
```
```typescript With API Key (Alternative) theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Initialize client with explicit API key
const client = new Perplexity({
apiKey: process.env.PERPLEXITY_API_KEY
});
const completion = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{ role: "user", content: "What were the results of the 2025 French Open Finals?" }
]
});
console.log(completion.choices[0].message.content);
```
Set your API key as an environment variable: `export PERPLEXITY_API_KEY="your_api_key_here"` (macOS/Linux) or `setx PERPLEXITY_API_KEY "your_api_key_here"` (Windows).
**cURL** is a command-line tool for making HTTP requests. Set your API key and run the command:
```bash Non-streaming Request theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--data '{
"model": "sonar-pro",
"messages": [
{
"role": "user",
"content": "What were the results of the 2025 French Open Finals?"
}
]
}' | jq
```
```bash Streaming Response theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SONAR_API_KEY" \
-d '{
"model": "sonar-pro",
"messages": [
{
"role": "user",
"content": "What were the results of the 2025 French Open Finals?"
}
],
"stream": true
}'| jq
```
## Response Content
```
## 2025 French Open Finals Results
**Men's Singles Final**
- **Champion:** Carlos Alcaraz
- **Runner-up:** Jannik Sinner
- **Score:** 4–6, 6–7^(4–7), 6–4, 7–6^(7–3), 7–6^(10–2)
- **Details:** Carlos Alcaraz successfully defended his title by defeating Jannik Sinner in a dramatic five-set final. The match lasted 5 hours and 29 minutes, making it the longest French Open final in history and the second-longest major final ever. Alcaraz came back from two sets down and saved three championship points, marking a historic comeback. This victory gave Alcaraz his second French Open and fifth Grand Slam title, making him the second-youngest man to win five majors in the Open Era. It was also the first time a French Open singles final was decided by a final-set tiebreak.[1][2]
**Women's Singles Final**
- **Champion:** Coco Gauff
- **Runner-up:** Aryna Sabalenka
- **Score:** (Set scores not fully provided, but Gauff won in three sets)
- **Details:** Coco Gauff rallied from an early deficit to defeat Aryna Sabalenka in a three-set battle. After losing the first set, Gauff fought back to claim her second Grand Slam title, with both coming against Sabalenka (the first being the 2023 US Open). Gauff’s victory marks her first French Open crown at age 21.[5]
**Women's Doubles Final**
- **Champions:** Anna Danilina / Aleksandra Krunić
- **Runners-up:** Sara Errani / (partner not fully specified)
- **Score:** 4–6, 6–1, 6–1
- **Details:** Danilina and Krunić won the women's doubles final in three sets, taking control after dropping the first set.[3]
**Summary Table**
| Event | Winner | Runner-up | Score |
|------------------------|---------------------------------------|----------------------------------|-----------------------------------------------|
| Men's Singles | Carlos Alcaraz | Jannik Sinner | 4–6, 6–7(4–7), 6–4, 7–6(7–3), 7–6(10–2) |
| Women's Singles | Coco Gauff | Aryna Sabalenka | Gauff won in 3 sets (full scores not given) |
| Women's Doubles | Anna Danilina / Aleksandra Krunić | Sara Errani / (unspecified) | 4–6, 6–1, 6–1 |
Alcaraz's men's final win was both historic for its comeback and duration, and Gauff’s victory marked a defining moment in her early career.[1][2][5]
```
## Search Results
```json theme={null}
[
"https://en.wikipedia.org/wiki/2025_French_Open_%E2%80%93_Men's_singles",
"https://en.wikipedia.org/wiki/2025_French_Open_%E2%80%93_Men's_singles_final",
"https://www.rolandgarros.com/en-us/matches?status=finished",
"https://www.tennis.com/news/articles/who-were-the-winners-and-losers-at-2025-roland-garros",
"https://www.cbssports.com/tennis/news/2025-french-open-results-schedule-as-jannik-sinner-faces-carlos-alcaraz-coco-gauff-earns-first-title/"
]
```
## Sample Search Results (first 2 sources)
```json theme={null}
[
{
"title": "2025 French Open – Men's singles final",
"url": "https://en.wikipedia.org/wiki/2025_French_Open_%E2%80%93_Men's_singles_final",
"date": "2025-06-08",
"last_updated": "2025-08-09",
"snippet": "After 5 hours and 29 minutes of play, Alcaraz defeated Sinner 4–6, 6–7 (4–7) , 6–4, 7–6 (7–3) , 7–6 (10–2) , in the longest French Open final in history."
},
{
"title": "2025 Roland Garros Men's Singles Tennis Live Scores - ESPN",
"url": "https://www.espn.com/tennis/scoreboard/tournament/_/eventId/172-2025/competitionType/1",
"date": "2025-06-08",
"last_updated": "2025-08-29",
"snippet": "2025 Roland Garros Scores May 18 - June 8, 2025 Court Philippe-Chatrier, Paris, France Men's Singles 2025 Carlos Alcaraz Defending Champion Carlos Alcaraz."
}
]
```
## Usage Information
```json theme={null}
{
"prompt_tokens": 12,
"completion_tokens": 315,
"total_tokens": 327,
"search_context_size": "low",
"cost": {
"input_tokens_cost": 0.0,
"output_tokens_cost": 0.005,
"request_cost": 0.006,
"total_cost": 0.011
}
}
```
## Raw Response
```json expandable theme={null}
{
"id": "66f3900f-e32e-4d59-b677-1a55de188262",
"model": "sonar-pro",
"created": 1756485272,
"usage": {
"prompt_tokens": 12,
"completion_tokens": 315,
"total_tokens": 327,
"search_context_size": "low",
"cost": {
"input_tokens_cost": 0.0,
"output_tokens_cost": 0.005,
"request_cost": 0.006,
"total_cost": 0.011
}
},
"citations": [
"https://en.wikipedia.org/wiki/2025_French_Open_%E2%80%93_Men's_singles_final",
"https://www.espn.com/tennis/scoreboard/tournament/_/eventId/172-2025/competitionType/1",
"https://www.cbssports.com/tennis/news/2025-french-open-results-schedule-as-jannik-sinner-faces-carlos-alcaraz-coco-gauff-earns-first-title/",
"https://www.youtube.com/watch?v=jrkwqoI-gEg",
"https://en.wikipedia.org/wiki/2025_French_Open_%E2%80%93_Men's_singles"
],
"search_results": [
{
"title": "2025 French Open – Men's singles final",
"url": "https://en.wikipedia.org/wiki/2025_French_Open_%E2%80%93_Men's_singles_final",
"date": "2025-06-08",
"last_updated": "2025-08-09",
"snippet": "After 5 hours and 29 minutes of play, Alcaraz defeated Sinner 4–6, 6–7 (4–7) , 6–4, 7–6 (7–3) , 7–6 (10–2) , in the longest French Open final in history."
},
{
"title": "2025 Roland Garros Men's Singles Tennis Live Scores - ESPN",
"url": "https://www.espn.com/tennis/scoreboard/tournament/_/eventId/172-2025/competitionType/1",
"date": "2025-06-08",
"last_updated": "2025-08-29",
"snippet": "2025 Roland Garros Scores May 18 - June 8, 2025 Court Philippe-Chatrier, Paris, France Men's Singles 2025 Carlos Alcaraz Defending Champion Carlos Alcaraz."
},
{
"title": "2025 French Open: Results, schedule as Jannik Sinner ...",
"url": "https://www.cbssports.com/tennis/news/2025-french-open-results-schedule-as-jannik-sinner-faces-carlos-alcaraz-coco-gauff-earns-first-title/",
"date": "2025-06-07",
"last_updated": "2025-08-29",
"snippet": "The women's final is on June 7, and the men's final is one day later on June 8. Men's final. (1) Jannik Sinner vs. (2) Carlos Alcaraz -- Sunday, ..."
},
{
"title": "Alcaraz, Gauff Win French Open 2025 | Swiatek, Ruud Fall - YouTube",
"url": "https://www.youtube.com/watch?v=jrkwqoI-gEg",
"date": "2025-06-09",
"last_updated": "2025-08-04",
"snippet": "We had some big changes in the rankings also. What was your favorite moment? 0:00 | Intro 0:14 | Weekly Results 0:36 | Rise & Fall 1:24 ..."
},
{
"title": "2025 French Open – Men's singles",
"url": "https://en.wikipedia.org/wiki/2025_French_Open_%E2%80%93_Men's_singles",
"date": "2025-04-27",
"last_updated": "2025-08-29",
"snippet": "Defending champion Carlos Alcaraz defeated Jannik Sinner in the final, 4–6, 6–7, 6–4, 7–6, 7–6 to win the men's singles tennis title at the 2025 French Open. ..."
}
],
"object": "chat.completion",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "**Carlos Alcaraz won the 2025 French Open men's singles final, defeating Jannik Sinner 4–6, 6–7(4–7), 6–4, 7–6(7–3), 7–6(10–2), while Coco Gauff won the women's singles title by rallying past Aryna Sabalenka in three sets**[1][3][5][4].\n\nKey details from the finals:\n\n- **Men's Singles:** \n - Alcaraz came back from two sets down to win in the longest French Open final ever (5 hours, 29 minutes)[1][5].\n - He saved three championship points, a record in the Open Era for men's majors[1][5].\n - This marked his second Roland Garros title and fifth Grand Slam overall[5].\n - The match was the first French Open singles final decided by a match tiebreak (final set tiebreak introduced in 2022)[1][5].\n\n- **Women's Singles:** \n - Coco Gauff defeated Aryna Sabalenka after losing the first set, showcasing a strong comeback[3].\n - Gauff secured her second Grand Slam (her first was at the 2023 US Open)[3].\n - The final was played June 7, 2025; Gauff overcame an early deficit to win in three sets[3].\n\nThese finals were historic for their drama, length, and the milestone achievements for both Alcaraz and Gauff."
},
"delta": {
"role": "assistant",
"content": ""
}
}
]
}
```
For a full guide on streaming, including parsing, error handling, citation management, and best practices, see our [streaming guide](/guides/streaming-responses).
## Next Steps
Now that you've made your first API call, here are some recommended next steps:
Learn how to use the official Perplexity SDK with type safety, async support, and advanced features.
Explore the different models available and their capabilities.
View the complete API documentation with detailed endpoint specifications.
Explore code examples, tutorials, and integration patterns.
Need help? Check out our [community](https://community.perplexity.ai) for support and discussions with other developers.
# Academic Filter Guide
Source: https://docs.perplexity.ai/guides/academic-filter-guide
The `search_mode: "academic"` parameter allows you to tailor your searches specifically to academic and scholarly sources, prioritizing peer-reviewed papers, journal articles, and research publications.
## Overview
The academic filter—sometimes referred to as "academic mode" or "Focus: Academic"—is a feature in Perplexity that allows users to target their searches specifically to academic and scholarly sources. This is especially useful for students, researchers, and professionals who require peer-reviewed papers, journal articles, and research-focused answers rather than general web content.
When you activate the academic filter by setting `search_mode: "academic"`, Perplexity prioritizes results from scholarly databases, journals, and reputable academic publications, filtering out non-academic or general web sources. This ensures that the answers you receive are grounded in research and scholarly consensus.
## Key Features and Functionality
* **Source Filtering**: Prioritizes scholarly databases, academic journals, and research publications
* **Research Focus**: Returns results based on peer-reviewed research rather than general web content
* **Enhanced Precision**: Provides more technical and discipline-specific information for academic queries
* **Compatibility**: Works with other search parameters like `search_context_size` to further refine results
## Usage Examples
### Basic Academic Search
This example shows how to perform a basic search using the academic filter.
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar-pro",
messages=[{"role": "user", "content": "What is the scientific name of the lions mane mushroom?"}],
search_mode="academic",
web_search_options={"search_context_size": "low"}
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar-pro",
messages: [{"role": "user", "content": "What is the scientific name of the lions mane mushroom?"}],
search_mode: "academic",
web_search_options: {"search_context_size": "low"}
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "accept: application/json" \
--header "authorization: Bearer $SONAR_API_KEY" \
--header "content-type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [{"role": "user", "content": "What is the scientific name of the lions mane mushroom?"}],
"search_mode": "academic",
"web_search_options": {"search_context_size": "low"}
}' | jq
```
### Combining Academic Mode with Other Parameters
You can combine the academic filter with other parameters for more refined searches:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar",
messages=[{"role": "user", "content": "What are the latest findings on neural networks for image recognition?"}],
search_mode="academic",
search_after_date_filter="1/1/2023",
web_search_options={"search_context_size": "high"}
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar",
messages: [{"role": "user", "content": "What are the latest findings on neural networks for image recognition?"}],
search_mode: "academic",
search_after_date_filter: "1/1/2023",
web_search_options: {"search_context_size": "high"}
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "accept: application/json" \
--header "authorization: Bearer $SONAR_API_KEY" \
--header "content-type: application/json" \
--data '{
"model": "sonar",
"messages": [{"role": "user", "content": "What are the latest findings on neural networks for image recognition?"}],
"stream": false,
"search_mode": "academic",
"search_after_date_filter": "1/1/2023",
"web_search_options": {"search_context_size": "high"}
}' | jq
```
## Recommended Use Cases
The academic filter is particularly valuable for:
1. **Research Literature Reviews**: When you need to gather scholarly information on a specific topic
2. **Technical and Scientific Queries**: For questions requiring scientifically accurate, peer-reviewed answers
3. **Academic Writing Assistance**: When working on papers, theses, or dissertations that require scholarly sources
4. **Educational Support**: For students and educators requiring academically rigorous information
## Best Practices
### Optimizing Academic Searches
* **Be Specific**: Formulate clear, focused questions to receive more precise academic responses
* **Use Technical Terminology**: Include field-specific terms to better target relevant academic literature
* **Combine with Date Filters**: For the most recent research, combine with `search_after_date_filter`
* **Adjust Context Size**: Use higher `search_context_size` values for more comprehensive academic responses
### Performance Considerations
* Academic searches may sometimes take slightly longer due to the specialized nature of scholarly databases
* Consider using models like `sonar-deep-research` for particularly complex academic inquiries
* For more comprehensive literature reviews, set `stream: false` to receive complete responses
### Limitations
* Availability of academic sources varies by field and topic
* Very recent research (published within the last few months) may not always be included
* Some paywalled or subscription-only academic content may not be fully accessible
⸻
# API Key Management
Source: https://docs.perplexity.ai/guides/api-key-management
Learn how to generate, revoke, and rotate API keys for secure access
## Overview
API keys are essential for authenticating requests to the Perplexity API. This guide covers how to create, manage, and rotate your API keys using our authentication token management endpoints.
API keys should be treated as sensitive credentials. Store them securely and never expose them in client-side code or public repositories.
## Getting Started: Create Your API Group First
**Important Prerequisites**: Before you can generate any API keys, you must first create an API group through the Perplexity web interface.
Navigate to the API Groups page and create your first group:
**[Create API Group →](https://www.perplexity.ai/account/api/group)**
API groups help organize your keys and manage access across different projects or environments.
Choose a descriptive name for your API group (e.g., "Production", "Development", or your project name) to help with organization.
Once you have an API group, navigate to the API Keys page to generate your first key:
**[Generate API Keys →](https://www.perplexity.ai/account/api/keys)**
You can create multiple keys within each group for different purposes or environments.
After creating your first API key through the web interface, you can use the programmatic endpoints below to generate and manage additional keys.
## Key Management Endpoints
Perplexity provides two endpoints for managing API keys programmatically:
* **`/generate_auth_token`** - Creates a new API key
* **`/revoke_auth_token`** - Revokes an existing API key
Once an API key is revoked, it cannot be recovered. Make sure to update your applications with new keys before revoking old ones.
## Generating API Keys
Create new API keys programmatically with optional naming for better organization.
### Request
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/generate_auth_token \
--header "Authorization: Bearer YOUR_EXISTING_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"token_name": "Production API Key"
}'
```
```python Python theme={null}
import requests
url = "https://api.perplexity.ai/generate_auth_token"
headers = {
"Authorization": "Bearer YOUR_EXISTING_API_KEY",
"Content-Type": "application/json"
}
payload = {
"token_name": "Production API Key" # Optional
}
response = requests.post(url, headers=headers, json=payload)
data = response.json()
print(f"New API Key: {data['auth_token']}")
print(f"Created at: {data['created_at_epoch_seconds']}")
```
```typescript TypeScript theme={null}
const response = await fetch("https://api.perplexity.ai/generate_auth_token", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_EXISTING_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
token_name: "Production API Key" // Optional
})
});
const data = await response.json();
console.log(`New API Key: ${data.auth_token}`);
console.log(`Created at: ${data.created_at_epoch_seconds}`);
```
### Response
```json theme={null}
{
"auth_token": "pplx-1234567890abcdef",
"created_at_epoch_seconds": 1735689600,
"token_name": "Production API Key"
}
```
Store the `auth_token` immediately and securely. This is the only time you'll be able to see the full token value.
## Revoking API Keys
Revoke API keys that are no longer needed or may have been compromised.
### Request
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/revoke_auth_token \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"auth_token": "pplx-1234567890abcdef"
}'
```
```python Python theme={null}
import requests
url = "https://api.perplexity.ai/revoke_auth_token"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"auth_token": "pplx-1234567890abcdef"
}
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 200:
print("API key successfully revoked")
```
```typescript TypeScript theme={null}
const response = await fetch("https://api.perplexity.ai/revoke_auth_token", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
auth_token: "pplx-1234567890abcdef"
})
});
if (response.status === 200) {
console.log("API key successfully revoked");
}
```
### Response
Returns a `200 OK` status code on successful revocation.
## API Key Rotation
Regular key rotation is a security best practice that minimizes the impact of potential key compromises. Here's how to implement zero-downtime key rotation:
### Rotation Strategy
Create a new API key while your current key is still active:
```python theme={null}
# Generate new key
new_key_response = requests.post(
"https://api.perplexity.ai/generate_auth_token",
headers={"Authorization": f"Bearer {current_key}"},
json={"token_name": f"Rotated Key - {datetime.now().isoformat()}"}
)
new_key = new_key_response.json()["auth_token"]
```
Deploy the new key to your applications:
```python theme={null}
# Update environment variables or secrets management
os.environ["PERPLEXITY_API_KEY"] = new_key
# Verify new key works
test_response = requests.post(
"https://api.perplexity.ai/chat/completions",
headers={"Authorization": f"Bearer {new_key}"},
json={
"model": "sonar",
"messages": [{"role": "user", "content": "Test"}]
}
)
assert test_response.status_code == 200
```
Ensure all services are using the new key before proceeding:
```python theme={null}
# Monitor your application logs to confirm
# all instances are using the new key
time.sleep(300) # Wait for propagation
```
Once confirmed, revoke the old key:
```python theme={null}
# Revoke old key
revoke_response = requests.post(
"https://api.perplexity.ai/revoke_auth_token",
headers={"Authorization": f"Bearer {new_key}"},
json={"auth_token": current_key}
)
assert revoke_response.status_code == 200
print("Key rotation completed successfully")
```
### Automated Rotation Example
Here's a complete example of an automated key rotation script:
```python Python theme={null}
import requests
import os
import time
from datetime import datetime
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class PerplexityKeyRotator:
def __init__(self, current_key):
self.base_url = "https://api.perplexity.ai"
self.current_key = current_key
def generate_new_key(self, name=None):
"""Generate a new API key"""
url = f"{self.base_url}/generate_auth_token"
headers = {"Authorization": f"Bearer {self.current_key}"}
payload = {}
if name:
payload["token_name"] = name
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
return response.json()
def test_key(self, key):
"""Test if a key is valid"""
url = f"{self.base_url}/chat/completions"
headers = {"Authorization": f"Bearer {key}"}
payload = {
"model": "sonar",
"messages": [{"role": "user", "content": "Test"}],
"max_tokens": 1
}
try:
response = requests.post(url, headers=headers, json=payload)
return response.status_code == 200
except:
return False
def revoke_key(self, key_to_revoke):
"""Revoke an API key"""
url = f"{self.base_url}/revoke_auth_token"
headers = {"Authorization": f"Bearer {self.current_key}"}
payload = {"auth_token": key_to_revoke}
response = requests.post(url, headers=headers, json=payload)
return response.status_code == 200
def rotate_key(self, update_callback=None):
"""Perform complete key rotation"""
logger.info("Starting key rotation...")
# Step 1: Generate new key
new_key_data = self.generate_new_key(
name=f"Rotated-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
)
new_key = new_key_data["auth_token"]
logger.info(f"New key generated: {new_key[:10]}...")
# Step 2: Test new key
if not self.test_key(new_key):
raise Exception("New key validation failed")
logger.info("New key validated successfully")
# Step 3: Update application (callback)
if update_callback:
update_callback(new_key)
logger.info("Application updated with new key")
# Step 4: Wait for propagation
logger.info("Waiting for propagation...")
time.sleep(30)
# Step 5: Revoke old key
old_key = self.current_key
self.current_key = new_key # Use new key for revocation
if self.revoke_key(old_key):
logger.info("Old key revoked successfully")
else:
logger.warning("Failed to revoke old key")
logger.info("Key rotation completed")
return new_key
# Usage example
def update_environment(new_key):
"""Update your environment with the new key"""
os.environ["PERPLEXITY_API_KEY"] = new_key
# Update your secrets management system here
# update_aws_secrets_manager(new_key)
# update_kubernetes_secret(new_key)
# Perform rotation
rotator = PerplexityKeyRotator(os.environ["PERPLEXITY_API_KEY"])
new_key = rotator.rotate_key(update_callback=update_environment)
print(f"Rotation complete. New key: {new_key[:10]}...")
```
```typescript TypeScript theme={null}
import fetch from 'node-fetch';
class PerplexityKeyRotator {
private baseUrl = 'https://api.perplexity.ai';
private currentKey: string;
constructor(currentKey: string) {
this.currentKey = currentKey;
}
async generateNewKey(name?: string): Promise<{
auth_token: string;
created_at_epoch_seconds: number;
token_name?: string;
}> {
const response = await fetch(`${this.baseUrl}/generate_auth_token`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.currentKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(name ? { token_name: name } : {})
});
if (!response.ok) {
throw new Error(`Failed to generate key: ${response.statusText}`);
}
return response.json();
}
async testKey(key: string): Promise {
try {
const response = await fetch(`${this.baseUrl}/chat/completions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${key}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'sonar',
messages: [{ role: 'user', content: 'Test' }],
max_tokens: 1
})
});
return response.ok;
} catch {
return false;
}
}
async revokeKey(keyToRevoke: string): Promise {
const response = await fetch(`${this.baseUrl}/revoke_auth_token`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.currentKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ auth_token: keyToRevoke })
});
return response.ok;
}
async rotateKey(updateCallback?: (newKey: string) => Promise): Promise {
console.log('Starting key rotation...');
// Step 1: Generate new key
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const newKeyData = await this.generateNewKey(`Rotated-${timestamp}`);
const newKey = newKeyData.auth_token;
console.log(`New key generated: ${newKey.substring(0, 10)}...`);
// Step 2: Test new key
if (!(await this.testKey(newKey))) {
throw new Error('New key validation failed');
}
console.log('New key validated successfully');
// Step 3: Update application
if (updateCallback) {
await updateCallback(newKey);
console.log('Application updated with new key');
}
// Step 4: Wait for propagation
console.log('Waiting for propagation...');
await new Promise(resolve => setTimeout(resolve, 30000));
// Step 5: Revoke old key
const oldKey = this.currentKey;
this.currentKey = newKey;
if (await this.revokeKey(oldKey)) {
console.log('Old key revoked successfully');
} else {
console.warn('Failed to revoke old key');
}
console.log('Key rotation completed');
return newKey;
}
}
// Usage example
async function updateEnvironment(newKey: string): Promise {
process.env.PERPLEXITY_API_KEY = newKey;
// Update your secrets management system here
// await updateAwsSecretsManager(newKey);
// await updateKubernetesSecret(newKey);
}
// Perform rotation
const rotator = new PerplexityKeyRotator(process.env.PERPLEXITY_API_KEY!);
const newKey = await rotator.rotateKey(updateEnvironment);
console.log(`Rotation complete. New key: ${newKey.substring(0, 10)}...`);
```
## Best Practices
Never hardcode API keys in your source code. Store them in environment variables or secure secret management systems.
**Good**: `os.environ["PERPLEXITY_API_KEY"]`
**Bad**: `api_key = "pplx-1234567890abcdef"`
Rotate your API keys regularly (e.g., every 90 days) to minimize the impact of potential compromises.
Set up automated rotation scripts to ensure zero downtime during the rotation process.
When generating keys, use the `token_name` parameter to identify their purpose and environment.
Examples: "Production-Main", "Development-Testing", "CI/CD-Pipeline"
Track which keys are being used in your applications and revoke unused keys promptly.
Maintain an inventory of active keys and their purposes.
## Security Considerations
**Never expose API keys in:**
* Client-side JavaScript code
* Mobile applications
* Public repositories
* Log files or error messages
* URLs or query parameters
### If a Key is Compromised
1. **Immediately generate a new key** using `/generate_auth_token`
2. **Update all applications** to use the new key
3. **Revoke the compromised key** using `/revoke_auth_token`
4. **Review access logs** to identify any unauthorized usage
5. **Implement additional security measures** such as IP allowlisting if available
## Troubleshooting
| Issue | Solution |
| -------------------------------------- | ---------------------------------------------------------------- |
| "Authentication failed" after rotation | Ensure the new key has propagated to all service instances |
| Cannot revoke a key | Verify you're using a valid API key with appropriate permissions |
| Key generation fails | Check your account status and API tier limits |
| Services still using old key | Implement proper secret rotation in your deployment pipeline |
For additional support with API key management, visit your [API settings page](https://www.perplexity.ai/settings/api) or contact our support team.
# Perplexity Crawlers
Source: https://docs.perplexity.ai/guides/bots
We strive to improve our service every day by delivering the best search experience possible. To achieve this, we collect data using web crawlers ("robots") and user agents that gather and index information from the internet, operating either automatically or in response to user requests. Webmasters can use the following robots.txt tags to manage how their sites and content interact with Perplexity. Each setting works independently, and it may take up to 24 hours for our systems to reflect changes.
| User Agent | Description |
| :-------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| PerplexityBot | `PerplexityBot` is designed to surface and link websites in search results on Perplexity. It is not used to crawl content for AI foundation models. To ensure your site appears in search results, we recommend allowing `PerplexityBot` in your site's `robots.txt` file and permitting requests from our published IP ranges listed below.
Full user-agent string: `Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; PerplexityBot/1.0; +https://perplexity.ai/perplexitybot)`
Published IP addresses: [https://www.perplexity.com/perplexitybot.json](https://www.perplexity.com/perplexitybot.json) |
| Perplexity‑User | `Perplexity-User` supports user actions within Perplexity. When users ask Perplexity a question, it might visit a web page to help provide an accurate answer and include a link to the page in its response. `Perplexity-User` controls which sites these user requests can access. It is not used for web crawling or to collect content for training AI foundation models.
Full user-agent string: `Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Perplexity-User/1.0; +https://perplexity.ai/perplexity-user)`
Published IP addresses: [https://www.perplexity.com/perplexity-user.json](https://www.perplexity.com/perplexity-user.json)
Since a user requested the fetch, this fetcher generally ignores robots.txt rules. |
## WAF Configuration
If you're using a Web Application Firewall (WAF) to protect your site, you may need to explicitly whitelist Perplexity's bots to ensure they can access your content. Below are configuration guidelines for popular WAF providers.
### Cloudflare WAF
To configure Cloudflare WAF to allow Perplexity bots:
In your Cloudflare dashboard, go to **Security** → **WAF**.
Click on **Custom rules** and create a new rule to allow Perplexity bots.
Set up a rule that combines both User-Agent and IP address conditions:
* **Field**: User Agent
* **Operator**: Contains
* **Value**: `PerplexityBot` OR `Perplexity-User`
**AND**
* **Field**: IP Source Address
* **Operator**: Is in
* **Value**: Use the IP ranges from the official endpoints listed below
Set the action to **Allow** to ensure these requests bypass other security rules.
### AWS WAF
For AWS WAF configuration, create IP sets and string match conditions:
In the AWS WAF console, create IP sets for both PerplexityBot and Perplexity-User using the IP addresses from the official endpoints listed below.
Create string match conditions for the User-Agent headers:
* `PerplexityBot`
* `Perplexity-User`
Create rules that combine the IP sets with the corresponding User-Agent strings, and set the action to **Allow**.
Associate these rules with your Web ACL and ensure they have higher priority than blocking rules.
### IP Address Sources
Always use the most current IP ranges from the official JSON endpoints. These addresses are updated regularly and should be the source of truth for your WAF configurations.
* **PerplexityBot IP addresses**: [https://www.perplexity.com/perplexitybot.json](https://www.perplexity.com/perplexitybot.json)
* **Perplexity-User IP addresses**: [https://www.perplexity.com/perplexity-user.json](https://www.perplexity.com/perplexity-user.json)
Set up automated processes to periodically fetch and update your WAF rules with the latest IP ranges from these endpoints to ensure continuous access for Perplexity bots.
### Best Practices
When configuring WAF rules for Perplexity bots, combine both User-Agent string matching and IP address verification for enhanced security while ensuring legitimate bot traffic can access your content.
Changes to WAF configurations may take some time to propagate. Monitor your logs to ensure the rules are working as expected and that legitimate Perplexity bot traffic is being allowed through.
# OpenAI Compatibility
Source: https://docs.perplexity.ai/guides/chat-completions-guide
Use Perplexity’s Sonar API with OpenAI’s client libraries for seamless integration.
## OpenAI compatibility at a glance
Perplexity's Sonar API was designed with OpenAI compatibility in mind, matching the Chat Completions API interface. You can seamlessly use your existing OpenAI client libraries by simply changing the base URL and providing your Perplexity API key.
Keep using your existing OpenAI SDKs to get started fast; switch to our [native SDKs](/guides/perplexity-sdk) later as needed.
## Configuring OpenAI SDKs to call Sonar
To start using Sonar with OpenAI's client libraries, pass your Perplexity API key and change the base\_url to `https://api.perplexity.ai`:
```python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.perplexity.ai"
)
resp = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "user", "content": "Hello!"}
]
)
print(resp.choices[0].message.content)
```
```typescript theme={null}
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://api.perplexity.ai"
});
const resp = await client.chat.completions.create({
model: "sonar-pro",
messages: [{ role: "user", content: "Hello!" }]
});
console.log(resp.choices[0].message.content);
```
Your responses will match OpenAI's format exactly. See the [response structure](#response-structure) section below for complete field details.
## API compatibility
### Standard OpenAI parameters
These parameters work exactly the same as OpenAI's API:
* `model` - Model name (use Perplexity model names)
* `messages` - Chat messages array
* `temperature` - Sampling temperature (0-2)
* `max_tokens` - Maximum tokens in response
* `top_p` - Nucleus sampling parameter
* `frequency_penalty` - Frequency penalty (-2.0 to 2.0)
* `presence_penalty` - Presence penalty (-2.0 to 2.0)
* `stream` - Enable streaming responses
### Perplexity-specific parameters
These Perplexity-specific parameters are also included:
* `search_domain_filter` - Limit or exclude specific domains
* `search_recency_filter` - Filter by content recency
* `return_images` - Include image URLs in response
* `return_related_questions` - Include related questions
* `search_mode` - "web" (default) or "academic" mode selector.
See [API Reference](/api-reference) for parameter details and models.
## Examples with OpenAI's client libraries
### Basic Usage
Start with these simple examples to make your first API calls:
```python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.perplexity.ai"
)
response = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "user", "content": "What are the latest developments in AI?"}
]
)
print(response.choices[0].message.content)
```
```typescript theme={null}
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://api.perplexity.ai"
});
const response = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{ role: "user", content: "What are the latest developments in AI?" }
]
});
console.log(response.choices[0].message.content);
```
### Advanced Examples
For more control over search behavior and response generation:
```python Search Filtering theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.perplexity.ai"
)
response = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "user", "content": "Latest climate research findings"}
],
extra_body={
"search_domain_filter": ["nature.com", "science.org"],
"search_recency_filter": "month"
}
)
print(response.choices[0].message.content)
print(f"Sources: {len(response.search_results)} articles found")
```
```python Full Configuration theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.perplexity.ai"
)
response = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "system", "content": "Be precise and concise."},
{"role": "user", "content": "How many stars are in our galaxy?"}
],
temperature=0.2,
max_tokens=1000,
extra_body={
"search_mode": "web",
"search_domain_filter": ["nasa.gov", "space.com"],
"return_related_questions": True
}
)
print(response.choices[0].message.content)
for result in response.search_results:
print(f"- {result['title']}: {result['url']}")
```
```typescript Search Filtering theme={null}
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://api.perplexity.ai"
});
const response = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{ role: "user", content: "Latest climate research findings" }
],
// TypeScript SDK: Use direct parameters (not extra_body)
search_domain_filter: ["nature.com", "science.org"],
search_recency_filter: "month"
});
console.log(response.choices[0].message.content);
console.log(`Sources: ${response.search_results.length} articles found`);
```
```typescript Full Configuration theme={null}
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://api.perplexity.ai"
});
const response = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{ role: "system", content: "Be precise and concise." },
{ role: "user", content: "How many stars are in our galaxy?" }
],
temperature: 0.2,
max_tokens: 1000,
search_mode: "web",
search_domain_filter: ["nasa.gov", "space.com"],
return_related_questions: true
});
console.log(response.choices[0].message.content);
response.search_results.forEach(result => {
console.log(`- ${result.title}: ${result.url}`);
});
```
## Response structure
Perplexity API responses include both standard OpenAI fields and additional search metadata:
### Standard OpenAI Fields
* `choices[0].message.content` - The AI-generated response
* `model` - The model name used
* `usage` - Token consumption details
* `id`, `created`, `object` - Standard response metadata
### Perplexity-Specific Fields
* `search_results` - Array of web sources with titles, URLs, and dates
* `usage.search_context_size` - Search context setting used
```python theme={null}
# Access the main response
content = response.choices[0].message.content
print(content)
# Access search sources
for result in response.search_results:
print(f"Source: {result['title']}")
print(f"URL: {result['url']}")
print(f"Date: {result['date']}")
print("---")
# Check token usage
print(f"Tokens used: {response.usage.total_tokens}")
```
```typescript theme={null}
// Access the main response
const content = response.choices[0].message.content;
console.log(content);
// Access search sources
response.search_results.forEach(result => {
console.log(`Source: ${result.title}`);
console.log(`URL: ${result.url}`);
console.log(`Date: ${result.date}`);
console.log("---");
});
// Check token usage
console.log(`Tokens used: ${response.usage.total_tokens}`);
```
Search results are returned even when streaming is enabled, but they arrive in the final chunk of the stream. See the [Streaming Guide](/guides/streaming-responses) for details.
## Unsupported and notable differences
While compatibility is high, note the following differences from OpenAI:
* **Model names**: Use Perplexity models like `sonar-pro`, `sonar-reasoning-pro`.
* **Search controls**: Perplexity adds web/academic search parameters via `extra_body` (Python) or root fields (TypeScript) as shown above.
If you previously used OpenAI-only fields that aren't applicable to Perplexity search controls, remove or ignore them. Check the API Reference for the current list of supported fields.
## Technical notes
* **Error format**: Same as OpenAI's API for compatibility
* **Rate limiting**: Apply standard rate limiting practices
* **Model names**: Use Perplexity model names (`sonar-pro`, `sonar-reasoning-pro`, etc.)
* **Authentication**: Use `Bearer` token format in Authorization header
## Next steps
Browse available Sonar models and their capabilities.
Learn to fine-tune search behavior with filters and parameters.
Implement real-time streaming responses in your application.
View complete endpoint documentation and parameter details.
# Chat Completions SDK
Source: https://docs.perplexity.ai/guides/chat-completions-sdk
Use the Perplexity SDKs to access the Chat Completions API with type safety, streaming support, and modern language features.
## Overview
Generate AI responses with web-grounded knowledge using either the Python or TypeScript SDKs. Both SDKs provide full support for chat completions, streaming responses, async operations, and comprehensive error handling.
## Quick Start
```python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": "Tell me about the latest developments in AI",
}
],
model="sonar",
)
print(f"Response: {completion.choices[0].message.content}")
```
```typescript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
messages: [
{
role: "user",
content: "Tell me about the latest developments in AI",
}
],
model: "sonar",
});
console.log(`Response: ${completion.choices[0].message.content}`);
```
```
Response: Based on the latest information, here are some key developments in AI for 2024:
**Large Language Models & Foundation Models:**
- GPT-4 and its variants continue to improve with better reasoning capabilities
- Open-source models like Llama 2 and Code Llama have gained significant traction
- Specialized models for coding, math, and scientific tasks have emerged
**Multimodal AI:**
- Vision-language models can now process images, text, and audio simultaneously
- Real-time image generation and editing capabilities have improved dramatically
**AI Safety & Alignment:**
- Constitutional AI and RLHF techniques are becoming standard practice
- Increased focus on AI governance and regulatory frameworks...
Request ID: req_123abc456def789
```
## Features
### Model Selection
Choose from different Sonar models based on your needs:
```python theme={null}
# Standard Sonar model for general queries
completion = client.chat.completions.create(
messages=[{"role": "user", "content": "What is quantum computing?"}],
model="sonar"
)
# Sonar Pro for more complex queries
completion = client.chat.completions.create(
messages=[{"role": "user", "content": "Analyze the economic implications of renewable energy adoption"}],
model="sonar-pro"
)
# Sonar Reasoning Pro for complex analytical tasks
completion = client.chat.completions.create(
messages=[{"role": "user", "content": "Solve this complex mathematical problem step by step"}],
model="sonar-reasoning-pro"
)
```
```typescript theme={null}
// Standard Sonar model for general queries
const completion = await client.chat.completions.create({
messages: [{ role: "user", content: "What is quantum computing?" }],
model: "sonar"
});
// Sonar Pro for more complex queries
const completion = await client.chat.completions.create({
messages: [{ role: "user", content: "Analyze the economic implications of renewable energy adoption" }],
model: "sonar-pro"
});
// Sonar Reasoning Pro for complex analytical tasks
const completion = await client.chat.completions.create({
messages: [{ role: "user", content: "Solve this complex mathematical problem step by step" }],
model: "sonar-reasoning-pro"
});
```
### Conversation Context
Build multi-turn conversations with context:
```python theme={null}
messages = [
{"role": "system", "content": "You are a helpful research assistant."},
{"role": "user", "content": "What are the main causes of climate change?"},
{"role": "assistant", "content": "The main causes of climate change include..."},
{"role": "user", "content": "What are some potential solutions?"}
]
completion = client.chat.completions.create(
messages=messages,
model="sonar"
)
```
```typescript theme={null}
const messages: Perplexity.ChatMessage[] = [
{ role: "system", content: "You are a helpful research assistant." },
{ role: "user", content: "What are the main causes of climate change?" },
{ role: "assistant", content: "The main causes of climate change include..." },
{ role: "user", content: "What are some potential solutions?" }
];
const completion = await client.chat.completions.create({
messages,
model: "sonar"
});
```
### Web Search Options
Control how the model searches and uses web information:
```python theme={null}
completion = client.chat.completions.create(
messages=[
{"role": "user", "content": "What are the latest developments in renewable energy?"}
],
model="sonar",
web_search_options={
"search_recency_filter": "week", # Focus on recent results
"search_domain_filter": ["energy.gov", "iea.org", "irena.org"], # Trusted sources
"max_search_results": 10
}
)
```
```typescript theme={null}
const completion = await client.chat.completions.create({
messages: [
{ role: "user", content: "What are the latest developments in renewable energy?" }
],
model: "sonar",
search_recency_filter: "week", // Focus on recent results
search_domain_filter: ["energy.gov", "iea.org", "irena.org"], // Trusted sources
return_images: true, // Include image URLs
return_related_questions: true // Get follow-up questions
});
```
### Response Customization
Customize response format and behavior:
```python theme={null}
completion = client.chat.completions.create(
messages=[
{"role": "user", "content": "Explain machine learning in simple terms"}
],
model="sonar",
max_tokens=500, # Limit response length
temperature=0.7, # Control creativity
top_p=0.9, # Control diversity
presence_penalty=0.1, # Reduce repetition
frequency_penalty=0.1
)
```
```typescript theme={null}
const completion = await client.chat.completions.create({
messages: [
{ role: "user", content: "Explain machine learning in simple terms" }
],
model: "sonar",
max_tokens: 500, // Limit response length
temperature: 0.7, // Control creativity (0-2)
top_p: 0.9, // Control diversity (0-1)
presence_penalty: 0.1, // Reduce repetition (-2 to 2)
frequency_penalty: 0.1 // Reduce repetition (-2 to 2)
});
```
### Streaming Responses
Get real-time response streaming for better user experience:
```python theme={null}
stream = client.chat.completions.create(
messages=[
{"role": "user", "content": "Write a summary of recent AI breakthroughs"}
],
model="sonar",
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
```
```typescript theme={null}
const stream = await client.chat.completions.create({
messages: [
{ role: "user", content: "Write a summary of recent AI breakthroughs" }
],
model: "sonar",
stream: true
});
for await (const chunk of stream) {
if (chunk.choices[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
```
For comprehensive streaming documentation including metadata collection, error handling, advanced patterns, and raw HTTP examples, see the [Streaming Guide](/guides/streaming-responses).
## Async Chat Completions
Async chat completions are only available for the sonar-deep-research model.
For long-running or batch processing tasks, use the async endpoints:
### Creating Async Requests
```python theme={null}
# Start an async completion request
async_request = client.async_.chat.completions.create(
messages=[
{"role": "user", "content": "Write a comprehensive analysis of renewable energy trends"}
],
model="sonar-deep-research",
max_tokens=2000
)
print(f"Request submitted with ID: {async_request.request_id}")
print(f"Status: {async_request.status}")
```
```typescript theme={null}
// Start an async completion request
const asyncRequest = await client.async.chat.completions.create({
messages: [
{ role: "user", content: "Write a comprehensive analysis of renewable energy trends" }
],
model: "sonar-deep-reasearch",
max_tokens: 2000
});
console.log(`Request submitted with ID: ${asyncRequest.request_id}`);
console.log(`Status: ${asyncRequest.status}`);
```
### Checking Request Status
```python theme={null}
# Check the status of an async request
request_id = "req_123abc456def789"
status = client.async_.chat.completions.get(request_id)
print(f"Status: {status.status}")
if status.status == "completed":
print(f"Response: {status.result.choices[0].message.content}")
elif status.status == "failed":
print(f"Error: {status.error}")
```
```typescript theme={null}
// Check the status of an async request
const requestId = "req_123abc456def789";
const status = await client.async.chat.completions.get(requestId);
console.log(`Status: ${status.status}`);
if (status.status === "completed") {
console.log(`Response: ${status.result?.choices[0]?.message?.content}`);
} else if (status.status === "failed") {
console.log(`Error: ${status.error}`);
}
```
### Listing Async Requests
```python theme={null}
# List recent async requests
requests = client.async_.chat.completions.list(
limit=10,
status="completed"
)
for request in requests.data:
print(f"ID: {request.id}, Status: {request.status}")
```
```typescript theme={null}
// List recent async requests
const requests = await client.async.chat.completions.list({
limit: 10,
status: "completed"
});
requests.data.forEach(request => {
console.log(`ID: ${request.id}, Status: ${request.status}`);
});
```
## Advanced Usage
### Error Handling
Handle chat-specific errors:
```python theme={null}
import perplexity
try:
completion = client.chat.completions.create(
messages=[{"role": "user", "content": "What is AI?"}],
model="sonar",
max_tokens=50000 # Exceeds limit
)
except perplexity.BadRequestError as e:
print(f"Invalid request parameters: {e}")
except perplexity.RateLimitError as e:
print("Rate limit exceeded, please retry later")
except perplexity.APIStatusError as e:
print(f"API error: {e.status_code}")
```
```typescript theme={null}
try {
const completion = await client.chat.completions.create({
messages: [{ role: "user", content: "What is AI?" }],
model: "sonar",
max_tokens: 50000 // Exceeds limit
});
} catch (error) {
if (error instanceof Perplexity.BadRequestError) {
console.error(`Invalid request parameters: ${error.message}`);
} else if (error instanceof Perplexity.RateLimitError) {
console.error("Rate limit exceeded, please retry later");
} else if (error instanceof Perplexity.APIError) {
console.error(`API error ${error.status}: ${error.message}`);
}
}
```
### Custom Instructions
Use system messages for consistent behavior:
```python theme={null}
system_prompt = """You are an expert research assistant specializing in technology and science.
Always provide well-sourced, accurate information and cite your sources.
Format your responses with clear headings and bullet points when appropriate."""
completion = client.chat.completions.create(
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": "Explain quantum computing applications"}
],
model="sonar-pro"
)
```
```typescript theme={null}
const systemPrompt = `You are an expert research assistant specializing in technology and science.
Always provide well-sourced, accurate information and cite your sources.
Format your responses with clear headings and bullet points when appropriate.`;
const completion = await client.chat.completions.create({
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: "Explain quantum computing applications" }
],
model: "sonar-pro"
});
```
### Concurrent Operations
Handle multiple conversations efficiently:
```python theme={null}
async def handle_multiple_chats(user_messages):
client = AsyncPerplexity()
tasks = [
client.chat.completions.create(
messages=[{"role": "user", "content": msg}],
model="sonar-deep-reseach"
)
for msg in user_messages
]
return await asyncio.gather(*tasks, return_exceptions=True)
```
```typescript theme={null}
async function processQuestions(questions: string[]) {
const tasks = questions.map(question =>
client.chat.completions.create({
messages: [{ role: "user", content: question }],
model: "sonar-deep-research"
})
);
const results = await Promise.all(tasks);
return results.map(result => result.choices[0].message.content);
}
const questions = [
"What is artificial intelligence?",
"How does machine learning work?",
"What are neural networks?"
];
const answers = await processQuestions(questions);
```
## Best Practices
Choose the right model for your use case: `sonar` for general queries, `sonar-pro` for complex analysis, `sonar-reasoning-pro` for analytical tasks.
```python theme={null}
# For quick factual queries
simple_query = client.chat.completions.create(
messages=[{"role": "user", "content": "What is the capital of France?"}],
model="sonar"
)
# For complex analysis
complex_query = client.chat.completions.create(
messages=[{"role": "user", "content": "Analyze the economic impact of AI on employment"}],
model="sonar-pro"
)
```
```typescript theme={null}
// For quick factual queries
const simpleQuery = await client.chat.completions.create({
messages: [{ role: "user", content: "What is the capital of France?" }],
model: "sonar"
});
// For complex analysis
const complexQuery = await client.chat.completions.create({
messages: [{ role: "user", content: "Analyze the economic impact of AI on employment" }],
model: "sonar-pro"
});
```
Use streaming for better user experience with lengthy responses.
```python theme={null}
def stream_response(query):
stream = client.chat.completions.create(
messages=[{"role": "user", "content": query}],
model="sonar",
stream=True
)
response = ""
for chunk in stream:
if chunk.choices[0].delta.content:
content = chunk.choices[0].delta.content
print(content, end="", flush=True)
response += content
return response
```
```typescript theme={null}
async function streamResponse(query: string): Promise {
const stream = await client.chat.completions.create({
messages: [{ role: "user", content: query }],
model: "sonar",
stream: true
});
let response = "";
for await (const chunk of stream) {
if (chunk.choices[0]?.delta?.content) {
const content = chunk.choices[0].delta.content;
process.stdout.write(content);
response += content;
}
}
return response;
}
```
Implement exponential backoff for production applications.
```python theme={null}
import time
import random
def chat_with_retry(messages, max_retries=3):
for attempt in range(max_retries):
try:
return client.chat.completions.create(
messages=messages,
model="sonar"
)
except perplexity.RateLimitError:
if attempt == max_retries - 1:
raise
delay = (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
```
```typescript theme={null}
async function chatWithRetry(
messages: Perplexity.ChatMessage[],
maxRetries: number = 3
): Promise {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.chat.completions.create({
messages,
model: "sonar"
});
} catch (error) {
if (error instanceof Perplexity.RateLimitError && attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
throw new Error("Max retries exceeded");
}
```
Configure parameters based on your application's needs.
```python theme={null}
# For factual Q&A
factual_config = {
"temperature": 0.1, # Low creativity for accuracy
"top_p": 0.9,
"search_recency_filter": "month"
}
# For creative writing
creative_config = {
"temperature": 0.8, # Higher creativity
"top_p": 0.95,
"presence_penalty": 0.1,
"frequency_penalty": 0.1
}
# Usage
factual_response = client.chat.completions.create(
messages=[{"role": "user", "content": "What is the current inflation rate?"}],
model="sonar",
**factual_config
)
```
```typescript theme={null}
// For factual Q&A
const factualConfig = {
temperature: 0.1, // Low creativity for accuracy
top_p: 0.9,
search_recency_filter: "month" as const
};
// For creative writing
const creativeConfig = {
temperature: 0.8, // Higher creativity
top_p: 0.95,
presence_penalty: 0.1,
frequency_penalty: 0.1
};
// Usage
const factualResponse = await client.chat.completions.create({
messages: [{ role: "user", content: "What is the current inflation rate?" }],
model: "sonar",
...factualConfig
});
```
## Resources
* [The Perplexity SDK Guide](/guides/perplexity-sdk) - The Perplexity SDK guide
* [OpenAI Compatibility](/guides/chat-completions-guide) - OpenAI compatibility guide
* [Streaming Responses](/guides/streaming-responses) - Complete streaming guide with advanced patterns
* [API Reference - Chat Completions](/api-reference/chat-completions-post) - Chat Completions API Reference
* [API Reference - Async Chat Completions](/api-reference/async-chat-completions-post) - Async API Reference
* [Structured Outputs](/guides/structured-outputs) - Formatted response generation
# Sonar Date and Time Filters
Source: https://docs.perplexity.ai/guides/date-range-filter-guide
The `search_after_date_filter` and `search_before_date_filter` parameters allow you to restrict search results to a specific publication date range. Only results with publication dates falling between these dates will be returned.
The `last_updated_after_filter` and `last_updated_before_filter` parameters allow you to filter by when content was last modified or updated, rather than when it was originally published.
The `search_recency_filter` parameter provides a convenient way to filter results by predefined time periods (e.g., "day", "week", "month", "year") relative to the current date.
Specific date filters must be provided in the "%m/%d/%Y" format (e.g., "3/1/2025"). Recency filters use predefined values like "day", "week", "month", or "year". All filters are optional—you may supply either specific dates or recency filters as needed.
## Overview
Date and time filters allow you to control which search results are returned by limiting them to specific time periods. There are three types of date and time filters available:
### Publication Date Filters
The `search_after_date_filter` and `search_before_date_filter` parameters filter results based on when content was **originally created or published**. This is useful when you need to:
* Find content published within a specific timeframe
* Exclude outdated or overly recent publications
* Focus on content from a particular publication period
### Last Updated Date Filters
The `last_updated_after_filter` and `last_updated_before_filter` parameters filter results based on when content was **last modified or updated**. This is useful when you need to:
* Find recently updated or maintained content
* Exclude stale content that hasn't been updated recently
* Focus on content that has been refreshed within a specific period
### Search Recency Filter
The `search_recency_filter` parameter provides a simple way to filter results by predefined time periods relative to the current date. This is useful when you need to:
* Find content from the past day, week, month, or year
* Get recent results without specifying exact dates
* Quickly filter for timely information
**Available values:**
* `"day"` - Content from the past 24 hours
* `"week"` - Content from the past 7 days
* `"month"` - Content from the past 30 days
* `"year"` - Content from the past 365 days
**Important:** These filter types target different dates—publication filters use the original creation/publication date, while last updated filters use the modification date, and recency filters use a relative time period from the current date.
To constrain search results by publication date:
```bash theme={null}
"search_after_date_filter": "3/1/2025",
"search_before_date_filter": "3/5/2025"
```
To constrain search results by last updated date:
```bash theme={null}
"last_updated_after_filter": "3/1/2025",
"last_updated_before_filter": "3/5/2025"
```
To constrain search results by recency:
```bash theme={null}
"search_recency_filter": "week"
```
These filters will be applied in addition to any other search parameters (for example, domain filters).
## Examples
**1. Limiting Results by Publication Date Range**
This example limits search results to content published between March 1, 2025, and March 5, 2025.
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar",
messages=[
{"role": "system", "content": "You are an expert on current events."},
{"role": "user", "content": "Show me tech news published this week."}
],
search_after_date_filter="3/1/2025",
search_before_date_filter="3/5/2025"
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar",
messages: [
{"role": "system", "content": "You are an expert on current events."},
{"role": "user", "content": "Show me tech news published this week."}
],
search_after_date_filter: "3/1/2025",
search_before_date_filter: "3/5/2025"
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"messages": [
{"role": "system", "content": "You are an expert on current events."},
{"role": "user", "content": "Show me tech news published this week."}
],
"search_after_date_filter": "3/1/2025",
"search_before_date_filter": "3/5/2025"
}' | jq
```
**2. Filtering with a Single Publication Date Parameter**
If you only wish to restrict the results to those published on or after a specific date, include just the `search_after_date_filter`:
```bash theme={null}
payload = {
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Show me news articles published after March 1, 2025."}
],
"search_after_date_filter": "3/1/2025"
}
```
**3. Filtering by Last Updated Date Range**
This example limits search results to content that was last updated between March 1, 2025, and March 5, 2025. This is useful for finding recently maintained or refreshed content.
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "system", "content": "You are an expert on current events."},
{"role": "user", "content": "Show me recently updated tech articles."}
],
last_updated_after_filter="3/1/2025",
last_updated_before_filter="3/5/2025"
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{"role": "system", "content": "You are an expert on current events."},
{"role": "user", "content": "Show me recently updated tech articles."}
],
last_updated_after_filter: "3/1/2025",
last_updated_before_filter: "3/5/2025"
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are an expert on current events."},
{"role": "user", "content": "Show me recently updated tech articles."}
],
"last_updated_after_filter": "3/1/2025",
"last_updated_before_filter": "3/5/2025"
}' | jq
```
**4. Combining Publication and Last Updated Filters**
You can combine both filter types to find content that was published in one timeframe and updated in another:
```bash theme={null}
payload = {
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Show me articles published last year but updated recently."}
],
"search_after_date_filter": "1/1/2024",
"search_before_date_filter": "12/31/2024",
"last_updated_after_filter": "3/1/2025"
}
```
**5. Using Search Recency Filter**
The `search_recency_filter` provides a convenient way to filter results by predefined time periods without specifying exact dates:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "system", "content": "You are an expert on current events."},
{"role": "user", "content": "What are the latest AI developments?"}
],
search_recency_filter="week"
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{"role": "system", "content": "You are an expert on current events."},
{"role": "user", "content": "What are the latest AI developments?"}
],
search_recency_filter: "week"
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are an expert on current events."},
{"role": "user", "content": "What are the latest AI developments?"}
],
"search_recency_filter": "week"
}' | jq
```
This example will return only content from the past 7 days, automatically calculated from the current date.
## Best Practices
**Date Format**
* Strict Format: Dates must match the “%m/%d/%Y” format exactly. For example, the date “3/1/2025” or “03/01/2025” is acceptable.
* Consistency: Use one or both filters consistently based on your search needs. Combining both provides a clear range.
**Filter Selection**
* Choose the Right Filter Type: Use publication date filters (`search_after_date_filter`/`search_before_date_filter`) when you care about when content was originally created. Use last updated filters (`last_updated_after_filter`/`last_updated_before_filter`) when you need recently maintained content. Use recency filters (`search_recency_filter`) for quick, relative time filtering.
* Recency vs. Exact Dates: Use `search_recency_filter` for convenience when you want recent content (e.g., "past week"). Use specific date filters when you need precise control over the time range.
* Combining Filters: You can use both publication and last updated filters together to find content that meets both criteria (e.g., published in 2024 but updated recently). Note that `search_recency_filter` cannot be combined with other date filters.
**Client-Side Validation**
* Regex Check: Validate date strings on the client side (or via the API) using a regex such as:
```bash theme={null}
date_regex='^(0?[1-9]|1[0-2])/(0?[1-9]|[12][0-9]|3[01])/[0-9]{4}$'
```
```python theme={null}
date_regex = r'^(0?[1-9]|1[0-2])/(0?[1-9]|[12]\d|3[01])/\d{4}$'
```
This ensures that dates conform to the required format before sending the request.
**Performance Considerations**
* Narrowing the Search: Applying date range filters typically reduces the number of results, which may improve response times and result relevance.
* Avoid Over-Restriction: Ensure that the date range is neither too narrow (limiting useful results) nor too broad (defeating the purpose of the filter).
⸻
## Last Updated Date Filters
The `last_updated_after_filter` and `last_updated_before_filter` parameters provide powerful filtering capabilities based on when content was last modified or updated, rather than when it was originally published. This is particularly useful for finding recently maintained, refreshed, or updated content.
### Parameters
**`last_updated_after_filter`**
* Filters search results to only include content last updated after this date
* Format should be %m/%d/%Y (e.g. 3/1/2025)
* Optional parameter
**`last_updated_before_filter`**
* Filters search results to only include content last updated before this date
* Format should be %m/%d/%Y (e.g. 3/1/2025)
* Optional parameter
### Use Cases
**Content Freshness**: Find articles, documentation, or resources that have been recently updated to ensure you're getting the most current information.
**Maintenance Tracking**: Identify which content has been actively maintained within a specific timeframe.
**Quality Assurance**: Focus on content that has been refreshed recently, which often indicates higher quality and relevance.
### Code Examples
**1. Find Recently Updated Content (After a Specific Date)**
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a helpful assistant focused on current information."},
{"role": "user", "content": "Find me documentation that has been updated recently."}
],
"last_updated_after_filter": "1/1/2025"
}' | jq
```
```python python theme={null}
import requests
url = "https://api.perplexity.ai/chat/completions"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
payload = {
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a helpful assistant focused on current information."},
{"role": "user", "content": "Find me documentation that has been updated recently."}
],
"last_updated_after_filter": "1/1/2025"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
```javascript javascript theme={null}
const response = await fetch('https://api.perplexity.ai/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'sonar-pro',
messages: [
{role: 'system', content: 'You are a helpful assistant focused on current information.'},
{role: 'user', content: 'Find me documentation that has been updated recently.'}
],
last_updated_after_filter: '1/1/2025'
})
});
const data = await response.json();
console.log(data);
```
**2. Find Content Updated Within a Specific Window**
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are an expert on technology trends."},
{"role": "user", "content": "Show me tech articles that were updated last week."}
],
"last_updated_after_filter": "2/24/2025",
"last_updated_before_filter": "3/3/2025"
}' | jq
```
```python python theme={null}
import requests
from datetime import datetime, timedelta
# Calculate dates for last week
today = datetime.now()
week_ago = today - timedelta(days=7)
url = "https://api.perplexity.ai/chat/completions"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
payload = {
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are an expert on technology trends."},
{"role": "user", "content": "Show me tech articles that were updated last week."}
],
"last_updated_after_filter": week_ago.strftime("%m/%d/%Y"),
"last_updated_before_filter": today.strftime("%m/%d/%Y")
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
**3. Exclude Recently Updated Content (Before a Date)**
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a research assistant."},
{"role": "user", "content": "Find historical content that hasn'\''t been updated recently."}
],
"last_updated_before_filter": "1/1/2024"
}' | jq
```
```python python theme={null}
import requests
url = "https://api.perplexity.ai/chat/completions"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
payload = {
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a research assistant."},
{"role": "user", "content": "Find historical content that hasn't been updated recently."}
],
"last_updated_before_filter": "1/1/2024"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
### Advanced Usage Patterns
**Combining with Domain Filters**
```python theme={null}
payload = {
"model": "sonar-pro",
"messages": [
{"role": "user", "content": "Latest updates on AI research."}
],
"search_domain_filter": ["arxiv.org", "openai.com"],
"last_updated_after_filter": "2/1/2025"
}
```
**Finding Maintained vs. Stale Content**
```python theme={null}
# Find actively maintained content
recent_payload = {
"model": "sonar-pro",
"messages": [
{"role": "user", "content": "Current best practices for React development."}
],
"last_updated_after_filter": "1/1/2025"
}
# Find potentially outdated content
stale_payload = {
"model": "sonar-pro",
"messages": [
{"role": "user", "content": "React development practices."}
],
"last_updated_before_filter": "1/1/2023"
}
```
### Tips for Last Updated Filters
1. **Content Freshness Strategy**: Use `last_updated_after_filter` when you need the most current information on rapidly evolving topics.
2. **Quality Indicator**: Recently updated content often indicates active maintenance and higher reliability.
3. **Research Applications**: Combine with publication date filters to find content published years ago but updated recently, indicating ongoing relevance.
4. **Performance**: These filters can significantly improve response relevance by focusing on maintained content.
5. **Date Selection**: Choose update date ranges based on your content type - technical documentation might need monthly updates, while academic papers might be updated annually.
# File Attachments with Sonar
Source: https://docs.perplexity.ai/guides/file-attachments
Learn how to upload and analyze documents (PDF, DOC, DOCX, TXT, RTF) using Sonar models
## Overview
Sonar models support document analysis through file uploads. You can provide files either as URLs to publicly accessible documents or as base64 encoded bytes. Ask questions about document content, get summaries, extract information, and perform detailed analysis of uploaded files in multiple formats including PDF, DOC, DOCX, TXT, and RTF.
**SDK Installation Required**: Install the official SDK first - `pip install perplexityai` for Python or `npm install @perplexity-ai/perplexity_ai` for TypeScript/JavaScript.
Document files can be provided as:
* A public URL pointing to the file
* Base64 encoded bytes (without any prefix)
Supported formats: PDF, DOC, DOCX, TXT, RTF.
The maximum file size is 50MB. Files larger than this limit will not be processed.
## Supported Features
* **Document Summarization**: Get concise summaries of document content
* **Question Answering**: Ask specific questions about the document
* **Content Extraction**: Extract key information, data, and insights
* **Multi-language Support**: Analyze documents in various languages
* **Large Document Handling**: Process lengthy documents efficiently
* **Multiple Formats**: Support for PDF, DOC, DOCX, TXT, and RTF files
## Basic Usage
### Simple Document Analysis
#### Using a Public URL
```bash cURL theme={null}
curl -X POST "https://api.perplexity.ai/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"content": [
{
"type": "text",
"text": "Summarize this document"
},
{
"type": "file_url",
"file_url": {
"url": "https://example.com/document.pdf"
},
}
],
"role": "user"
}
],
"model": "sonar-pro"
}'
```
```python Python theme={null}
from perplexity import Perplexity
# Initialize the client (uses PERPLEXITY_API_KEY environment variable)
client = Perplexity()
# Analyze the document
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": "Summarize this document"
},
{
"type": "file_url",
"file_url": {
"url": "https://example.com/document.pdf"
},
}
]
}
]
)
# Print the response
print(completion.choices[0].message.content)
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
// Initialize the client (uses PERPLEXITY_API_KEY environment variable)
const client = new Perplexity();
// Analyze the document
const completion = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: 'Summarize this document'
},
{
type: 'file_url',
file_url: {
url: 'https://example.com/document.pdf'
},
file_name: 'document.pdf'
}
]
}
]
});
// Print the response
console.log(completion.choices[0].message.content);
```
```go Go theme={null}
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
url := "https://api.perplexity.ai/chat/completions"
payload := map[string]interface{}{
"messages": []map[string]interface{}{
{
"content": []map[string]interface{}{
{
"type": "text",
"text": "Summarize this document",
},
{
"type": "file_url",
"file_url": map[string]string{
"url": "https://example.com/document.pdf",
},
},
},
"role": "user",
},
},
"model": "sonar-pro",
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
}
```
#### Using Base64 Encoded Bytes
```bash cURL theme={null}
curl -X POST "https://api.perplexity.ai/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"content": [
{
"type": "text",
"text": "Summarize this document"
},
{
"type": "file_url",
"file_url": {
"url": "JVBERi0xLjQKJeLjz9MKNCAwIG9iago..."
},
"file_name": "report.pdf"
}
],
"role": "user"
}
],
"model": "sonar-pro"
}'
```
```python Python theme={null}
from perplexity import Perplexity
import base64
# Initialize the client
client = Perplexity()
# Read and encode file
with open("document.pdf", "rb") as file:
file_data = file.read()
encoded_file = base64.b64encode(file_data).decode('utf-8')
# Analyze the document
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": "Summarize this document"
},
{
"type": "file_url",
"file_url": {
"url": encoded_file # Just the base64 string, no prefix
},
}
]
}
]
)
print(completion.choices[0].message.content)
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
const fs = require('fs');
// Initialize the client
const client = new Perplexity();
// Read and encode file
const fileData = fs.readFileSync('document.pdf');
const encodedFile = fileData.toString('base64');
// Analyze the document
const completion = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: 'Summarize this document'
},
{
type: 'file_url',
file_url: {
url: encodedFile // Just the base64 string, no prefix
},
file_name: 'document.pdf'
}
]
}
]
});
console.log(completion.choices[0].message.content);
```
### Advanced Analysis with Web Search
```bash cURL theme={null}
curl -X POST "https://api.perplexity.ai/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"content": [
{
"type": "text",
"text": "What are the key findings in this research paper? Provide additional context from recent studies."
},
{
"type": "file_url",
"file_url": {
"url": "https://example.com/research-paper.pdf"
},
"file_name": "research-paper.pdf"
}
],
"role": "user"
}
],
"model": "sonar-pro"
}'
```
```python Python theme={null}
from perplexity import Perplexity
# Initialize the client
client = Perplexity()
# Analyze the document with web search
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": "What are the key findings in this research paper? Provide additional context from recent studies."
},
{
"type": "file_url",
"file_url": {
"url": "https://example.com/research-paper.pdf"
},
"file_name": "research-paper.pdf"
}
]
}
]
)
# Print the response
print(completion.choices[0].message.content)
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
// Initialize the client
const client = new Perplexity();
// Analyze the document with web search
const completion = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: 'What are the key findings in this research paper? Provide additional context from recent studies.'
},
{
type: 'file_url',
file_url: {
url: 'https://example.com/research-paper.pdf'
},
file_name: 'research-paper.pdf'
}
]
}
]
});
// Print the response
console.log(completion.choices[0].message.content);
```
## File Requirements
* PDF files (.pdf extension)
* Word documents (.doc, .docx extensions)
* Text files (.txt extension)
* Rich Text Format (.rtf extension)
* Text-based documents (not scanned images)
* Base64 encoded file bytes
* Password-protected files (if publicly accessible)
* Maximum file size: 50MB
* Recommended: Under 50MB for optimal performance
* Maximum processing time: 60 seconds
* Large files may take longer to analyze
## Common Use Cases
### Academic Research
```python theme={null}
question = "What methodology was used in this study and what were the main conclusions?"
```
### Legal Documents
```python theme={null}
question = "Extract the key terms and conditions from this contract"
```
### Financial Reports
```python theme={null}
question = "What are the revenue trends and key financial metrics mentioned?"
```
### Technical Documentation
```python theme={null}
question = "Explain the implementation details and provide a step-by-step guide"
```
## Best Practices
* Be specific about what information you need
* Ask one focused question per request for best results
* Use follow-up questions to dive deeper into specific sections
* Ensure documents are text-based, not scanned images
* For URLs: Use publicly accessible URLs (Google Drive, Dropbox, etc.)
* For URLs: Verify the URL returns the document directly, not a preview page
* For base64: Encode the entire file content properly
* For base64: Provide only the base64 string without any prefix (no `data:` URI scheme)
* Break down complex questions into smaller parts
* Consider processing large documents in sections
* Use streaming for real-time responses on lengthy analyses
## Error Handling
### Common Issues
| Error | Cause | Solution |
| -------------------- | ------------------------------------ | --------------------------------------------------------- |
| `Invalid URL` | URL not accessible or invalid base64 | Verify URL returns file directly or check base64 encoding |
| `File too large` | File exceeds 50MB limit | Compress or split the document |
| `Processing timeout` | Document too complex | Simplify question or use smaller sections |
| `Invalid base64` | Malformed base64 string | Ensure proper base64 encoding without prefix |
## Pricing
PDF analysis follows standard Sonar pricing based on:
* Input tokens (document content + question)
* Output tokens (AI response)
* Web search usage (if enabled)
Large documents consume more input tokens. Consider the document size when estimating costs.
# Image Attachments with Sonar
Source: https://docs.perplexity.ai/guides/image-attachments
Learn how to upload and analyze images using Sonar models
## Overview
Sonar models support image analysis through direct image uploads. You can include images in your API requests to support multi-modal conversations alongside text. Images can be provided either as base64 encoded strings within a data URI or as standard HTTPS URLs.
**SDK Installation Required**: Install the official SDK first - `pip install perplexityai` for Python or `npm install @perplexity-ai/perplexity_ai` for TypeScript/JavaScript.
* When using base64 encoding, the API currently only supports images up to 50 MB per image.
* Supported formats for base64 encoded images: PNG (image/png), JPEG (image/jpeg), WEBP (image/webp), and GIF (image/gif).
* When using an HTTPS URL, the model will attempt to fetch the image from the provided URL. Ensure the URL is publicly accessible.
## Supported Features
Image uploads can be useful for:
* **Visual Question Answering**: Ask questions about visual content (e.g., text in a screenshot, diagram interpretation)
* **Context Analysis**: Providing context for follow-up queries
* **Multi-modal Conversations**: Analyzing visual media as part of a multi-turn conversation
* **Content Description**: Get detailed descriptions of images
* **Text Extraction**: Extract text from images and documents
## Input Methods
You can provide images in your requests using two methods:
### 1. URL of the Image
Provide a publicly accessible HTTPS URL pointing directly to the image file, for example:
```
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
```
### 2. Base64 Encoded Image Data
Encode the image as base64 and embed it in a data URI, for example:
```
data:image/png;base64,
```
## Request Format
Images must be embedded in the `messages` array, alongside any text input. Each image should be provided using the following structure:
```json theme={null}
{
"type": "image_url",
"image_url": {
"url": ""
}
}
```
The `url` field accepts either:
* **A URL of the image**: A publicly accessible HTTPS URL pointing directly to the image file
* **The base64 encoded image data**: A data URI in the format `data:image/{format};base64,{base64_content}`
## Basic Usage
Use this method when you have the image file locally and want to embed it directly into the request payload. Remember the 50MB size limit and supported formats (PNG, JPEG, WEBP, GIF).
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--data '{
"model": "sonar-pro",
"stream": false,
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Can you describe this image?"
},
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,$BASE64_ENCODED_IMAGE"
}
}
]
}
]
}' | jq
```
```python Python theme={null}
from perplexity import Perplexity
import base64
# Initialize the client
client = Perplexity()
# Read and encode image as base64
try:
with open("path/to/your/image.png", "rb") as image_file:
base64_image = base64.b64encode(image_file.read()).decode("utf-8")
image_data_uri = f"data:image/png;base64,{base64_image}" # Ensure correct MIME type
except FileNotFoundError:
print("Error: Image file not found.")
exit()
# Analyze the image
try:
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Can you describe this image?"},
{"type": "image_url", "image_url": {"url": image_data_uri}}
]
}
]
)
print(completion.choices[0].message.content)
except Exception as e:
print(f"API Request failed: {e}")
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
const fs = require('fs');
// Initialize the client
const client = new Perplexity();
// Read and encode image as base64
try {
const imageBuffer = fs.readFileSync('path/to/your/image.png');
const base64Image = imageBuffer.toString('base64');
const imageDataUri = `data:image/png;base64,${base64Image}`;
// Analyze the image
const completion = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Can you describe this image?' },
{ type: 'image_url', image_url: { url: imageDataUri } }
]
}
]
});
console.log(completion.choices[0].message.content);
} catch (error) {
console.error('Error:', error.message);
}
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import * as fs from 'fs';
// Initialize the client
const client = new Perplexity();
// Read and encode image as base64
try {
const imageBuffer = fs.readFileSync('path/to/your/image.png');
const base64Image = imageBuffer.toString('base64');
const imageDataUri = `data:image/png;base64,${base64Image}`;
// Analyze the image
const completion = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Can you describe this image?' },
{ type: 'image_url', image_url: { url: imageDataUri } }
]
}
]
});
console.log(completion.choices[0].message.content);
} catch (error) {
console.error('Error:', error.message);
}
```
Use this method to reference an image hosted online. Ensure the URL is publicly accessible and points directly to the image file.
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "accept: application/json" \
--header "content-type: application/json" \
--header "Authorization: Bearer $SONAR_API_KEY" \
--data '{
"model": "sonar-pro",
"stream": false,
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Can you describe the image at this URL?"
},
{
"type": "image_url",
"image_url": {
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
}
}
]
}
]
}' | jq
```
```python Python theme={null}
from perplexity import Perplexity
# Initialize the client
client = Perplexity()
# Example HTTPS URL
image_https_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
# Analyze the image
try:
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Can you describe the image at this URL?"},
{"type": "image_url", "image_url": {"url": image_https_url}}
]
}
]
)
print(completion.choices[0].message.content)
except Exception as e:
print(f"API Request failed: {e}")
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
// Initialize the client
const client = new Perplexity();
// Example HTTPS URL
const imageHttpsUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg";
// Analyze the image
try {
const completion = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Can you describe the image at this URL?' },
{ type: 'image_url', image_url: { url: imageHttpsUrl } }
]
}
]
});
console.log(completion.choices[0].message.content);
} catch (error) {
console.error('API Request failed:', error.message);
}
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Initialize the client
const client = new Perplexity();
// Example HTTPS URL
const imageHttpsUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg";
// Analyze the image
const analyzeImage = async (): Promise => {
try {
const completion = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Can you describe the image at this URL?' },
{ type: 'image_url', image_url: { url: imageHttpsUrl } }
]
}
]
});
console.log(completion.choices[0].message.content);
} catch (error) {
console.error('API Request failed:', error.message);
}
};
analyzeImage();
```
## Common Use Cases
### Screenshot Analysis
```python theme={null}
question = "What text is visible in this screenshot?"
```
### Diagram Interpretation
```python theme={null}
question = "Explain the workflow shown in this diagram"
```
### Product Analysis
```python theme={null}
question = "Describe the features and specifications of this product"
```
### Document Processing
```python theme={null}
question = "Extract all the key information from this document image"
```
## Best Practices
* Use high-resolution images for better text extraction
* Ensure good contrast for text recognition
* Avoid heavily compressed images when detail is important
* Use appropriate image formats (PNG for screenshots, JPEG for photos)
* Keep images under 50MB for base64 encoding
* Compress images when possible without losing critical detail
* Consider using HTTPS URLs for very large images
* Use WebP format for balanced quality and size
* Ensure URLs are publicly accessible (no authentication required)
* Use direct links to image files, not web pages
* Test URLs in a browser before using in API calls
* Consider using CDNs for reliable image hosting
## Pricing
Images are tokenized based on their pixel dimensions using the following formula:
```
tokens = (width px × height px) / 750
```
**Examples:**
* A 1024×768 image would consume: (1024 × 768) / 750 = 1,048 tokens
* A 512×512 image would consume: (512 × 512) / 750 = 349 tokens
These image tokens are then priced according to the input token pricing of the model you're using (e.g., `sonar-pro`, `sonar`, etc.). The image tokens are added to your total token count for the request alongside any text tokens.
To optimize costs, resize images to the minimum resolution needed for your use case while maintaining adequate quality.
## Limitations
* Image and regex cannot be used together in the same request
* `sonar-deep-research` does not support image input
* Ensure provided HTTPS URLs are publicly accessible
* Base64 images have a 50MB size limit
* Supported formats: PNG, JPEG, WEBP, and GIF
# Sonar Language Filter Guide
Source: https://docs.perplexity.ai/guides/language-filter-guide
The `search_language_filter` parameter allows you to filter search results by language using ISO 639-1 language codes. Only results in the specified languages will be returned.
Language codes must be valid 2-letter ISO 639-1 codes (e.g., "en", "ru", "fr"). You can filter by up to 10 languages per request.
## Overview
The language filter for the Sonar models allows you to control which search results are returned by limiting them to specific languages. This is particularly useful when you need to:
* Generate responses based on content in specific languages
* Conduct multilingual research across multiple languages
* Focus on regional content in local languages
* Build language-specific applications or features
The `search_language_filter` parameter accepts an array of ISO 639-1 language codes and returns only results that match those languages.
To filter search results by language:
```bash theme={null}
"search_language_filter": ["en", "fr", "de"]
```
This filter will be applied in addition to any other search parameters.
## Examples
**1. Single Language Filter**
This example limits search results to English language content only.
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me about recent AI developments."}
],
search_language_filter=["en"]
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar",
messages: [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me about recent AI developments."}
],
search_language_filter: ["en"]
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me about recent AI developments."}
],
"search_language_filter": ["en"]
}' | jq
```
**2. Multiple Language Filter**
Search across multiple languages to gather diverse perspectives or multilingual content:
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are the latest renewable energy innovations in Europe?"}
],
search_language_filter=["en", "fr", "de"]
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are the latest renewable energy innovations in Europe?"}
],
search_language_filter: ["en", "fr", "de"]
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are the latest renewable energy innovations in Europe?"}
],
"search_language_filter": ["en", "fr", "de"]
}' | jq
```
**3. Regional Language Research**
Focus on content from specific regions by using their local languages:
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Search for Asian market insights in local languages
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are the technology market trends in East Asia?"}
],
search_language_filter=["zh", "ja", "ko"]
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Search for Asian market insights in local languages
const completion = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are the technology market trends in East Asia?"}
],
search_language_filter: ["zh", "ja", "ko"]
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are the technology market trends in East Asia?"}
],
"search_language_filter": ["zh", "ja", "ko"]
}' | jq
```
**4. Combining with Other Filters**
Language filters work seamlessly with other search parameters for precise control:
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Combine language filter with domain and date filters
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are recent breakthroughs in quantum computing?"}
],
search_language_filter=["en", "de"],
search_domain_filter=["nature.com", "science.org", "arxiv.org"],
search_recency_filter="month"
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Combine language filter with domain and date filters
const completion = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are recent breakthroughs in quantum computing?"}
],
search_language_filter: ["en", "de"],
search_domain_filter: ["nature.com", "science.org", "arxiv.org"],
search_recency_filter: "month"
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are recent breakthroughs in quantum computing?"}
],
"search_language_filter": ["en", "de"],
"search_domain_filter": ["nature.com", "science.org", "arxiv.org"],
"search_recency_filter": "month"
}' | jq
```
## Parameter Reference
### `search_language_filter`
* **Type**: Array of strings
* **Format**: ISO 639-1 language codes (2 lowercase letters)
* **Description**: Filters search results to only include content in the specified languages
* **Optional**: Yes
* **Maximum**: 10 language codes per request
* **Example**: `"search_language_filter": ["en", "fr", "de"]`
## Common Language Codes
Here's a comprehensive list of frequently used ISO 639-1 language codes:
| Language | Code | Language | Code |
| ---------- | ---- | ---------- | ---- |
| English | `en` | Portuguese | `pt` |
| Spanish | `es` | Dutch | `nl` |
| French | `fr` | Polish | `pl` |
| German | `de` | Swedish | `sv` |
| Italian | `it` | Norwegian | `no` |
| Russian | `ru` | Danish | `da` |
| Chinese | `zh` | Finnish | `fi` |
| Japanese | `ja` | Czech | `cs` |
| Korean | `ko` | Hungarian | `hu` |
| Arabic | `ar` | Greek | `el` |
| Hindi | `hi` | Turkish | `tr` |
| Bengali | `bn` | Hebrew | `he` |
| Indonesian | `id` | Thai | `th` |
| Vietnamese | `vi` | Ukrainian | `uk` |
For a complete list of ISO 639-1 language codes, see the [ISO 639-1 standard](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
## Best Practices
### Language Code Validation
* **Use Valid Codes**: Always use valid 2-letter ISO 639-1 codes. Invalid codes will result in an API error.
* **Lowercase Only**: Language codes must be lowercase (e.g., "en" not "EN").
* **Client-Side Validation**: Validate language codes on the client side using a regex pattern:
```python Python theme={null}
import re
def validate_language_code(code):
pattern = r'^[a-z]{2}$'
return bool(re.match(pattern, code))
def validate_language_filters(codes):
if len(codes) > 10:
raise ValueError("Maximum 10 language codes allowed")
for code in codes:
if not validate_language_code(code):
raise ValueError(f"Invalid language code: {code}")
return True
# Usage
try:
codes = ["en", "fr", "de"]
validate_language_filters(codes)
response = client.chat.completions.create(
model="sonar",
messages=[{"role": "user", "content": "technology news"}],
search_language_filter=codes
)
except ValueError as e:
print(f"Validation error: {e}")
```
```typescript TypeScript theme={null}
function validateLanguageCode(code: string): boolean {
const pattern = /^[a-z]{2}$/;
return pattern.test(code);
}
function validateLanguageFilters(codes: string[]): void {
if (codes.length > 10) {
throw new Error("Maximum 10 language codes allowed");
}
for (const code of codes) {
if (!validateLanguageCode(code)) {
throw new Error(`Invalid language code: ${code}`);
}
}
}
// Usage
try {
const codes = ["en", "fr", "de"];
validateLanguageFilters(codes);
const response = await client.chat.completions.create({
model: "sonar",
messages: [{role: "user", content: "technology news"}],
searchLanguageFilter: codes
});
} catch (error) {
console.error("Validation error:", error.message);
}
```
### Strategic Language Selection
* **Be Specific**: Choose languages that are most relevant to your research or application needs.
* **Consider Your Audience**: Select languages that match your target audience's preferences.
* **Regional Relevance**: Combine language filters with geographic filters for better regional targeting.
* **Content Availability**: Some topics may have limited content in certain languages. Start broad and narrow down as needed.
### Performance Considerations
* **Filter Size**: While you can specify up to 10 languages, using fewer languages may improve response times.
* **Result Quality**: More languages mean a broader search scope, which can dilute result relevance. Be strategic about which languages to include.
* **Combination Effects**: Language filters combined with other restrictive filters (domain, date) may significantly reduce the number of results.
## Advanced Usage Patterns
### Multilingual Research
Conduct comprehensive research by searching across multiple languages:
```python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Research a global topic in multiple languages
languages = [
["en"], # English-speaking countries
["zh", "ja"], # East Asia
["es", "pt"], # Latin America and Iberia
["fr", "de", "it"] # Western Europe
]
results_by_region = {}
for lang_group in languages:
completion = client.chat.completions.create(
model="sonar",
messages=[
{"role": "user", "content": "sustainable development goals progress"}
],
search_language_filter=lang_group
)
results_by_region[", ".join(lang_group)] = completion
# Analyze results by language/region
for region, result in results_by_region.items():
print(f"Results in {region}:")
print(result.choices[0].message.content[:200])
print("---")
```
### Content Localization Research
Find examples and references in target languages for localization projects:
```python theme={null}
# Generate insights from target market languages
target_languages = ["ja", "ko", "zh"] # Asian markets
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "user", "content": "smartphone reviews 2024"}
],
search_language_filter=target_languages,
search_recency_filter="month"
)
```
### Academic Research Across Languages
Access scholarly content in different languages:
```python theme={null}
# Search for research papers in multiple languages
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "user", "content": "quantum computing algorithms"}
],
search_language_filter=["en", "de", "fr", "ru"],
search_domain_filter=["arxiv.org", "nature.com", "science.org"]
)
```
### News Monitoring by Language
Track news stories across different language regions:
```python theme={null}
# Monitor breaking news in different languages
news_queries = {
"English": ["en"],
"Chinese": ["zh"],
"Spanish": ["es"],
"Arabic": ["ar"]
}
for region, langs in news_queries.items():
completion = client.chat.completions.create(
model="sonar",
messages=[
{"role": "user", "content": "breaking news technology"}
],
search_language_filter=langs,
search_recency_filter="day"
)
print(f"{region} News:")
print(completion.choices[0].message.content[:200])
print("---")
```
## Error Handling
When using language filters, implement proper error handling for validation issues:
```python Python theme={null}
from perplexity import Perplexity, BadRequestError
client = Perplexity()
def safe_language_chat(query, languages):
"""
Generate a response with language-filtered search and error handling.
"""
try:
# Validate language codes
if not isinstance(languages, list):
raise ValueError("Languages must be provided as a list")
if len(languages) > 10:
raise ValueError("Maximum 10 language codes allowed")
# Validate each code format
for lang in languages:
if not isinstance(lang, str) or len(lang) != 2 or not lang.islower():
raise ValueError(f"Invalid language code format: {lang}")
# Perform chat completion
completion = client.chat.completions.create(
model="sonar",
messages=[{"role": "user", "content": query}],
search_language_filter=languages
)
return completion
except ValueError as e:
print(f"Validation error: {e}")
return None
except BadRequestError as e:
print(f"API error: {e.message}")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
# Usage
result = safe_language_chat(
"artificial intelligence trends",
["en", "fr", "de"]
)
if result:
print(result.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
async function safeLanguageChat(
query: string,
languages: string[]
): Promise {
try {
// Validate language codes
if (!Array.isArray(languages)) {
throw new Error("Languages must be provided as an array");
}
if (languages.length > 10) {
throw new Error("Maximum 10 language codes allowed");
}
// Validate each code format
for (const lang of languages) {
if (typeof lang !== 'string' ||
lang.length !== 2 ||
lang !== lang.toLowerCase()) {
throw new Error(`Invalid language code format: ${lang}`);
}
}
// Perform chat completion
const completion = await client.chat.completions.create({
model: "sonar",
messages: [{role: "user", content: query}],
searchLanguageFilter: languages
});
return completion;
} catch (error) {
if (error instanceof Perplexity.BadRequestError) {
console.error("API error:", error.message);
} else if (error instanceof Error) {
console.error("Error:", error.message);
}
return null;
}
}
// Usage
const result = await safeLanguageChat(
"artificial intelligence trends",
["en", "fr", "de"]
);
if (result) {
console.log(result.choices[0].message.content);
}
```
For best results, combine language filtering with other filters like `search_domain_filter` or `search_recency_filter` to narrow down your search to highly relevant, timely content in your target languages.
# Perplexity MCP Server
Source: https://docs.perplexity.ai/guides/mcp-server
Connect AI assistants to Perplexity's search and reasoning capabilities using the Model Context Protocol (MCP).
## Overview
The Perplexity MCP Server enables AI assistants to access Perplexity's powerful search and reasoning capabilities directly within their workflows. Using the Model Context Protocol (MCP), you can integrate real-time web search, conversational AI, and advanced reasoning into any MCP-compatible client.
The **Model Context Protocol (MCP)** is an open standard that connects AI assistants with external data sources and tools. Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/introduction).
## Installation
### One-Click Install
Get started instantly with these one-click installers:
}
href="https://cursor.com/en/install-mcp?name=perplexity&config=eyJ0eXBlIjoic3RkaW8iLCJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBwZXJwbGV4aXR5LWFpL21jcC1zZXJ2ZXIiXX0="
>
Automatically configure the Perplexity MCP server in Cursor with one click.
}
href="https://vscode.dev/redirect/mcp/install?name=perplexity&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40perplexity-ai%2Fmcp-server%22%5D%7D"
>
Automatically configure the Perplexity MCP server in VS Code with one click.
### Manual Setup
Navigate to the API Portal and generate a new key.
Add the MCP server to your client configuration:
**Option 1: Plugin Install (Recommended)**
The easiest way to get started:
```bash theme={null}
# Add the Perplexity marketplace
/plugin marketplace add perplexityai/modelcontextprotocol
# Install the plugin
/plugin install perplexity
# Set your API key
export PERPLEXITY_API_KEY="your_key_here"
```
**Option 2: Manual Configuration**
Add to your `claude.json`:
```json theme={null}
{
"mcpServers": {
"perplexity": {
"type": "stdio",
"command": "npx",
"args": ["-y", "perplexity-mcp"],
"env": {
"PERPLEXITY_API_KEY": "your_key_here"
}
}
}
}
```
Add to your `mcp.json`:
```json theme={null}
{
"mcpServers": {
"perplexity": {
"command": "npx",
"args": ["-y", "@perplexity-ai/mcp-server"],
"env": {
"PERPLEXITY_API_KEY": "your_key_here"
}
}
}
}
```
Add to your `claude_desktop_config.json`:
```json theme={null}
{
"mcpServers": {
"perplexity": {
"command": "npx",
"args": ["-y", "@perplexity-ai/mcp-server"],
"env": {
"PERPLEXITY_API_KEY": "your_key_here"
}
}
}
}
```
For any MCP-compatible client:
```bash theme={null}
npx @perplexity-ai/mcp-server
```
Set environment variable: `PERPLEXITY_API_KEY=your_key_here`
Restart your MCP client and start using Perplexity's tools in your AI workflows.
## Available Tools
Direct web search using the Perplexity Search API. Returns ranked search results with titles, URLs, snippets, and metadata.
**Best for:** Finding current information, news, facts, or specific web content.
General-purpose conversational AI with real-time web search using the `sonar-pro` model.
**Best for:** Quick questions, everyday searches, and conversational queries that benefit from web context.
Deep, comprehensive research using the `sonar-deep-research` model. Provides thorough analysis with citations.
**Best for:** Complex topics requiring detailed investigation, comprehensive reports, and in-depth analysis.
Advanced reasoning and problem-solving using the `sonar-reasoning-pro` model.
**Best for:** Logical problems, complex analysis, decision-making, and tasks requiring step-by-step reasoning.
For detailed setup instructions, troubleshooting, and proxy configuration, visit our [GitHub repository](https://github.com/perplexityai/modelcontextprotocol).
# Quickstart
Source: https://docs.perplexity.ai/guides/perplexity-sdk
Learn how to use the official Perplexity SDKs for Python and TypeScript/JavaScript to access the Perplexity APIs with type safety and async support.
## Overview
The official Perplexity SDKs provide convenient access to the Perplexity APIs from Python 3.8+ and Node.js applications. Both SDKs include type definitions for all request parameters and response fields, with both synchronous and asynchronous clients.
## Available APIs
AI responses with web-grounded knowledge, conversation context, and streaming support.
Ranked web search results with filtering, multi-query support, and domain controls.
## Installation
Install the SDK for your preferred language:
```bash Python theme={null}
pip install perplexityai
```
```bash TypeScript/JavaScript theme={null}
npm install @perplexity-ai/perplexity_ai
```
## Authentication
Navigate to the **API Keys** tab in the API Portal and generate a new key.
After generating the key, set it as an environment variable in your terminal:
```bash theme={null}
setx PERPLEXITY_API_KEY "your_api_key_here"
```
```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```
### Using Environment Variables
You can use the environment variable directly:
```python Python theme={null}
import os
from perplexity import Perplexity
client = Perplexity() # Automatically uses PERPLEXITY_API_KEY
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity({
apiKey: process.env['PERPLEXITY_API_KEY'], // This is the default and can be omitted
});
```
Or use [python-dotenv](https://pypi.org/project/python-dotenv/) (Python) or [dotenv](https://www.npmjs.com/package/dotenv) (Node.js) to load the environment variable from a `.env` file:
```python Python theme={null}
import os
from dotenv import load_dotenv
from perplexity import Perplexity
load_dotenv()
client = Perplexity() # Uses PERPLEXITY_API_KEY from .env file
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import dotenv from 'dotenv';
dotenv.config();
const client = new Perplexity(); // Uses PERPLEXITY_API_KEY from .env file
```
Now you're ready to start using the Perplexity APIs! Choose your API below for step-by-step usage guides.
Get started with AI responses
Get started with web search
## Resources
Install from PyPI with pip
Install from npm registry
# Best Practices
Source: https://docs.perplexity.ai/guides/perplexity-sdk-best-practices
Learn best practices for using the Perplexity SDKs in production, including environment variables, rate limiting, security, and efficient request patterns.
## Overview
This guide covers essential best practices for using the Perplexity SDKs in production environments. Following these practices will help you build robust, secure, and efficient applications.
## Security Best Practices
### Environment Variables
Always store API keys securely using environment variables:
Store API keys in environment variables, never in source code.
```python Python theme={null}
import os
from perplexity import Perplexity
# Good: Use environment variables
client = Perplexity(
api_key=os.environ.get("PERPLEXITY_API_KEY")
)
# Bad: Never hardcode API keys
# client = Perplexity(api_key="pplx-abc123...") # DON'T DO THIS
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Good: Use environment variables
const client = new Perplexity({
apiKey: process.env.PERPLEXITY_API_KEY
});
// Bad: Never hardcode API keys
// const client = new Perplexity({
// apiKey: "pplx-abc123..." // DON'T DO THIS
// });
```
Never commit API keys to version control. Use .env files locally and secure environment variable management in production.
Create a `.env` file for local development (add it to .gitignore).
```bash .env theme={null}
PERPLEXITY_API_KEY=your_api_key_here
PERPLEXITY_MAX_RETRIES=3
PERPLEXITY_TIMEOUT=30000
```
```python Python theme={null}
from dotenv import load_dotenv
import os
from perplexity import Perplexity
# Load environment variables from .env file
load_dotenv()
client = Perplexity(
api_key=os.getenv("PERPLEXITY_API_KEY"),
max_retries=int(os.getenv("PERPLEXITY_MAX_RETRIES", "3"))
)
```
```typescript TypeScript/JavaScript theme={null}
import dotenv from 'dotenv';
import Perplexity from '@perplexity-ai/perplexity_ai';
// Load environment variables from .env file
dotenv.config();
const client = new Perplexity({
apiKey: process.env.PERPLEXITY_API_KEY,
maxRetries: parseInt(process.env.PERPLEXITY_MAX_RETRIES || '3')
});
```
Check for required environment variables at startup.
```python Python theme={null}
import os
import sys
from perplexity import Perplexity
def create_client():
api_key = os.getenv("PERPLEXITY_API_KEY")
if not api_key:
print("Error: PERPLEXITY_API_KEY environment variable is required")
sys.exit(1)
return Perplexity(api_key=api_key)
client = create_client()
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
function createClient(): Perplexity {
const apiKey = process.env.PERPLEXITY_API_KEY;
if (!apiKey) {
console.error("Error: PERPLEXITY_API_KEY environment variable is required");
process.exit(1);
}
return new Perplexity({ apiKey });
}
const client = createClient();
```
### API Key Rotation
Implement secure API key rotation:
```python Python theme={null}
import os
import logging
from perplexity import Perplexity
from typing import Optional
class SecurePerplexityClient:
def __init__(self, primary_key: Optional[str] = None, fallback_key: Optional[str] = None):
self.primary_key = primary_key or os.getenv("PERPLEXITY_API_KEY")
self.fallback_key = fallback_key or os.getenv("PERPLEXITY_API_KEY_FALLBACK")
self.current_client = Perplexity(api_key=self.primary_key)
self.logger = logging.getLogger(__name__)
def _switch_to_fallback(self):
"""Switch to fallback API key if available"""
if self.fallback_key:
self.logger.warning("Switching to fallback API key")
self.current_client = Perplexity(api_key=self.fallback_key)
return True
return False
def search(self, query: str, **kwargs):
try:
return self.current_client.search.create(query=query, **kwargs)
except Exception as e:
if "authentication" in str(e).lower() and self._switch_to_fallback():
return self.current_client.search.create(query=query, **kwargs)
raise e
# Usage
client = SecurePerplexityClient()
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
class SecurePerplexityClient {
private primaryKey: string;
private fallbackKey?: string;
private currentClient: Perplexity;
constructor(primaryKey?: string, fallbackKey?: string) {
this.primaryKey = primaryKey || process.env.PERPLEXITY_API_KEY!;
this.fallbackKey = fallbackKey || process.env.PERPLEXITY_API_KEY_FALLBACK;
this.currentClient = new Perplexity({ apiKey: this.primaryKey });
}
private switchToFallback(): boolean {
if (this.fallbackKey) {
console.warn("Switching to fallback API key");
this.currentClient = new Perplexity({ apiKey: this.fallbackKey });
return true;
}
return false;
}
async search(query: string, options?: any) {
try {
return await this.currentClient.search.create({ query, ...options });
} catch (error: any) {
if (error.message.toLowerCase().includes('authentication') && this.switchToFallback()) {
return await this.currentClient.search.create({ query, ...options });
}
throw error;
}
}
}
// Usage
const client = new SecurePerplexityClient();
```
## Rate Limiting and Efficiency
### Intelligent Rate Limiting
Implement exponential backoff with jitter:
```python Python theme={null}
import time
import random
import asyncio
from typing import TypeVar, Callable, Any
import perplexity
from perplexity import Perplexity
T = TypeVar('T')
class RateLimitedClient:
def __init__(self, client: Perplexity, max_retries: int = 5):
self.client = client
self.max_retries = max_retries
def _calculate_delay(self, attempt: int) -> float:
"""Calculate delay with exponential backoff and jitter"""
base_delay = 2 ** attempt
jitter = random.uniform(0.1, 0.5)
return min(base_delay + jitter, 60.0) # Cap at 60 seconds
def with_retry(self, func: Callable[[], T]) -> T:
"""Execute function with intelligent retry logic"""
last_exception = None
for attempt in range(self.max_retries):
try:
return func()
except perplexity.RateLimitError as e:
last_exception = e
if attempt < self.max_retries - 1:
delay = self._calculate_delay(attempt)
print(f"Rate limited. Retrying in {delay:.2f}s (attempt {attempt + 1})")
time.sleep(delay)
continue
raise e
except perplexity.APIConnectionError as e:
last_exception = e
if attempt < self.max_retries - 1:
delay = min(2 ** attempt, 10.0) # Shorter delay for connection errors
print(f"Connection error. Retrying in {delay:.2f}s")
time.sleep(delay)
continue
raise e
raise last_exception
def search(self, query: str, **kwargs):
return self.with_retry(
lambda: self.client.search.create(query=query, **kwargs)
)
# Usage
client = RateLimitedClient(Perplexity())
result = client.search("artificial intelligence")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
class RateLimitedClient {
private client: Perplexity;
private maxRetries: number;
constructor(client: Perplexity, maxRetries: number = 5) {
this.client = client;
this.maxRetries = maxRetries;
}
private calculateDelay(attempt: number): number {
const baseDelay = 2 ** attempt * 1000; // Convert to milliseconds
const jitter = Math.random() * 500; // 0-500ms jitter
return Math.min(baseDelay + jitter, 60000); // Cap at 60 seconds
}
async withRetry(func: () => Promise): Promise {
let lastError: any;
for (let attempt = 0; attempt < this.maxRetries; attempt++) {
try {
return await func();
} catch (error: any) {
lastError = error;
if (error.constructor.name === 'RateLimitError') {
if (attempt < this.maxRetries - 1) {
const delay = this.calculateDelay(attempt);
console.log(`Rate limited. Retrying in ${delay}ms (attempt ${attempt + 1})`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
} else if (error.constructor.name === 'APIConnectionError') {
if (attempt < this.maxRetries - 1) {
const delay = Math.min(2 ** attempt * 1000, 10000);
console.log(`Connection error. Retrying in ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
}
throw error;
}
}
throw lastError;
}
async search(query: string, options?: any) {
return this.withRetry(() =>
this.client.search.create({ query, ...options })
);
}
}
// Usage
const client = new RateLimitedClient(new Perplexity());
const result = await client.search("artificial intelligence");
```
### Request Batching
Efficiently batch multiple requests:
```python Python theme={null}
import asyncio
from typing import List, TypeVar, Generic
from perplexity import AsyncPerplexity, DefaultAioHttpClient
T = TypeVar('T')
class BatchProcessor(Generic[T]):
def __init__(self, batch_size: int = 5, delay_between_batches: float = 1.0):
self.batch_size = batch_size
self.delay_between_batches = delay_between_batches
async def process_batch(
self,
items: List[str],
process_func: Callable[[str], Awaitable[T]]
) -> List[T]:
"""Process items in batches with rate limiting"""
results = []
for i in range(0, len(items), self.batch_size):
batch = items[i:i + self.batch_size]
# Process batch concurrently
tasks = [process_func(item) for item in batch]
batch_results = await asyncio.gather(*tasks, return_exceptions=True)
# Filter out exceptions and collect results
for result in batch_results:
if not isinstance(result, Exception):
results.append(result)
# Delay between batches
if i + self.batch_size < len(items):
await asyncio.sleep(self.delay_between_batches)
return results
# Usage
async def main():
processor = BatchProcessor(batch_size=3, delay_between_batches=0.5)
async with AsyncPerplexity(
http_client=DefaultAioHttpClient()
) as client:
async def search_query(query: str):
return await client.search.create(query=query)
queries = ["AI", "ML", "DL", "NLP", "CV"]
results = await processor.process_batch(queries, search_query)
print(f"Processed {len(results)} successful queries")
asyncio.run(main())
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
class BatchProcessor {
constructor(
private batchSize: number = 5,
private delayBetweenBatches: number = 1000
) {}
async processBatch(
items: T[],
processFunc: (item: T) => Promise
): Promise {
const results: R[] = [];
for (let i = 0; i < items.length; i += this.batchSize) {
const batch = items.slice(i, i + this.batchSize);
// Process batch concurrently
const tasks = batch.map(item =>
processFunc(item).catch(error => error)
);
const batchResults = await Promise.all(tasks);
// Filter out exceptions and collect results
for (const result of batchResults) {
if (!(result instanceof Error)) {
results.push(result);
}
}
// Delay between batches
if (i + this.batchSize < items.length) {
await new Promise(resolve =>
setTimeout(resolve, this.delayBetweenBatches)
);
}
}
return results;
}
}
// Usage
async function main() {
const processor = new BatchProcessor(3, 500);
const client = new Perplexity();
const searchQuery = (query: string) =>
client.search.create({ query });
const queries = ["AI", "ML", "DL", "NLP", "CV"];
const results = await processor.processBatch(queries, searchQuery);
console.log(`Processed ${results.length} successful queries`);
}
main();
```
## Production Configuration
### Configuration Management
Use environment-based configuration for different deployment stages:
```python Python theme={null}
import os
from dataclasses import dataclass
from typing import Optional
import httpx
from perplexity import Perplexity, DefaultHttpxClient
@dataclass
class PerplexityConfig:
api_key: str
max_retries: int = 3
timeout_seconds: float = 30.0
max_connections: int = 100
max_keepalive: int = 20
environment: str = "production"
@classmethod
def from_env(cls) -> "PerplexityConfig":
"""Load configuration from environment variables"""
api_key = os.getenv("PERPLEXITY_API_KEY")
if not api_key:
raise ValueError("PERPLEXITY_API_KEY environment variable is required")
return cls(
api_key=api_key,
max_retries=int(os.getenv("PERPLEXITY_MAX_RETRIES", "3")),
timeout_seconds=float(os.getenv("PERPLEXITY_TIMEOUT", "30.0")),
max_connections=int(os.getenv("PERPLEXITY_MAX_CONNECTIONS", "100")),
max_keepalive=int(os.getenv("PERPLEXITY_MAX_KEEPALIVE", "20")),
environment=os.getenv("ENVIRONMENT", "production")
)
def create_client(self) -> Perplexity:
"""Create optimized client based on configuration"""
timeout = httpx.Timeout(
connect=5.0,
read=self.timeout_seconds,
write=10.0,
pool=10.0
)
limits = httpx.Limits(
max_keepalive_connections=self.max_keepalive,
max_connections=self.max_connections,
keepalive_expiry=60.0 if self.environment == "production" else 30.0
)
return Perplexity(
api_key=self.api_key,
max_retries=self.max_retries,
timeout=timeout,
http_client=DefaultHttpxClient(limits=limits)
)
# Usage
config = PerplexityConfig.from_env()
client = config.create_client()
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import https from 'https';
interface PerplexityConfig {
apiKey: string;
maxRetries: number;
timeoutMs: number;
maxConnections: number;
maxKeepalive: number;
environment: string;
}
class ConfigManager {
static fromEnv(): PerplexityConfig {
const apiKey = process.env.PERPLEXITY_API_KEY;
if (!apiKey) {
throw new Error("PERPLEXITY_API_KEY environment variable is required");
}
return {
apiKey,
maxRetries: parseInt(process.env.PERPLEXITY_MAX_RETRIES || '3'),
timeoutMs: parseInt(process.env.PERPLEXITY_TIMEOUT || '30000'),
maxConnections: parseInt(process.env.PERPLEXITY_MAX_CONNECTIONS || '100'),
maxKeepalive: parseInt(process.env.PERPLEXITY_MAX_KEEPALIVE || '20'),
environment: process.env.NODE_ENV || 'production'
};
}
static createClient(config: PerplexityConfig): Perplexity {
const httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: config.environment === 'production' ? 60000 : 30000,
maxSockets: config.maxConnections,
maxFreeSockets: config.maxKeepalive,
timeout: config.timeoutMs
});
return new Perplexity({
apiKey: config.apiKey,
maxRetries: config.maxRetries,
timeout: config.timeoutMs,
httpAgent: httpsAgent
});
}
}
// Usage
const config = ConfigManager.fromEnv();
const client = ConfigManager.createClient(config);
```
### Monitoring and Logging
Implement comprehensive monitoring:
```python Python theme={null}
import logging
import time
import functools
from typing import Any, Callable
from perplexity import Perplexity
import perplexity
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class MonitoredPerplexityClient:
def __init__(self, client: Perplexity):
self.client = client
self.request_count = 0
self.error_count = 0
self.total_response_time = 0.0
def _log_request(self, method: str, **kwargs):
"""Log request details"""
self.request_count += 1
logger.info(f"Making {method} request #{self.request_count}")
logger.debug(f"Request parameters: {kwargs}")
def _log_response(self, method: str, duration: float, success: bool = True):
"""Log response details"""
self.total_response_time += duration
avg_response_time = self.total_response_time / self.request_count
if success:
logger.info(f"{method} completed in {duration:.2f}s (avg: {avg_response_time:.2f}s)")
else:
self.error_count += 1
logger.error(f"{method} failed after {duration:.2f}s (errors: {self.error_count})")
def search(self, query: str, **kwargs):
self._log_request("search", query=query, **kwargs)
start_time = time.time()
try:
result = self.client.search.create(query=query, **kwargs)
duration = time.time() - start_time
self._log_response("search", duration, success=True)
return result
except Exception as e:
duration = time.time() - start_time
self._log_response("search", duration, success=False)
logger.error(f"Search error: {type(e).__name__}: {e}")
raise
def get_stats(self):
"""Get client statistics"""
return {
"total_requests": self.request_count,
"error_count": self.error_count,
"success_rate": (self.request_count - self.error_count) / max(self.request_count, 1),
"avg_response_time": self.total_response_time / max(self.request_count, 1)
}
# Usage
client = MonitoredPerplexityClient(Perplexity())
result = client.search("machine learning")
print(client.get_stats())
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
interface ClientStats {
totalRequests: number;
errorCount: number;
successRate: number;
avgResponseTime: number;
}
class MonitoredPerplexityClient {
private client: Perplexity;
private requestCount: number = 0;
private errorCount: number = 0;
private totalResponseTime: number = 0;
constructor(client: Perplexity) {
this.client = client;
}
private logRequest(method: string, params: any): void {
this.requestCount++;
console.log(`Making ${method} request #${this.requestCount}`);
console.debug(`Request parameters:`, params);
}
private logResponse(method: string, duration: number, success: boolean = true): void {
this.totalResponseTime += duration;
const avgResponseTime = this.totalResponseTime / this.requestCount;
if (success) {
console.log(`${method} completed in ${duration.toFixed(2)}ms (avg: ${avgResponseTime.toFixed(2)}ms)`);
} else {
this.errorCount++;
console.error(`${method} failed after ${duration.toFixed(2)}ms (errors: ${this.errorCount})`);
}
}
async search(query: string, options?: any) {
this.logRequest("search", { query, ...options });
const startTime = performance.now();
try {
const result = await this.client.search.create({ query, ...options });
const duration = performance.now() - startTime;
this.logResponse("search", duration, true);
return result;
} catch (error) {
const duration = performance.now() - startTime;
this.logResponse("search", duration, false);
console.error(`Search error: ${error}`);
throw error;
}
}
getStats(): ClientStats {
return {
totalRequests: this.requestCount,
errorCount: this.errorCount,
successRate: (this.requestCount - this.errorCount) / Math.max(this.requestCount, 1),
avgResponseTime: this.totalResponseTime / Math.max(this.requestCount, 1)
};
}
}
// Usage
const client = new MonitoredPerplexityClient(new Perplexity());
const result = await client.search("machine learning");
console.log(client.getStats());
```
## Error Handling Best Practices
### Graceful Degradation
Implement fallback strategies for different error types:
```python Python theme={null}
from typing import Optional, Dict, Any
import perplexity
from perplexity import Perplexity
class ResilientPerplexityClient:
def __init__(self, client: Perplexity):
self.client = client
self.circuit_breaker_threshold = 5
self.circuit_breaker_count = 0
self.circuit_breaker_open = False
def _should_circuit_break(self) -> bool:
"""Check if circuit breaker should be triggered"""
return self.circuit_breaker_count >= self.circuit_breaker_threshold
def _record_failure(self):
"""Record a failure for circuit breaker"""
self.circuit_breaker_count += 1
if self._should_circuit_break():
self.circuit_breaker_open = True
print("Circuit breaker activated - temporarily disabling API calls")
def _record_success(self):
"""Record a success - reset circuit breaker"""
self.circuit_breaker_count = 0
self.circuit_breaker_open = False
def search_with_fallback(
self,
query: str,
fallback_response: Optional[Dict[str, Any]] = None
):
"""Search with graceful degradation"""
if self.circuit_breaker_open:
print("Circuit breaker open - returning fallback response")
return fallback_response or {
"query": query,
"results": [],
"status": "service_unavailable"
}
try:
result = self.client.search.create(query=query)
self._record_success()
return result
except perplexity.RateLimitError:
print("Rate limited - implementing backoff strategy")
# Could implement intelligent backoff here
raise
except perplexity.APIConnectionError as e:
print(f"Connection error: {e}")
self._record_failure()
return fallback_response or {
"query": query,
"results": [],
"status": "connection_error"
}
except Exception as e:
print(f"Unexpected error: {e}")
self._record_failure()
return fallback_response or {
"query": query,
"results": [],
"status": "error"
}
# Usage
client = ResilientPerplexityClient(Perplexity())
result = client.search_with_fallback("machine learning")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
interface FallbackResponse {
query: string;
results: any[];
status: string;
}
class ResilientPerplexityClient {
private client: Perplexity;
private circuitBreakerThreshold: number = 5;
private circuitBreakerCount: number = 0;
private circuitBreakerOpen: boolean = false;
constructor(client: Perplexity) {
this.client = client;
}
private shouldCircuitBreak(): boolean {
return this.circuitBreakerCount >= this.circuitBreakerThreshold;
}
private recordFailure(): void {
this.circuitBreakerCount++;
if (this.shouldCircuitBreak()) {
this.circuitBreakerOpen = true;
console.log("Circuit breaker activated - temporarily disabling API calls");
}
}
private recordSuccess(): void {
this.circuitBreakerCount = 0;
this.circuitBreakerOpen = false;
}
async searchWithFallback(
query: string,
fallbackResponse?: FallbackResponse
): Promise {
if (this.circuitBreakerOpen) {
console.log("Circuit breaker open - returning fallback response");
return fallbackResponse || {
query,
results: [],
status: "service_unavailable"
};
}
try {
const result = await this.client.search.create({ query });
this.recordSuccess();
return result;
} catch (error: any) {
if (error.constructor.name === 'RateLimitError') {
console.log("Rate limited - implementing backoff strategy");
throw error;
} else if (error.constructor.name === 'APIConnectionError') {
console.log(`Connection error: ${error.message}`);
this.recordFailure();
return fallbackResponse || {
query,
results: [],
status: "connection_error"
};
} else {
console.log(`Unexpected error: ${error.message}`);
this.recordFailure();
return fallbackResponse || {
query,
results: [],
status: "error"
};
}
}
}
}
// Usage
const client = new ResilientPerplexityClient(new Perplexity());
const result = await client.searchWithFallback("machine learning");
```
## Testing Best Practices
### Unit Testing with Mocking
Create testable code with proper mocking:
```python Python theme={null}
import unittest
from unittest.mock import Mock, patch
from perplexity import Perplexity
from perplexity.types import SearchCreateResponse, SearchResult
class TestPerplexityIntegration(unittest.TestCase):
def setUp(self):
self.mock_client = Mock(spec=Perplexity)
def test_search_success(self):
# Mock successful response
mock_result = SearchResult(
title="Test Result",
url="https://example.com",
snippet="Test snippet"
)
mock_response = SearchCreateResponse(
query="test query",
results=[mock_result]
)
self.mock_client.search.create.return_value = mock_response
# Test your application logic
result = self.mock_client.search.create(query="test query")
self.assertEqual(result.query, "test query")
self.assertEqual(len(result.results), 1)
self.assertEqual(result.results[0].title, "Test Result")
@patch('perplexity.Perplexity')
def test_rate_limit_handling(self, mock_perplexity_class):
# Mock rate limit error
mock_client = Mock()
mock_perplexity_class.return_value = mock_client
mock_client.search.create.side_effect = perplexity.RateLimitError("Rate limited")
# Test your error handling logic here
with self.assertRaises(perplexity.RateLimitError):
mock_client.search.create(query="test")
if __name__ == '__main__':
unittest.main()
```
```typescript TypeScript/JavaScript theme={null}
import { jest } from '@jest/globals';
import Perplexity from '@perplexity-ai/perplexity_ai';
import type { SearchCreateResponse, SearchResult } from '@perplexity-ai/perplexity_ai';
// Mock the Perplexity client
jest.mock('@perplexity-ai/perplexity_ai');
describe('Perplexity Integration', () => {
let mockClient: jest.Mocked;
beforeEach(() => {
mockClient = new Perplexity() as jest.Mocked;
});
test('should handle successful search', async () => {
const mockResult: SearchResult = {
title: "Test Result",
url: "https://example.com",
snippet: "Test snippet"
};
const mockResponse: SearchCreateResponse = {
query: "test query",
results: [mockResult]
};
(mockClient.search.create as jest.Mock).mockResolvedValue(mockResponse);
const result = await mockClient.search.create({ query: "test query" });
expect(result.query).toBe("test query");
expect(result.results).toHaveLength(1);
expect(result.results[0].title).toBe("Test Result");
});
test('should handle rate limit errors', async () => {
const rateLimitError = new Error('Rate limited');
rateLimitError.constructor.name = 'RateLimitError';
(mockClient.search.create as jest.Mock).mockRejectedValue(rateLimitError);
await expect(mockClient.search.create({ query: "test" })).rejects.toThrow('Rate limited');
});
});
```
## Performance Best Practices Summary
Never hardcode API keys or configuration values.
Use exponential backoff with jitter for retry strategies.
Optimize HTTP client settings for your use case.
Track performance metrics and error rates.
Provide fallback responses when APIs are unavailable.
Use dependency injection and mocking for unit tests.
## Related Resources
Comprehensive error handling strategies
Async operations and optimization techniques
Production-ready configuration patterns
Leveraging types for safer code
# Configuration
Source: https://docs.perplexity.ai/guides/perplexity-sdk-configuration
Learn how to configure the Perplexity SDKs for retries, timeouts, proxies, and advanced HTTP client customization.
## Overview
The Perplexity SDKs provide extensive configuration options to customize client behavior for different environments and use cases. This guide covers retry configuration, timeout settings, and custom HTTP client setup.
## Retries and Timeouts
### Basic Retry Configuration
Configure how the SDK handles failed requests:
```python Python theme={null}
from perplexity import Perplexity
import httpx
client = Perplexity(
max_retries=3, # Default is 2
timeout=httpx.Timeout(30.0, read=10.0, write=5.0, connect=2.0)
)
# Per-request configuration
search = client.with_options(max_retries=5).search.create(
query="example"
)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity({
maxRetries: 3, // Default is 2
timeout: 30000, // 30 seconds in milliseconds
});
// Per-request configuration
const search = await client.withOptions({ maxRetries: 5 }).search.create({
query: "example"
});
```
### Advanced Timeout Configuration
Set granular timeout controls for different phases of the request:
```python Python theme={null}
import httpx
from perplexity import Perplexity
# Detailed timeout configuration
timeout_config = httpx.Timeout(
connect=5.0, # Time to establish connection
read=30.0, # Time to read response
write=10.0, # Time to send request
pool=10.0 # Time to get connection from pool
)
client = Perplexity(timeout=timeout_config)
# For long-running operations
long_timeout = httpx.Timeout(
connect=5.0,
read=120.0, # 2 minutes for complex queries
write=10.0,
pool=10.0
)
client_long = Perplexity(timeout=long_timeout)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Basic timeout (applies to entire request)
const client = new Perplexity({
timeout: 30000 // 30 seconds
});
// For long-running operations
const clientLong = new Perplexity({
timeout: 120000 // 2 minutes for complex queries
});
// Per-request timeout override
const result = await client.withOptions({
timeout: 60000 // 1 minute for this specific request
}).chat.completions.create({
model: "llama-3.1-sonar-large-128k-online",
messages: [{ role: "user", content: "Complex research query..." }]
});
```
## Custom HTTP Client
### Proxy Configuration
Configure the SDK to work with corporate proxies:
```python Python theme={null}
import httpx
from perplexity import Perplexity, DefaultHttpxClient
# HTTP Proxy
client = Perplexity(
http_client=DefaultHttpxClient(
proxy="http://proxy.company.com:8080"
)
)
# HTTPS Proxy with authentication
client_auth = Perplexity(
http_client=DefaultHttpxClient(
proxy="http://username:password@proxy.company.com:8080"
)
)
# SOCKS proxy
client_socks = Perplexity(
http_client=DefaultHttpxClient(
proxy="socks5://proxy.company.com:1080"
)
)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { SocksProxyAgent } from 'socks-proxy-agent';
// HTTP/HTTPS Proxy
const client = new Perplexity({
httpAgent: new HttpsProxyAgent('http://proxy.company.com:8080')
});
// Proxy with authentication
const clientAuth = new Perplexity({
httpAgent: new HttpsProxyAgent('http://username:password@proxy.company.com:8080')
});
// SOCKS proxy
const clientSocks = new Perplexity({
httpAgent: new SocksProxyAgent('socks5://proxy.company.com:1080')
});
```
### Custom Headers and User Agent
Add custom headers to all requests:
```python Python theme={null}
import httpx
from perplexity import Perplexity, DefaultHttpxClient
# Custom headers
headers = {
"User-Agent": "MyApp/1.0",
"X-Custom-Header": "custom-value"
}
client = Perplexity(
http_client=DefaultHttpxClient(
headers=headers
)
)
# Advanced HTTP client configuration
transport = httpx.HTTPTransport(
local_address="0.0.0.0", # Bind to specific interface
verify=True, # SSL verification
cert=None, # Client certificate
http2=True # Enable HTTP/2
)
client_advanced = Perplexity(
http_client=DefaultHttpxClient(
transport=transport,
headers=headers
)
)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Custom headers
const client = new Perplexity({
defaultHeaders: {
"User-Agent": "MyApp/1.0",
"X-Custom-Header": "custom-value"
}
});
// Advanced fetch configuration
const clientAdvanced = new Perplexity({
fetch: (url, options) => {
return fetch(url, {
...options,
headers: {
...options?.headers,
"User-Agent": "MyApp/1.0",
"X-Custom-Header": "custom-value"
}
});
}
});
```
### SSL/TLS Configuration
Configure SSL verification and certificates:
```python Python theme={null}
import httpx
import ssl
from perplexity import Perplexity, DefaultHttpxClient
# Disable SSL verification (not recommended for production)
client_no_ssl = Perplexity(
http_client=DefaultHttpxClient(
verify=False
)
)
# Custom SSL context
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
client_custom_ssl = Perplexity(
http_client=DefaultHttpxClient(
verify=ssl_context
)
)
# Client certificate authentication
client_cert = Perplexity(
http_client=DefaultHttpxClient(
cert=("client.crt", "client.key")
)
)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import https from 'https';
// Custom HTTPS agent with SSL options
const httpsAgent = new https.Agent({
rejectUnauthorized: false, // Disable SSL verification (not recommended)
keepAlive: true,
maxSockets: 50
});
const client = new Perplexity({
httpAgent: httpsAgent
});
// For Node.js environments with custom CA certificates
const httpsAgentCA = new https.Agent({
ca: [/* your CA certificates */],
cert: /* client certificate */,
key: /* client private key */
});
const clientCert = new Perplexity({
httpAgent: httpsAgentCA
});
```
## Connection Pooling
Optimize performance with connection pooling:
```python Python theme={null}
import httpx
from perplexity import Perplexity, DefaultHttpxClient
# Configure connection limits
limits = httpx.Limits(
max_keepalive_connections=20, # Keep-alive connections
max_connections=100, # Total connections
keepalive_expiry=30.0 # Keep-alive timeout
)
client = Perplexity(
http_client=DefaultHttpxClient(
limits=limits
)
)
# For high-throughput applications
high_throughput_limits = httpx.Limits(
max_keepalive_connections=100,
max_connections=500,
keepalive_expiry=60.0
)
client_high_throughput = Perplexity(
http_client=DefaultHttpxClient(
limits=high_throughput_limits
)
)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import https from 'https';
// Configure agent pool settings
const httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 30000, // 30 seconds
maxSockets: 50, // Max connections per host
maxFreeSockets: 10, // Max idle connections per host
timeout: 60000 // Socket timeout
});
const client = new Perplexity({
httpAgent: httpsAgent
});
// For high-throughput applications
const highThroughputAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 60000,
maxSockets: 200,
maxFreeSockets: 50,
timeout: 120000
});
const clientHighThroughput = new Perplexity({
httpAgent: highThroughputAgent
});
```
## Environment-Specific Configuration
### Development Configuration
Settings optimized for development and debugging:
```python Python theme={null}
import httpx
from perplexity import Perplexity, DefaultHttpxClient
# Development configuration
dev_client = Perplexity(
max_retries=1, # Fail fast in development
timeout=httpx.Timeout(10.0), # Short timeout
http_client=DefaultHttpxClient(
# Enable detailed logging
event_hooks={
'request': [lambda request: print(f"Request: {request.method} {request.url}")],
'response': [lambda response: print(f"Response: {response.status_code}")]
}
)
)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Development configuration
const devClient = new Perplexity({
maxRetries: 1, // Fail fast in development
timeout: 10000, // 10 second timeout
// Custom fetch with logging
fetch: (url, options) => {
console.log(`Request: ${options?.method || 'GET'} ${url}`);
return fetch(url, options).then(response => {
console.log(`Response: ${response.status}`);
return response;
});
}
});
```
### Production Configuration
Settings optimized for production environments:
```python Python theme={null}
import httpx
from perplexity import Perplexity, DefaultHttpxClient
# Production configuration
prod_limits = httpx.Limits(
max_keepalive_connections=50,
max_connections=200,
keepalive_expiry=60.0
)
prod_timeout = httpx.Timeout(
connect=5.0,
read=60.0,
write=10.0,
pool=10.0
)
prod_client = Perplexity(
max_retries=3,
timeout=prod_timeout,
http_client=DefaultHttpxClient(
limits=prod_limits,
verify=True, # Always verify SSL in production
http2=True # Enable HTTP/2 for better performance
)
)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import https from 'https';
// Production configuration
const prodAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 60000,
maxSockets: 100,
maxFreeSockets: 20,
timeout: 60000
});
const prodClient = new Perplexity({
maxRetries: 3,
timeout: 60000,
httpAgent: prodAgent
});
```
## Configuration Patterns
### Environment-Based Configuration
Use environment variables to configure the client:
```python Python theme={null}
import os
import httpx
from perplexity import Perplexity, DefaultHttpxClient
def create_client():
# Base configuration
timeout = httpx.Timeout(
connect=float(os.getenv('PERPLEXITY_CONNECT_TIMEOUT', '5.0')),
read=float(os.getenv('PERPLEXITY_READ_TIMEOUT', '30.0')),
write=float(os.getenv('PERPLEXITY_WRITE_TIMEOUT', '10.0'))
)
max_retries = int(os.getenv('PERPLEXITY_MAX_RETRIES', '3'))
# Optional proxy configuration
proxy = os.getenv('PERPLEXITY_PROXY')
http_client_kwargs = {}
if proxy:
http_client_kwargs['proxy'] = proxy
return Perplexity(
max_retries=max_retries,
timeout=timeout,
http_client=DefaultHttpxClient(**http_client_kwargs)
)
client = create_client()
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import { HttpsProxyAgent } from 'https-proxy-agent';
function createClient(): Perplexity {
const maxRetries = parseInt(process.env.PERPLEXITY_MAX_RETRIES || '3');
const timeout = parseInt(process.env.PERPLEXITY_TIMEOUT || '30000');
const config: any = {
maxRetries,
timeout
};
// Optional proxy configuration
if (process.env.PERPLEXITY_PROXY) {
config.httpAgent = new HttpsProxyAgent(process.env.PERPLEXITY_PROXY);
}
return new Perplexity(config);
}
const client = createClient();
```
### Configuration Factory
Create reusable configuration patterns:
```python Python theme={null}
import httpx
from perplexity import Perplexity, DefaultHttpxClient
class PerplexityClientFactory:
@staticmethod
def development():
return Perplexity(
max_retries=1,
timeout=httpx.Timeout(10.0)
)
@staticmethod
def production():
return Perplexity(
max_retries=3,
timeout=httpx.Timeout(connect=5.0, read=60.0, write=10.0),
http_client=DefaultHttpxClient(
limits=httpx.Limits(
max_keepalive_connections=50,
max_connections=200
)
)
)
@staticmethod
def high_throughput():
return Perplexity(
max_retries=2,
timeout=httpx.Timeout(connect=2.0, read=30.0, write=5.0),
http_client=DefaultHttpxClient(
limits=httpx.Limits(
max_keepalive_connections=100,
max_connections=500
)
)
)
# Usage
client = PerplexityClientFactory.production()
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import https from 'https';
class PerplexityClientFactory {
static development(): Perplexity {
return new Perplexity({
maxRetries: 1,
timeout: 10000
});
}
static production(): Perplexity {
const agent = new https.Agent({
keepAlive: true,
maxSockets: 100,
timeout: 60000
});
return new Perplexity({
maxRetries: 3,
timeout: 60000,
httpAgent: agent
});
}
static highThroughput(): Perplexity {
const agent = new https.Agent({
keepAlive: true,
maxSockets: 500,
maxFreeSockets: 100,
timeout: 30000
});
return new Perplexity({
maxRetries: 2,
timeout: 30000,
httpAgent: agent
});
}
}
// Usage
const client = PerplexityClientFactory.production();
```
## Related Resources
Handle timeouts and connection errors
Optimize async operations and connection pooling
# Error Handling
Source: https://docs.perplexity.ai/guides/perplexity-sdk-error-handling
Learn how to handle API errors gracefully with the Perplexity SDKs for Python and TypeScript/JavaScript.
## Overview
The Perplexity SDKs provide robust error handling with specific exception types for different error scenarios. This guide covers how to catch and handle common API errors gracefully.
## Common Error Types
The SDKs provide specific exception types for different error scenarios:
* **APIConnectionError** - Network connection issues
* **RateLimitError** - API rate limit exceeded
* **APIStatusError** - HTTP status errors (4xx, 5xx)
* **AuthenticationError** - Invalid API key or authentication issues
* **ValidationError** - Invalid request parameters
## Basic Error Handling
Handle common API errors with try-catch blocks:
```python Python theme={null}
import perplexity
from perplexity import Perplexity
client = Perplexity()
try:
search = client.search.create(query="machine learning")
print(search.results)
except perplexity.APIConnectionError as e:
print("Network connection failed")
print(e.__cause__)
except perplexity.RateLimitError as e:
print("Rate limit exceeded, please retry later")
except perplexity.APIStatusError as e:
print(f"API error: {e.status_code}")
print(e.response)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
try {
const search = await client.search.create({ query: "machine learning" });
console.log(search.results);
} catch (error) {
if (error.constructor.name === 'APIConnectionError') {
console.log("Network connection failed");
console.log(error.cause);
} else if (error.constructor.name === 'RateLimitError') {
console.log("Rate limit exceeded, please retry later");
} else if (error.constructor.name === 'APIStatusError') {
console.log(`API error: ${error.status}`);
console.log(error.response);
}
}
```
Common HTTP status codes: 400 (Bad Request), 401 (Authentication), 403 (Permission Denied), 404 (Not Found), 429 (Rate Limit), 500+ (Server Error).
## Advanced Error Handling
### Exponential Backoff for Rate Limits
Implement intelligent retry logic for rate limit errors:
```python Python theme={null}
import time
import random
import perplexity
from perplexity import Perplexity
def search_with_retry(client, query, max_retries=3):
for attempt in range(max_retries):
try:
return client.search.create(query=query)
except perplexity.RateLimitError:
if attempt == max_retries - 1:
raise # Re-raise on final attempt
# Exponential backoff with jitter
delay = (2 ** attempt) + random.uniform(0, 1)
print(f"Rate limited. Retrying in {delay:.2f} seconds...")
time.sleep(delay)
except perplexity.APIConnectionError:
if attempt == max_retries - 1:
raise
# Shorter delay for connection errors
delay = 1 + random.uniform(0, 1)
print(f"Connection error. Retrying in {delay:.2f} seconds...")
time.sleep(delay)
# Usage
client = Perplexity()
result = search_with_retry(client, "artificial intelligence")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
async function searchWithRetry(
client: Perplexity,
query: string,
maxRetries: number = 3
) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.search.create({ query });
} catch (error) {
if (attempt === maxRetries - 1) {
throw error; // Re-throw on final attempt
}
if (error.constructor.name === 'RateLimitError') {
// Exponential backoff with jitter
const delay = (2 ** attempt + Math.random()) * 1000;
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else if (error.constructor.name === 'APIConnectionError') {
// Shorter delay for connection errors
const delay = (1 + Math.random()) * 1000;
console.log(`Connection error. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error; // Don't retry other errors
}
}
}
}
// Usage
const client = new Perplexity();
const result = await searchWithRetry(client, "artificial intelligence");
```
### Error Context and Debugging
Extract detailed error information for debugging:
```python Python theme={null}
import perplexity
from perplexity import Perplexity
client = Perplexity()
try:
chat = client.chat.completions.create(
model="sonar-pro",
messages=[{"role": "user", "content": "What's the weather?"}]
)
except perplexity.APIStatusError as e:
print(f"Status Code: {e.status_code}")
print(f"Error Type: {e.type}")
print(f"Error Message: {e.message}")
# Access raw response for detailed debugging
if hasattr(e, 'response'):
print(f"Raw Response: {e.response.text}")
print(f"Request ID: {e.response.headers.get('X-Request-ID')}")
except perplexity.ValidationError as e:
print(f"Validation Error: {e}")
# Handle parameter validation errors
except Exception as e:
print(f"Unexpected error: {type(e).__name__}: {e}")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
try {
const chat = await client.chat.completions.create({
model: "sonar-pro",
messages: [{ role: "user", content: "What's the weather?" }]
});
} catch (error: any) {
if (error.constructor.name === 'APIStatusError') {
console.log(`Status Code: ${error.status}`);
console.log(`Error Type: ${error.type}`);
console.log(`Error Message: ${error.message}`);
// Access raw response for detailed debugging
if (error.response) {
console.log(`Raw Response: ${await error.response.text()}`);
console.log(`Request ID: ${error.response.headers.get('X-Request-ID')}`);
}
} else if (error.constructor.name === 'ValidationError') {
console.log(`Validation Error: ${error.message}`);
// Handle parameter validation errors
} else {
console.log(`Unexpected error: ${error.constructor.name}: ${error.message}`);
}
}
```
## Error Recovery Strategies
### Graceful Degradation
Implement fallback mechanisms when API calls fail:
```python Python theme={null}
import perplexity
from perplexity import Perplexity
def get_ai_response(query, fallback_response="I'm sorry, I'm temporarily unavailable."):
client = Perplexity()
try:
# Primary: Try online model
response = client.chat.completions.create(
model="sonar-pro",
messages=[{"role": "user", "content": query}]
)
return response.choices[0].message.content
except perplexity.RateLimitError:
try:
# Fallback: Try offline model if rate limited
response = client.chat.completions.create(
model="llama-3.1-8b-instruct",
messages=[{"role": "user", "content": query}]
)
return response.choices[0].message.content
except Exception:
return fallback_response
except perplexity.APIConnectionError:
# Network issues - return cached response or fallback
return fallback_response
except Exception as e:
print(f"Unexpected error: {e}")
return fallback_response
# Usage
response = get_ai_response("What is machine learning?")
print(response)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
async function getAIResponse(
query: string,
fallbackResponse: string = "I'm sorry, I'm temporarily unavailable."
): Promise {
const client = new Perplexity();
try {
// Primary: Try online model
const response = await client.chat.completions.create({
model: "sonar-pro",
messages: [{ role: "user", content: query }]
});
return response.choices[0].message.content || "";
} catch (error: any) {
if (error.constructor.name === 'RateLimitError') {
try {
// Fallback: Try offline model if rate limited
const response = await client.chat.completions.create({
model: "llama-3.1-8b-instruct",
messages: [{ role: "user", content: query }]
});
return response.choices[0].message.content || "";
} catch {
return fallbackResponse;
}
} else if (error.constructor.name === 'APIConnectionError') {
// Network issues - return cached response or fallback
return fallbackResponse;
} else {
console.log(`Unexpected error: ${error.message}`);
return fallbackResponse;
}
}
}
// Usage
const response = await getAIResponse("What is machine learning?");
console.log(response);
```
## Best Practices
Rate limiting is common with API usage. Always implement retry logic with exponential backoff.
Don't implement aggressive retry loops without delays - this can worsen rate limiting.
Include proper logging to track error patterns and API health.
```python Python theme={null}
import logging
import perplexity
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
try:
result = client.search.create(query="example")
except perplexity.APIStatusError as e:
logger.error(f"API Error {e.status_code}: {e.message}",
extra={'request_id': e.response.headers.get('X-Request-ID')})
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
try {
const result = await client.search.create({ query: "example" });
} catch (error: any) {
console.error(`API Error ${error.status}: ${error.message}`, {
requestId: error.response?.headers.get('X-Request-ID')
});
}
```
Configure timeouts to prevent hanging requests.
```python Python theme={null}
import httpx
from perplexity import Perplexity
client = Perplexity(
timeout=httpx.Timeout(connect=5.0, read=30.0, write=5.0, pool=10.0)
)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity({
timeout: 30000 // 30 seconds
});
```
Check for invalid API keys and provide helpful error messages.
```python Python theme={null}
try:
result = client.search.create(query="test")
except perplexity.AuthenticationError:
print("Invalid API key. Please check your PERPLEXITY_API_KEY environment variable.")
```
```typescript TypeScript/JavaScript theme={null}
try {
const result = await client.search.create({ query: "test" });
} catch (error: any) {
if (error.constructor.name === 'AuthenticationError') {
console.log("Invalid API key. Please check your PERPLEXITY_API_KEY environment variable.");
}
}
```
## Related Resources
Configure timeouts and retries
Environment variables and rate limiting
# Performance Optimization
Source: https://docs.perplexity.ai/guides/perplexity-sdk-performance
Learn how to optimize the Perplexity SDKs for high-throughput applications with async support, connection pooling, and raw response access.
## Overview
The Perplexity SDKs provide several features to optimize performance for high-throughput applications. This guide covers async operations, connection pooling, raw response access, and other performance optimization techniques.
## Async Support
### Basic Async Usage
For applications that need to handle multiple requests concurrently:
```bash Python Installation theme={null}
pip install perplexityai[aiohttp]
```
```bash TypeScript/JavaScript Installation theme={null}
npm install @perplexity-ai/perplexity_ai
# Async support is built-in with TypeScript/JavaScript
```
```python Python theme={null}
import asyncio
from perplexity import AsyncPerplexity, DefaultAioHttpClient
async def main():
async with AsyncPerplexity(
http_client=DefaultAioHttpClient()
) as client:
# Single async request
search = await client.search.create(query="machine learning")
print(search.results)
asyncio.run(main())
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
async function main() {
const client = new Perplexity();
// Async is built-in for TypeScript/JavaScript
const search = await client.search.create({ query: "machine learning" });
console.log(search.results);
}
main();
```
### Concurrent Requests
Process multiple requests simultaneously for better throughput:
```python Python theme={null}
import asyncio
from perplexity import AsyncPerplexity, DefaultAioHttpClient
async def concurrent_searches():
async with AsyncPerplexity(
http_client=DefaultAioHttpClient()
) as client:
# Concurrent requests
queries = ["AI", "machine learning", "deep learning", "neural networks"]
tasks = [
client.search.create(query=query)
for query in queries
]
results = await asyncio.gather(*tasks)
for i, result in enumerate(results):
print(f"Query '{queries[i]}': {len(result.results)} results")
asyncio.run(concurrent_searches())
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
async function concurrentSearches() {
const client = new Perplexity();
// Concurrent requests
const queries = ["AI", "machine learning", "deep learning", "neural networks"];
const tasks = queries.map(query =>
client.search.create({ query })
);
const results = await Promise.all(tasks);
results.forEach((result, i) => {
console.log(`Query '${queries[i]}': ${result.results.length} results`);
});
}
concurrentSearches();
```
### Batch Processing with Rate Limiting
Process large numbers of requests while respecting rate limits:
```python Python theme={null}
import asyncio
from perplexity import AsyncPerplexity, DefaultAioHttpClient
async def batch_process_with_limit(queries, batch_size=5, delay=1.0):
async with AsyncPerplexity(
http_client=DefaultAioHttpClient()
) as client:
results = []
for i in range(0, len(queries), batch_size):
batch = queries[i:i + batch_size]
# Process batch concurrently
tasks = [
client.search.create(query=query)
for query in batch
]
batch_results = await asyncio.gather(*tasks, return_exceptions=True)
results.extend(batch_results)
# Delay between batches to respect rate limits
if i + batch_size < len(queries):
await asyncio.sleep(delay)
return results
# Usage
queries = [f"query {i}" for i in range(20)]
results = asyncio.run(batch_process_with_limit(queries))
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
async function batchProcessWithLimit(
queries: string[],
batchSize: number = 5,
delay: number = 1000
) {
const client = new Perplexity();
const results = [];
for (let i = 0; i < queries.length; i += batchSize) {
const batch = queries.slice(i, i + batchSize);
// Process batch concurrently
const tasks = batch.map(query =>
client.search.create({ query }).catch(error => error)
);
const batchResults = await Promise.all(tasks);
results.push(...batchResults);
// Delay between batches to respect rate limits
if (i + batchSize < queries.length) {
await new Promise(resolve => setTimeout(resolve, delay));
}
}
return results;
}
// Usage
const queries = Array.from({ length: 20 }, (_, i) => `query ${i}`);
const results = await batchProcessWithLimit(queries);
```
## Raw Response Access
Access headers, status codes, and raw response data for advanced use cases:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Get raw response with headers
response = client.search.with_raw_response.create(
query="machine learning"
)
print(f"Status Code: {response.status_code}")
print(f"Request ID: {response.headers.get('X-Request-ID')}")
print(f"Rate Limit Remaining: {response.headers.get('X-RateLimit-Remaining')}")
print(f"Rate Limit Reset: {response.headers.get('X-RateLimit-Reset')}")
# Parse the actual search results
search = response.parse()
print(f"Found {len(search.results)} results")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Get raw response with headers
const response = await client.search.withRawResponse.create({
query: "machine learning"
});
console.log(`Status Code: ${response.response.status}`);
console.log(`Request ID: ${response.response.headers.get('X-Request-ID')}`);
console.log(`Rate Limit Remaining: ${response.response.headers.get('X-RateLimit-Remaining')}`);
console.log(`Rate Limit Reset: ${response.response.headers.get('X-RateLimit-Reset')}`);
// Parse the actual search results
const search = response.parse();
console.log(`Found ${search.results.length} results`);
```
### Response Streaming
For chat completions, use streaming to get partial results as they arrive:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Stream chat completion responses
stream = client.chat.completions.create(
model="llama-3.1-sonar-large-128k-online",
messages=[{"role": "user", "content": "Explain quantum computing"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Stream chat completion responses
const stream = await client.chat.completions.create({
model: "llama-3.1-sonar-large-128k-online",
messages: [{ role: "user", content: "Explain quantum computing" }],
stream: true
});
for await (const chunk of stream) {
if (chunk.choices[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
```
## Connection Pooling
### Optimized Connection Settings
Configure connection pooling for better performance:
```python Python theme={null}
import httpx
from perplexity import Perplexity, DefaultHttpxClient, AsyncPerplexity, DefaultAioHttpClient
# Sync client with optimized connection pooling
limits = httpx.Limits(
max_keepalive_connections=50, # Keep connections alive
max_connections=100, # Total connection pool size
keepalive_expiry=30.0 # Keep-alive timeout
)
sync_client = Perplexity(
http_client=DefaultHttpxClient(limits=limits)
)
# Async client with optimized connection pooling
async_limits = httpx.Limits(
max_keepalive_connections=100,
max_connections=200,
keepalive_expiry=60.0
)
async def create_async_client():
return AsyncPerplexity(
http_client=DefaultAioHttpClient(limits=async_limits)
)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
import https from 'https';
// Optimized HTTPS agent for connection pooling
const optimizedAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 30000, // 30 seconds
maxSockets: 50, // Max connections per host
maxFreeSockets: 10, // Max idle connections per host
timeout: 60000 // Socket timeout
});
const client = new Perplexity({
httpAgent: optimizedAgent
});
// For high-throughput applications
const highThroughputAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 60000,
maxSockets: 200,
maxFreeSockets: 50,
timeout: 120000
});
const clientHighThroughput = new Perplexity({
httpAgent: highThroughputAgent
});
```
## Performance Monitoring
### Request Timing and Metrics
Monitor performance metrics to identify bottlenecks:
```python Python theme={null}
import time
import asyncio
from perplexity import AsyncPerplexity, DefaultAioHttpClient
class PerformanceMonitor:
def __init__(self):
self.request_times = []
self.error_count = 0
async def timed_request(self, client, query):
start_time = time.time()
try:
result = await client.search.create(query=query)
duration = time.time() - start_time
self.request_times.append(duration)
return result
except Exception as e:
self.error_count += 1
raise e
def get_stats(self):
if not self.request_times:
return {"error": "No successful requests"}
return {
"total_requests": len(self.request_times),
"error_count": self.error_count,
"avg_response_time": sum(self.request_times) / len(self.request_times),
"min_response_time": min(self.request_times),
"max_response_time": max(self.request_times)
}
async def run_performance_test():
monitor = PerformanceMonitor()
async with AsyncPerplexity(
http_client=DefaultAioHttpClient()
) as client:
queries = [f"test query {i}" for i in range(10)]
tasks = [
monitor.timed_request(client, query)
for query in queries
]
await asyncio.gather(*tasks, return_exceptions=True)
print(monitor.get_stats())
asyncio.run(run_performance_test())
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
class PerformanceMonitor {
private requestTimes: number[] = [];
private errorCount: number = 0;
async timedRequest(client: Perplexity, query: string) {
const startTime = performance.now();
try {
const result = await client.search.create({ query });
const duration = performance.now() - startTime;
this.requestTimes.push(duration);
return result;
} catch (error) {
this.errorCount++;
throw error;
}
}
getStats() {
if (this.requestTimes.length === 0) {
return { error: "No successful requests" };
}
return {
totalRequests: this.requestTimes.length,
errorCount: this.errorCount,
avgResponseTime: this.requestTimes.reduce((a, b) => a + b, 0) / this.requestTimes.length,
minResponseTime: Math.min(...this.requestTimes),
maxResponseTime: Math.max(...this.requestTimes)
};
}
}
async function runPerformanceTest() {
const monitor = new PerformanceMonitor();
const client = new Perplexity();
const queries = Array.from({ length: 10 }, (_, i) => `test query ${i}`);
const tasks = queries.map(query =>
monitor.timedRequest(client, query).catch(error => error)
);
await Promise.all(tasks);
console.log(monitor.getStats());
}
runPerformanceTest();
```
## Memory Optimization
### Efficient Data Processing
Process large datasets efficiently with streaming and pagination:
```python Python theme={null}
import asyncio
from perplexity import AsyncPerplexity, DefaultAioHttpClient
async def process_large_dataset(queries, process_fn):
"""Process queries in batches to manage memory usage"""
async with AsyncPerplexity(
http_client=DefaultAioHttpClient()
) as client:
async def process_single(query):
try:
result = await client.search.create(query=query)
# Process immediately to avoid storing in memory
processed = process_fn(result)
# Clear the original result from memory
del result
return processed
except Exception as e:
return f"Error processing {query}: {e}"
# Process in small batches
batch_size = 5
for i in range(0, len(queries), batch_size):
batch = queries[i:i + batch_size]
# Process batch
tasks = [process_single(query) for query in batch]
batch_results = await asyncio.gather(*tasks)
# Yield results instead of accumulating
for result in batch_results:
yield result
# Optional: Small delay to prevent overwhelming the API
await asyncio.sleep(0.1)
# Usage
async def summarize_result(search_result):
"""Process function that extracts only what we need"""
return {
"query": search_result.query,
"result_count": len(search_result.results),
"top_title": search_result.results[0].title if search_result.results else None
}
async def main():
queries = [f"query {i}" for i in range(100)]
async for processed_result in process_large_dataset(queries, summarize_result):
print(processed_result)
asyncio.run(main())
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
async function* processLargeDataset(
queries: string[],
processFn: (result: any) => T
): AsyncGenerator {
const client = new Perplexity();
async function processSingle(query: string): Promise {
try {
const result = await client.search.create({ query });
// Process immediately to avoid storing in memory
const processed = processFn(result);
return processed;
} catch (error) {
return `Error processing ${query}: ${error}`;
}
}
// Process in small batches
const batchSize = 5;
for (let i = 0; i < queries.length; i += batchSize) {
const batch = queries.slice(i, i + batchSize);
// Process batch
const tasks = batch.map(query => processSingle(query));
const batchResults = await Promise.all(tasks);
// Yield results instead of accumulating
for (const result of batchResults) {
yield result;
}
// Optional: Small delay to prevent overwhelming the API
await new Promise(resolve => setTimeout(resolve, 100));
}
}
// Usage
function summarizeResult(searchResult: any) {
return {
query: searchResult.query,
resultCount: searchResult.results.length,
topTitle: searchResult.results[0]?.title || null
};
}
async function main() {
const queries = Array.from({ length: 100 }, (_, i) => `query ${i}`);
for await (const processedResult of processLargeDataset(queries, summarizeResult)) {
console.log(processedResult);
}
}
main();
```
## Best Practices
Always use async clients when you need to process multiple requests simultaneously.
For CPU-bound processing after API calls, consider using worker threads or processes.
Configure appropriate connection limits based on your application's needs.
```python Python theme={null}
# Good: Optimized for your use case
limits = httpx.Limits(
max_keepalive_connections=20, # Based on expected concurrency
max_connections=50,
keepalive_expiry=30.0
)
```
```typescript TypeScript/JavaScript theme={null}
// Good: Optimized for your use case
const agent = new https.Agent({
keepAlive: true,
maxSockets: 20, // Based on expected concurrency
keepAliveMsecs: 30000
});
```
Use metrics to identify bottlenecks and optimize accordingly.
Don't optimize prematurely - measure first, then optimize based on actual performance data.
Implement proper rate limiting and backpressure handling for high-throughput applications.
```python Python theme={null}
# Use semaphores to limit concurrent requests
semaphore = asyncio.Semaphore(10) # Max 10 concurrent requests
async def rate_limited_request(client, query):
async with semaphore:
return await client.search.create(query=query)
```
```typescript TypeScript/JavaScript theme={null}
// Use a queue or throttling library
import pLimit from 'p-limit';
const limit = pLimit(10); // Max 10 concurrent requests
const rateLimitedRequest = (client: Perplexity, query: string) =>
limit(() => client.search.create({ query }));
```
## Related Resources
Optimize connection pooling and timeouts
Handle errors in async operations
# Type Safety
Source: https://docs.perplexity.ai/guides/perplexity-sdk-type-safety
Learn how to leverage full TypeScript definitions and Python type hints with the Perplexity SDKs for better development experience and code safety.
## Overview
Both Perplexity SDKs provide comprehensive type definitions to help you catch errors at development time and provide better IDE support. This guide covers type annotations, generic types, and advanced typing patterns.
## Basic Type Usage
### Type Imports and Annotations
Use type imports for better IDE support and type checking:
```python Python theme={null}
from perplexity import Perplexity
from perplexity.types import (
SearchCreateResponse,
ChatCompletionCreateResponse,
SearchResult,
ChatCompletionMessage
)
client = Perplexity()
# Type hints for better IDE support
search_response: SearchCreateResponse = client.search.create(
query="artificial intelligence"
)
# Access typed properties
result: SearchResult = search_response.results[0]
print(f"Title: {result.title}")
print(f"URL: {result.url}")
print(f"Snippet: {result.snippet}")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// TypeScript provides full intellisense and type checking
const searchResponse: Perplexity.Search.SearchCreateResponse = await client.search.create({
query: "artificial intelligence"
});
// Access typed properties with intellisense
const result = searchResponse.results[0];
console.log(`Title: ${result.title}`);
console.log(`URL: ${result.url}`);
console.log(`Snippet: ${result.snippet}`);
```
### Runtime Type Validation
Python SDK uses Pydantic for runtime type validation:
```python Python theme={null}
from perplexity import Perplexity
from perplexity.types import SearchCreateResponse
client = Perplexity()
# Runtime validation ensures type safety
try:
search_response = client.search.create(
query="machine learning",
max_results=10
)
# Pydantic model methods for serialization
json_data = search_response.to_json()
dict_data = search_response.to_dict()
# Type validation on field access
first_result = search_response.results[0]
print(f"Result type: {type(first_result)}")
except ValueError as e:
print(f"Type validation error: {e}")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// TypeScript compile-time type checking
const searchResponse: Perplexity.Search.SearchCreateResponse = await client.search.create({
query: "machine learning",
max_results: 10 // TypeScript ensures correct property names
});
// Serialization (already plain objects)
const jsonData = JSON.stringify(searchResponse);
const objectData = searchResponse; // Already a plain object
// Type safety at compile time
const firstResult = searchResponse.results[0];
console.log(`Result type available in IDE: ${typeof firstResult}`);
```
## Advanced Type Patterns
### Generic Type Helpers
Create reusable typed functions:
```python Python theme={null}
from typing import TypeVar, Generic, List, Optional, Callable
from perplexity import Perplexity
from perplexity.types import SearchCreateResponse, ChatCompletionCreateResponse
T = TypeVar('T')
R = TypeVar('R')
class TypedPerplexityClient:
def __init__(self, client: Perplexity):
self.client = client
def search_with_transform(
self,
query: str,
transform: Callable[[SearchCreateResponse], T]
) -> T:
"""Perform search and transform the result with type safety"""
response = self.client.search.create(query=query)
return transform(response)
def batch_search(
self,
queries: List[str]
) -> List[SearchCreateResponse]:
"""Perform multiple searches with proper typing"""
results = []
for query in queries:
response = self.client.search.create(query=query)
results.append(response)
return results
# Usage with type safety
client = TypedPerplexityClient(Perplexity())
def extract_titles(response: SearchCreateResponse) -> List[str]:
return [result.title for result in response.results]
# Typed function call
titles: List[str] = client.search_with_transform("AI research", extract_titles)
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
class TypedPerplexityClient {
constructor(private client: Perplexity) {}
async searchWithTransform(
query: string,
transform: (response: Perplexity.Search.SearchCreateResponse) => T
): Promise {
const response = await this.client.search.create({ query });
return transform(response);
}
async batchSearch(queries: string[]): Promise {
const tasks = queries.map(query =>
this.client.search.create({ query })
);
return Promise.all(tasks);
}
}
// Usage with type safety
const client = new TypedPerplexityClient(new Perplexity());
function extractTitles(response: Perplexity.Search.SearchCreateResponse): string[] {
return response.results.map(result => result.title);
}
// Typed function call with full intellisense
const titles: string[] = await client.searchWithTransform("AI research", extractTitles);
```
### Custom Type Guards
Create type guards for safer type checking:
```python Python theme={null}
from typing import Union, TypeGuard
from perplexity.types import (
SearchCreateResponse,
ChatCompletionCreateResponse,
SearchResult
)
def is_search_response(
response: Union[SearchCreateResponse, ChatCompletionCreateResponse]
) -> TypeGuard[SearchCreateResponse]:
"""Type guard to check if response is a search response"""
return hasattr(response, 'results')
def is_valid_search_result(result: SearchResult) -> TypeGuard[SearchResult]:
"""Type guard to validate search result structure"""
return (
hasattr(result, 'title') and
hasattr(result, 'url') and
hasattr(result, 'snippet') and
result.title is not None and
result.url is not None
)
# Usage
def process_response(
response: Union[SearchCreateResponse, ChatCompletionCreateResponse]
) -> None:
if is_search_response(response):
# TypeScript now knows this is SearchCreateResponse
for result in response.results:
if is_valid_search_result(result):
print(f"Valid result: {result.title}")
else:
print("Invalid result format")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
function isSearchResponse(
response: Perplexity.Search.SearchCreateResponse | Perplexity.StreamChunk
): response is Perplexity.Search.SearchCreateResponse {
return 'results' in response;
}
function isValidSearchResult(result: { title: string; url: string; snippet: string }): boolean {
return (
typeof result.title === 'string' &&
typeof result.url === 'string' &&
typeof result.snippet === 'string' &&
result.title.length > 0 &&
result.url.length > 0
);
}
// Usage
function processResponse(
response: Perplexity.Search.SearchCreateResponse | Perplexity.StreamChunk
): void {
if (isSearchResponse(response)) {
// TypeScript now knows this is SearchCreateResponse
response.results.forEach(result => {
if (isValidSearchResult(result)) {
console.log(`Valid result: ${result.title}`);
} else {
console.log("Invalid result format");
}
});
}
}
```
## Response Type Utilities
### Extracting Nested Types
Work with nested response structures safely:
```python Python theme={null}
from typing import List, Optional
from perplexity import Perplexity
from perplexity.types import (
SearchCreateResponse,
SearchResult,
ChatCompletionCreateResponse,
ChatCompletionChoice
)
class ResponseUtils:
@staticmethod
def extract_search_titles(response: SearchCreateResponse) -> List[str]:
"""Extract all search result titles with type safety"""
return [result.title for result in response.results if result.title]
@staticmethod
def extract_search_urls(response: SearchCreateResponse) -> List[str]:
"""Extract all search result URLs with type safety"""
return [result.url for result in response.results if result.url]
@staticmethod
def get_first_search_result(
response: SearchCreateResponse
) -> Optional[SearchResult]:
"""Get first search result safely"""
return response.results[0] if response.results else None
@staticmethod
def extract_chat_content(
response: ChatCompletionCreateResponse
) -> Optional[str]:
"""Extract chat completion content safely"""
if response.choices and response.choices[0].message:
return response.choices[0].message.content
return None
# Usage
client = Perplexity()
search_response = client.search.create(query="Python programming")
titles = ResponseUtils.extract_search_titles(search_response)
urls = ResponseUtils.extract_search_urls(search_response)
first_result = ResponseUtils.get_first_search_result(search_response)
print(f"Found {len(titles)} results")
if first_result:
print(f"First result: {first_result.title}")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
class ResponseUtils {
static extractSearchTitles(response: Perplexity.Search.SearchCreateResponse): string[] {
return response.results
.filter(result => result.title)
.map(result => result.title);
}
static extractSearchUrls(response: Perplexity.Search.SearchCreateResponse): string[] {
return response.results
.filter(result => result.url)
.map(result => result.url);
}
static getFirstSearchResult(
response: Perplexity.Search.SearchCreateResponse
) {
return response.results[0];
}
static extractChatContent(
response: Perplexity.StreamChunk
): string | undefined {
const content = response.choices[0]?.message?.content;
// Handle content which can be string, array of chunks, or null
if (typeof content === 'string') {
return content;
}
if (Array.isArray(content)) {
// Extract text from content chunks
return content
.filter(chunk => chunk.type === 'text' && 'text' in chunk)
.map(chunk => (chunk as { text: string }).text)
.join('');
}
return undefined;
}
}
// Usage
const client = new Perplexity();
const searchResponse: Perplexity.Search.SearchCreateResponse = await client.search.create({
query: "Python programming"
});
const titles = ResponseUtils.extractSearchTitles(searchResponse);
const urls = ResponseUtils.extractSearchUrls(searchResponse);
const firstResult = ResponseUtils.getFirstSearchResult(searchResponse);
console.log(`Found ${titles.length} results`);
if (firstResult) {
console.log(`First result: ${firstResult.title}`);
}
```
### Custom Response Mappers
Create typed mappers for domain-specific data structures:
```python Python theme={null}
from typing import List, Optional, Dict, Any
from dataclasses import dataclass
from perplexity.types import SearchCreateResponse, SearchResult
@dataclass
class SimplifiedSearchResult:
title: str
url: str
snippet: str
domain: str
@dataclass
class SearchSummary:
query: str
total_results: int
results: List[SimplifiedSearchResult]
domains: List[str]
class SearchResponseMapper:
@staticmethod
def to_simplified(response: SearchCreateResponse) -> SearchSummary:
"""Convert API response to simplified domain model"""
simplified_results = []
domains = set()
for result in response.results:
if result.title and result.url and result.snippet:
# Extract domain from URL
try:
from urllib.parse import urlparse
domain = urlparse(result.url).netloc
domains.add(domain)
simplified_results.append(SimplifiedSearchResult(
title=result.title,
url=result.url,
snippet=result.snippet,
domain=domain
))
except Exception:
# Skip invalid URLs
continue
return SearchSummary(
query=response.query,
total_results=len(simplified_results),
results=simplified_results,
domains=list(domains)
)
# Usage with type safety
client = Perplexity()
api_response = client.search.create(query="machine learning frameworks")
summary: SearchSummary = SearchResponseMapper.to_simplified(api_response)
print(f"Query: {summary.query}")
print(f"Results: {summary.total_results}")
print(f"Unique domains: {len(summary.domains)}")
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
interface SimplifiedSearchResult {
title: string;
url: string;
snippet: string;
domain: string;
}
interface SearchSummary {
query: string;
totalResults: number;
results: SimplifiedSearchResult[];
domains: string[];
}
class SearchResponseMapper {
static toSimplified(response: Perplexity.Search.SearchCreateResponse): SearchSummary {
const simplifiedResults: SimplifiedSearchResult[] = [];
const domains = new Set();
for (const result of response.results) {
if (result.title && result.url && result.snippet) {
try {
const domain = new URL(result.url).hostname;
domains.add(domain);
simplifiedResults.push({
title: result.title,
url: result.url,
snippet: result.snippet,
domain
});
} catch {
// Skip invalid URLs
continue;
}
}
}
return {
query: response.id, // response.id contains the search identifier
totalResults: simplifiedResults.length,
results: simplifiedResults,
domains: Array.from(domains)
};
}
}
// Usage with type safety
const client = new Perplexity();
const apiResponse: Perplexity.Search.SearchCreateResponse = await client.search.create({
query: "machine learning frameworks"
});
const summary: SearchSummary = SearchResponseMapper.toSimplified(apiResponse);
console.log(`ID: ${summary.query}`);
console.log(`Results: ${summary.totalResults}`);
console.log(`Unique domains: ${summary.domains.length}`);
```
## IDE Integration
### Enhanced Development Experience
Maximize IDE support with proper type usage:
```python Python theme={null}
from perplexity import Perplexity
from perplexity.types import SearchCreateResponse
from typing import TYPE_CHECKING
if TYPE_CHECKING:
# Import types only for type checking (no runtime cost)
from perplexity.types import ChatCompletionCreateResponse
class EnhancedClient:
def __init__(self):
self.client = Perplexity()
def search(self, query: str, **kwargs) -> SearchCreateResponse:
"""
Perform search with full type hints
Args:
query: Search query string
**kwargs: Additional search parameters
Returns:
SearchCreateResponse: Typed search results
"""
return self.client.search.create(query=query, **kwargs)
def chat(self, message: str, model: str = "sonar-pro") -> "ChatCompletionCreateResponse":
"""
Chat completion with type hints
Args:
message: User message
model: Model to use for completion
Returns:
ChatCompletionCreateResponse: Typed chat response
"""
return self.client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": message}]
)
# Usage with full IDE support
enhanced_client = EnhancedClient()
# IDE provides full autocomplete and type checking
search_result = enhanced_client.search("Python tutorials")
print(search_result.results[0].title) # Full intellisense available
chat_result = enhanced_client.chat("Explain decorators")
# Access content safely (can be string, list, or None)
content = chat_result.choices[0].message.content
if isinstance(content, str):
print(content) # Type-safe access
```
```typescript TypeScript/JavaScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
class EnhancedClient {
private client: Perplexity;
constructor() {
this.client = new Perplexity();
}
/**
* Perform search with full type hints
*/
async search(
query: string,
options?: Partial
): Promise {
return this.client.search.create({
query,
...options
});
}
/**
* Chat completion with type hints
*/
async chat(
message: string,
model: string = "sonar"
): Promise {
return this.client.chat.completions.create({
model,
messages: [{ role: "user", content: message }]
});
}
}
// Usage with full IDE support
const enhancedClient = new EnhancedClient();
// IDE provides full autocomplete and type checking
const searchResult = await enhancedClient.search("Python tutorials");
console.log(searchResult.results[0].title); // Full intellisense available
const chatResult = await enhancedClient.chat("Explain decorators");
// Content can be string, array of chunks, or null - handle appropriately
const content = chatResult.choices[0]?.message?.content;
if (typeof content === 'string') {
console.log(content); // Type-safe access
}
```
## Type Safety Best Practices
Import and use specific types for better IDE support and error catching.
```python Python theme={null}
# Good: Specific type imports
from perplexity.types import SearchCreateResponse, SearchResult
def process_search(response: SearchCreateResponse) -> List[str]:
return [result.title for result in response.results]
```
```typescript TypeScript/JavaScript theme={null}
// Good: Use namespace types for type safety
import Perplexity from '@perplexity-ai/perplexity_ai';
function processSearch(response: Perplexity.Search.SearchCreateResponse): string[] {
return response.results.map(result => result.title);
}
```
Implement proper type checking for dynamic data.
TypeScript types are compile-time only. Use type guards for runtime validation.
Create reusable typed functions and classes for common patterns.
Generic types help maintain type safety while providing flexibility.
Use type annotations as documentation for better code maintainability.
```python Python theme={null}
def analyze_search_results(
response: SearchCreateResponse,
min_score: float = 0.5
) -> Dict[str, Any]:
"""
Analyze search results with scoring
Args:
response: Search API response
min_score: Minimum quality score threshold
Returns:
Analysis results with scores and recommendations
"""
# Implementation with type safety
```
```typescript TypeScript/JavaScript theme={null}
/**
* Analyze search results with scoring
*/
function analyzeSearchResults(
response: Perplexity.Search.SearchCreateResponse,
minScore: number = 0.5
): { scores: number[]; recommendations: string[] } {
// Implementation with type safety
}
```
## Related Resources
Type-safe error handling patterns
Type safety in production code
# Privacy & Security
Source: https://docs.perplexity.ai/guides/privacy-security
Learn about Perplexity's data privacy, retention policies, and security certifications for API users
## Data Privacy & Retention
### Zero Data Retention Policy
Perplexity maintains a strict **Zero Data Retention Policy** for the Sonar API. We do not retain any data sent via the Sonar API, and we absolutely do not use any customer data to train our models or for any other purposes beyond processing your immediate request.
### Data We Collect
The only data we collect through the Sonar API consists of essential billable metrics required for service operation:
* Number of tokens processed
* Model used for each request
* Request timestamp and duration
* API key identification (for billing purposes)
This billing metadata does not include any content from your prompts, responses, or other user data.
## Security Certifications & Compliance
Perplexity is compliant with industry-leading security standards and certifications:
### Current Certifications
**[SOC 2 Type II Report](https://trust.perplexity.ai/)** - Comprehensive security controls audit covering security, availability, processing integrity, confidentiality, and privacy
**[2025 HIPAA Gap Assessment](https://trust.perplexity.ai/)** - Healthcare data protection compliance evaluation
**[CAIQlite](https://trust.perplexity.ai/)** - Cloud security assessment questionnaire demonstrating cloud security posture
## Additional Security Information
For comprehensive details about our security measures, infrastructure protection, and compliance frameworks, visit our dedicated security portal:
Access detailed security documentation, compliance reports, and transparency information
All security measures and certifications are regularly updated and maintained to ensure the highest standards of data protection and service security.
# Quickstart
Source: https://docs.perplexity.ai/guides/pro-search-quickstart
Get started with Pro Search for Sonar Pro - enhanced search with automated tools, multi-step reasoning, and real-time thought streaming
## Overview
Pro Search enhances [Sonar Pro](/getting-started/models/models/sonar-pro) with automated tool usage, enabling multi-step reasoning through intelligent tool orchestration including web search and URL content fetching.
Pro Search only works when streaming is enabled. Non-streaming requests will fall back to standard Sonar Pro behavior.
Standard Sonar Pro
Single web search execution
Fast response synthesis
Fixed search strategy
Static result processing
Pro Search for Sonar Pro
Multi-step reasoning with automated tools
Dynamic tool execution
Real-time thought streaming
Adaptive research strategies
## Basic Usage
Enabling Pro Search requires setting `stream` to `true` and specifying `"search_type": "pro"` in your API request. The default search type is `"fast"` for regular Sonar Pro.
Here is an example of how to enable Pro Search with streaming:
```python Python SDK theme={null}
from perplexity import Perplexity
client = Perplexity(api_key="YOUR_API_KEY")
messages = [
{
"role": "user",
"content": "Analyze the latest developments in quantum computing and their potential impact on cryptography. Include recent research findings and expert opinions."
}
]
response = client.chat.completions.create(
model="sonar-pro",
messages=messages,
stream=True,
web_search_options={
"search_type": "pro"
}
)
for chunk in response:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
```
```typescript TypeScript SDK theme={null}
import { Perplexity } from '@perplexity-ai/perplexity_ai';
const client = new Perplexity({
apiKey: 'YOUR_API_KEY'
});
const response = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: 'Analyze the latest developments in quantum computing and their potential impact on cryptography. Include recent research findings and expert opinions.'
}
],
stream: true,
web_search_options: {
search_type: 'pro'
}
});
for await (const chunk of response) {
if (chunk.choices[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{
"role": "user",
"content": "Analyze the latest developments in quantum computing and their potential impact on cryptography. Include recent research findings and expert opinions."
}
],
"stream": true,
"web_search_options": {
"search_type": "pro"
}
}' --no-buffer
```
```json theme={null}
{
"id": "2f16f4a0-e1d7-48c7-832f-8757b96ec221",
"model": "sonar-pro",
"created": 1759957470,
"usage": {
"prompt_tokens": 15,
"completion_tokens": 98,
"total_tokens": 113,
"search_context_size": "low",
"cost": {
"input_tokens_cost": 0.0,
"output_tokens_cost": 0.001,
"request_cost": 0.014,
"total_cost": 0.015
}
},
"search_results": [
{
"title": "Quantum Computing Breakthrough 2024",
"url": "https://example.com/quantum-breakthrough",
"date": "2024-03-15",
"snippet": "Researchers at MIT have developed a new quantum error correction method...",
"source": "web"
}
],
"reasoning_steps": [
{
"thought": "I need to search for recent quantum computing developments first.",
"type": "web_search",
"web_search": {
"search_keywords": [
"quantum computing developments 2024 cryptography impact",
"post-quantum cryptography"
],
"search_results": [
{
"title": "Quantum Computing Breakthrough 2024",
"url": "https://example.com/quantum-breakthrough",
"date": "2024-03-15",
"last_updated": "2024-03-20",
"snippet": "Researchers at MIT have developed a new quantum error correction method...",
"source": "web"
}
]
}
},
{
"thought": "Let me fetch detailed content from this research paper.",
"type": "fetch_url_content",
"fetch_url_content": {
"contents": [
{
"title": "Quantum Error Correction Paper",
"url": "https://arxiv.org/abs/2024.quantum",
"date": null,
"last_updated": null,
"snippet": "Abstract: This paper presents a novel approach to quantum error correction...",
"source": "web"
}
]
}
}
],
"object": "chat.completion.chunk",
"choices": [
{
"index": 0,
"delta": {
"role": "assistant",
"content": "## Latest Quantum Computing Developments\n\nBased on my research and analysis..."
}
}
]
}
```
## Enabling Automatic Classification
Sonar Pro can be configured to automatically classify queries into Pro Search or Fast Search based on complexity. This is the recommended approach for most applications.
Set `search_type: "auto"` to let the system intelligently route queries based on complexity.
```python Python SDK theme={null}
from perplexity import Perplexity
client = Perplexity(api_key="YOUR_API_KEY")
response = client.chat.completions.create(
model="sonar-pro",
messages=[
{
"role": "user",
"content": "Compare the energy efficiency of Tesla Model 3, Chevrolet Bolt, and Nissan Leaf"
}
],
stream=True,
web_search_options={
"search_type": "auto" # Automatic classification
}
)
for chunk in response:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
```
```typescript TypeScript SDK theme={null}
import { Perplexity } from '@perplexity-ai/perplexity_ai';
const client = new Perplexity({
apiKey: 'YOUR_API_KEY'
});
const response = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: 'Compare the energy efficiency of Tesla Model 3, Chevrolet Bolt, and Nissan Leaf'
}
],
stream: true,
web_search_options: {
search_type: 'auto' // Automatic classification
}
});
for await (const chunk of response) {
if (chunk.choices[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{
"role": "user",
"content": "Compare the energy efficiency of Tesla Model 3, Chevrolet Bolt, and Nissan Leaf"
}
],
"stream": true,
"web_search_options": {
"search_type": "auto"
}
}' --no-buffer
```
#### How Classification Works
The classifier analyzes your query and automatically routes it to:
* **Pro Search** for complex queries requiring:
* Multi-step reasoning or analysis
* Comparative analysis across multiple sources
* Deep research workflows
* **Fast Search** for straightforward queries like:
* Simple fact lookups
* Direct information retrieval
* Basic question answering
#### Billing with Auto Classification
**You are billed based on which search type your query triggers:**
* If classified as **Pro Search**: \$14–\$22 per 1,000 requests (based on context size)
* If classified as **Fast Search**: \$6–\$14 per 1,000 requests (based on context size - same as standard Sonar Pro)
To see the full pricing details, see the Pricing section.
Automatic classification is recommended for most applications as it balances cost optimization with query performance. You get Pro Search capabilities when needed without overpaying for simple queries.
### Manually Specifying the Search Type
If needed, you can manually specify the search type. This is useful for specific use cases where you know the query requires Pro Search capabilities.
* **`"search_type": "pro"`** — Manually specify Pro Search for complex queries when you know multi-step tool usage is needed
* **`"search_type": "fast"`** — Manually specify Fast Search for simple queries to optimize speed and cost (this is also the default when `search_type` is omitted)
## Built-in Tool Capabilities
Pro Search provides access to two powerful built-in tools that the model can use automatically:
Conduct targeted web searches with custom queries, filters, and search strategies based on the evolving research context.
Retrieve and analyze content from specific URLs to gather detailed information beyond search result snippets.
The model automatically decides which tools to use and when, creating dynamic research workflows tailored to each specific query. These are built-in tools that the system calls for you—you cannot register custom tools. Learn more in the [Built-in Tool Capabilities](/guides/pro-search-agentic-tools) guide.
## Additional Capabilities
Pro Search also provides access to advanced Sonar Pro features that enhance your development experience:
* **[Stream Mode Guide](/guides/pro-search-stream-mode-guide)**: Control streaming response formats with concise or full mode for optimized bandwidth usage and enhanced reasoning visibility.
## Pricing
Pro Search pricing consists of token usage plus request fees that vary by search type and context size.
Token Usage (Same for All Search Types)
Input Tokens\$3 per 1M
Output Tokens\$15 per 1M
Request Fees (per 1,000 requests)
Pro Search (Complex Queries)
High Context\$22
Medium Context\$18
Low Context\$14
Fast Search (Simple Queries)
High Context\$14
Medium Context\$10
Low Context\$6
When using `search_type: "auto"`, you're billed at the Pro Search rate if your query is classified as complex, or the Fast Search rate if classified as simple. See the full pricing details here.
## Next Steps
Comprehensive guide to the chat completions API
Complete API documentation and parameter reference
# Stream Mode: Concise vs Full
Source: https://docs.perplexity.ai/guides/pro-search-stream-mode-guide
Learn how to use stream_mode to control streaming response formats and optimize your integration
## Overview
The `stream_mode` parameter gives you control over how streaming responses are formatted. Choose between two modes:
* **`full`** (default) - Traditional streaming format with complete message objects in each chunk
* **`concise`** - Optimized streaming format with reduced redundancy and enhanced reasoning visibility
The `concise` mode is designed to minimize bandwidth usage and provide better visibility into the model's reasoning process.
## Quick Comparison
| Feature | Full Mode | Concise Mode |
| ----------------------- | ---------------------------------------- | ----------------------------------- |
| **Message aggregation** | Server-side (includes `choices.message`) | Client-side (delta only) |
| **Chunk types** | Single type (`chat.completion.chunk`) | Multiple types for different stages |
| **Search results** | Multiple times during stream | Only in `done` chunks |
| **Bandwidth** | Higher (includes redundant data) | Lower (optimized for efficiency) |
## Using Concise Mode
Set `stream_mode: "concise"` when creating streaming completions:
```python theme={null}
from perplexity import Perplexity
client = Perplexity()
stream = client.chat.completions.create(
model="sonar-pro",
messages=[{"role": "user", "content": "What's the weather in Seattle?"}],
stream=True,
stream_mode="concise"
)
for chunk in stream:
print(f"Chunk type: {chunk.object}")
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
```
```typescript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const stream = await client.chat.completions.create({
model: "sonar-pro",
messages: [{ role: "user", content: "What's the weather in Seattle?" }],
stream: true,
stream_mode: "concise"
});
for await (const chunk of stream) {
console.log(`Chunk type: ${chunk.object}`);
if (chunk.choices[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
```
```bash theme={null}
curl -X POST "https://api.perplexity.ai/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"messages": [{"role": "user", "content": "What is the weather in Seattle?"}],
"stream": true,
"stream_mode": "concise"
}'
```
## Understanding Chunk Types
In concise mode, you'll receive four different types of chunks during the stream:
### 1. `chat.reasoning`
Streamed during the reasoning stage, containing real-time reasoning steps and search operations.
```json theme={null}
{
"id": "cfa38f9d-fdbc-4ac6-a5d2-a3010b6a33a6",
"model": "sonar-pro",
"created": 1759441590,
"object": "chat.reasoning",
"choices": [{
"index": 0,
"finish_reason": null,
"message": {
"role": "assistant",
"content": ""
},
"delta": {
"role": "assistant",
"content": "",
"reasoning_steps": [{
"thought": "Searching the web for Seattle's current weather...",
"type": "web_search",
"web_search": {
"search_results": [...],
"search_keywords": ["Seattle current weather"]
}
}]
}
}],
"type": "message"
}
```
```python theme={null}
def handle_reasoning_chunk(chunk):
"""Process reasoning stage updates"""
if chunk.object == "chat.reasoning":
delta = chunk.choices[0].delta
if hasattr(delta, 'reasoning_steps'):
for step in delta.reasoning_steps:
print(f"\n[Reasoning] {step.thought}")
if step.type == "web_search":
keywords = step.web_search.search_keywords
print(f"[Search] Keywords: {', '.join(keywords)}")
```
```typescript theme={null}
function handleReasoningChunk(chunk: any) {
if (chunk.object === "chat.reasoning") {
const delta = chunk.choices[0].delta;
if (delta.reasoning_steps) {
for (const step of delta.reasoning_steps) {
console.log(`\n[Reasoning] ${step.thought}`);
if (step.type === "web_search") {
const keywords = step.web_search.search_keywords;
console.log(`[Search] Keywords: ${keywords.join(', ')}`);
}
}
}
}
}
```
### 2. `chat.reasoning.done`
Marks the end of the reasoning stage and includes all search results (web, images, videos) and reasoning steps.
```json theme={null}
{
"id": "3dd9d463-0fef-47e3-af70-92f9fcc4db1f",
"model": "sonar-pro",
"created": 1759459505,
"object": "chat.reasoning.done",
"usage": {
"prompt_tokens": 6,
"completion_tokens": 0,
"total_tokens": 6,
"search_context_size": "low"
},
"search_results": [...],
"images": [...],
"choices": [{
"index": 0,
"finish_reason": null,
"message": {
"role": "assistant",
"content": "",
"reasoning_steps": [...]
},
"delta": {
"role": "assistant",
"content": ""
}
}]
}
```
```python theme={null}
def handle_reasoning_done(chunk):
"""Process end of reasoning stage"""
if chunk.object == "chat.reasoning.done":
print("\n[Reasoning Complete]")
# Access all search results
if hasattr(chunk, 'search_results'):
print(f"Found {len(chunk.search_results)} sources")
for result in chunk.search_results[:3]:
print(f" • {result['title']}")
# Access image results
if hasattr(chunk, 'images'):
print(f"Found {len(chunk.images)} images")
# Partial usage stats available
if hasattr(chunk, 'usage'):
print(f"Tokens used so far: {chunk.usage.total_tokens}")
```
```typescript theme={null}
function handleReasoningDone(chunk: any) {
if (chunk.object === "chat.reasoning.done") {
console.log("\n[Reasoning Complete]");
// Access all search results
if (chunk.search_results) {
console.log(`Found ${chunk.search_results.length} sources`);
chunk.search_results.slice(0, 3).forEach((result: any) => {
console.log(` • ${result.title}`);
});
}
// Access image results
if (chunk.images) {
console.log(`Found ${chunk.images.length} images`);
}
// Partial usage stats available
if (chunk.usage) {
console.log(`Tokens used so far: ${chunk.usage.total_tokens}`);
}
}
}
```
### 3. `chat.completion.chunk`
Streamed during the response generation stage, containing the actual content being generated.
```json theme={null}
{
"id": "cfa38f9d-fdbc-4ac6-a5d2-a3010b6a33a6",
"model": "sonar-pro",
"created": 1759441592,
"object": "chat.completion.chunk",
"choices": [{
"index": 0,
"finish_reason": null,
"message": {
"role": "assistant",
"content": ""
},
"delta": {
"role": "assistant",
"content": " tonight"
}
}]
}
```
```python theme={null}
def handle_completion_chunk(chunk):
"""Process content generation updates"""
if chunk.object == "chat.completion.chunk":
delta = chunk.choices[0].delta
if hasattr(delta, 'content') and delta.content:
# Stream content to user
print(delta.content, end='', flush=True)
return delta.content
return ""
```
```typescript theme={null}
function handleCompletionChunk(chunk: any): string {
if (chunk.object === "chat.completion.chunk") {
const delta = chunk.choices[0]?.delta;
if (delta?.content) {
// Stream content to user
process.stdout.write(delta.content);
return delta.content;
}
}
return "";
}
```
### 4. `chat.completion.done`
Final chunk indicating the stream is complete, including final search results, usage statistics, and cost information.
```json theme={null}
{
"id": "cfa38f9d-fdbc-4ac6-a5d2-a3010b6a33a6",
"model": "sonar-pro",
"created": 1759441595,
"object": "chat.completion.done",
"usage": {
"prompt_tokens": 6,
"completion_tokens": 238,
"total_tokens": 244,
"search_context_size": "low",
"cost": {
"input_tokens_cost": 0.0,
"output_tokens_cost": 0.004,
"request_cost": 0.006,
"total_cost": 0.01
}
},
"search_results": [...],
"images": [...],
"choices": [{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "## Seattle Weather Forecast\n\nSeattle is experiencing...",
"reasoning_steps": [...]
},
"delta": {
"role": "assistant",
"content": ""
}
}]
}
```
```python theme={null}
def handle_completion_done(chunk):
"""Process stream completion"""
if chunk.object == "chat.completion.done":
print("\n\n[Stream Complete]")
# Final aggregated message
full_message = chunk.choices[0].message.content
# Final search results
if hasattr(chunk, 'search_results'):
print(f"\nFinal sources: {len(chunk.search_results)}")
# Complete usage and cost information
if hasattr(chunk, 'usage'):
usage = chunk.usage
print(f"\nTokens: {usage.total_tokens}")
if hasattr(usage, 'cost'):
print(f"Cost: ${usage.cost.total_cost:.4f}")
return {
'content': full_message,
'search_results': getattr(chunk, 'search_results', []),
'images': getattr(chunk, 'images', []),
'usage': getattr(chunk, 'usage', None)
}
```
```typescript theme={null}
function handleCompletionDone(chunk: any) {
if (chunk.object === "chat.completion.done") {
console.log("\n\n[Stream Complete]");
// Final aggregated message
const fullMessage = chunk.choices[0].message.content;
// Final search results
if (chunk.search_results) {
console.log(`\nFinal sources: ${chunk.search_results.length}`);
}
// Complete usage and cost information
if (chunk.usage) {
console.log(`\nTokens: ${chunk.usage.total_tokens}`);
if (chunk.usage.cost) {
console.log(`Cost: $${chunk.usage.cost.total_cost.toFixed(4)}`);
}
}
return {
content: fullMessage,
search_results: chunk.search_results || [],
images: chunk.images || [],
usage: chunk.usage || null
};
}
}
```
## Complete Implementation Examples
### Full Concise Mode Handler
```python theme={null}
from perplexity import Perplexity
class ConciseStreamHandler:
def __init__(self):
self.content = ""
self.reasoning_steps = []
self.search_results = []
self.images = []
self.usage = None
def stream_query(self, query: str, model: str = "sonar-pro"):
"""Handle a complete concise streaming request"""
client = Perplexity()
stream = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": query}],
stream=True,
stream_mode="concise"
)
for chunk in stream:
self.process_chunk(chunk)
return self.get_result()
def process_chunk(self, chunk):
"""Route chunk to appropriate handler"""
chunk_type = chunk.object
if chunk_type == "chat.reasoning":
self.handle_reasoning(chunk)
elif chunk_type == "chat.reasoning.done":
self.handle_reasoning_done(chunk)
elif chunk_type == "chat.completion.chunk":
self.handle_content(chunk)
elif chunk_type == "chat.completion.done":
self.handle_done(chunk)
def handle_reasoning(self, chunk):
"""Process reasoning updates"""
delta = chunk.choices[0].delta
if hasattr(delta, 'reasoning_steps'):
for step in delta.reasoning_steps:
self.reasoning_steps.append(step)
print(f"💭 {step.thought}")
def handle_reasoning_done(self, chunk):
"""Process end of reasoning"""
if hasattr(chunk, 'search_results'):
self.search_results = chunk.search_results
print(f"\n🔍 Found {len(self.search_results)} sources")
if hasattr(chunk, 'images'):
self.images = chunk.images
print(f"🖼️ Found {len(self.images)} images")
print("\n📝 Generating response...\n")
def handle_content(self, chunk):
"""Process content chunks"""
delta = chunk.choices[0].delta
if hasattr(delta, 'content') and delta.content:
self.content += delta.content
print(delta.content, end='', flush=True)
def handle_done(self, chunk):
"""Process completion"""
if hasattr(chunk, 'usage'):
self.usage = chunk.usage
print(f"\n\n✅ Complete | Tokens: {self.usage.total_tokens}")
if hasattr(self.usage, 'cost'):
print(f"💰 Cost: ${self.usage.cost.total_cost:.4f}")
def get_result(self):
"""Return complete result"""
return {
'content': self.content,
'reasoning_steps': self.reasoning_steps,
'search_results': self.search_results,
'images': self.images,
'usage': self.usage
}
# Usage
handler = ConciseStreamHandler()
result = handler.stream_query("What's the latest news in AI?")
print(f"\n\nFinal content length: {len(result['content'])} characters")
print(f"Sources used: {len(result['search_results'])}")
```
```typescript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
interface StreamResult {
content: string;
reasoning_steps: any[];
search_results: any[];
images: any[];
usage: any;
}
class ConciseStreamHandler {
private content: string = "";
private reasoning_steps: any[] = [];
private search_results: any[] = [];
private images: any[] = [];
private usage: any = null;
async streamQuery(query: string, model: string = "sonar-pro"): Promise {
const client = new Perplexity();
const stream = await client.chat.completions.create({
model,
messages: [{ role: "user", content: query }],
stream: true,
stream_mode: "concise"
});
for await (const chunk of stream) {
this.processChunk(chunk);
}
return this.getResult();
}
private processChunk(chunk: any) {
const chunkType = chunk.object;
switch (chunkType) {
case "chat.reasoning":
this.handleReasoning(chunk);
break;
case "chat.reasoning.done":
this.handleReasoningDone(chunk);
break;
case "chat.completion.chunk":
this.handleContent(chunk);
break;
case "chat.completion.done":
this.handleDone(chunk);
break;
}
}
private handleReasoning(chunk: any) {
const delta = chunk.choices[0].delta;
if (delta.reasoning_steps) {
for (const step of delta.reasoning_steps) {
this.reasoning_steps.push(step);
console.log(`💭 ${step.thought}`);
}
}
}
private handleReasoningDone(chunk: any) {
if (chunk.search_results) {
this.search_results = chunk.search_results;
console.log(`\n🔍 Found ${this.search_results.length} sources`);
}
if (chunk.images) {
this.images = chunk.images;
console.log(`🖼️ Found ${this.images.length} images`);
}
console.log("\n📝 Generating response...\n");
}
private handleContent(chunk: any) {
const delta = chunk.choices[0]?.delta;
if (delta?.content) {
this.content += delta.content;
process.stdout.write(delta.content);
}
}
private handleDone(chunk: any) {
if (chunk.usage) {
this.usage = chunk.usage;
console.log(`\n\n✅ Complete | Tokens: ${this.usage.total_tokens}`);
if (this.usage.cost) {
console.log(`💰 Cost: $${this.usage.cost.total_cost.toFixed(4)}`);
}
}
}
private getResult(): StreamResult {
return {
content: this.content,
reasoning_steps: this.reasoning_steps,
search_results: this.search_results,
images: this.images,
usage: this.usage
};
}
}
// Usage
const handler = new ConciseStreamHandler();
const result = await handler.streamQuery("What's the latest news in AI?");
console.log(`\n\nFinal content length: ${result.content.length} characters`);
console.log(`Sources used: ${result.search_results.length}`);
```
```python theme={null}
import requests
import json
def stream_concise_mode(query: str):
"""Handle concise streaming with raw HTTP"""
url = "https://api.perplexity.ai/chat/completions"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"model": "sonar-pro",
"messages": [{"role": "user", "content": query}],
"stream": True,
"stream_mode": "concise"
}
response = requests.post(url, headers=headers, json=payload, stream=True)
content = ""
search_results = []
usage = None
for line in response.iter_lines():
if line:
line = line.decode('utf-8')
if line.startswith('data: '):
data_str = line[6:]
if data_str == '[DONE]':
break
try:
chunk = json.loads(data_str)
chunk_type = chunk.get('object')
if chunk_type == 'chat.reasoning':
# Handle reasoning
delta = chunk['choices'][0]['delta']
if 'reasoning_steps' in delta:
for step in delta['reasoning_steps']:
print(f"💭 {step['thought']}")
elif chunk_type == 'chat.reasoning.done':
# Handle reasoning completion
if 'search_results' in chunk:
search_results = chunk['search_results']
print(f"\n🔍 Found {len(search_results)} sources\n")
elif chunk_type == 'chat.completion.chunk':
# Handle content
delta = chunk['choices'][0]['delta']
if 'content' in delta and delta['content']:
content += delta['content']
print(delta['content'], end='', flush=True)
elif chunk_type == 'chat.completion.done':
# Handle completion
if 'usage' in chunk:
usage = chunk['usage']
print(f"\n\n✅ Tokens: {usage['total_tokens']}")
except json.JSONDecodeError:
continue
return {
'content': content,
'search_results': search_results,
'usage': usage
}
# Usage
result = stream_concise_mode("What's the latest news in AI?")
```
## Best Practices
In concise mode, `choices.message` is not incrementally updated. You must aggregate chunks yourself.
```python theme={null}
# Track content yourself
content = ""
for chunk in stream:
if chunk.object == "chat.completion.chunk":
if chunk.choices[0].delta.content:
content += chunk.choices[0].delta.content
```
Display reasoning steps to users for better transparency and trust.
```python theme={null}
def display_reasoning(step):
"""Show reasoning to users"""
print(f"🔍 Searching for: {step.web_search.search_keywords}")
print(f"💭 {step.thought}")
```
Search results and usage information only appear in `chat.reasoning.done` and `chat.completion.done` chunks.
```python theme={null}
# Don't check for search_results in other chunk types
if chunk.object in ["chat.reasoning.done", "chat.completion.done"]:
if hasattr(chunk, 'search_results'):
process_search_results(chunk.search_results)
```
Use the `object` field to route chunks to appropriate handlers.
```python theme={null}
chunk_handlers = {
"chat.reasoning": handle_reasoning,
"chat.reasoning.done": handle_reasoning_done,
"chat.completion.chunk": handle_content,
"chat.completion.done": handle_done
}
handler = chunk_handlers.get(chunk.object)
if handler:
handler(chunk)
```
Cost information is only available in the `chat.completion.done` chunk.
```python theme={null}
if chunk.object == "chat.completion.done":
if hasattr(chunk.usage, 'cost'):
total_cost = chunk.usage.cost.total_cost
print(f"Request cost: ${total_cost:.4f}")
```
## Migration from Full Mode
If you're migrating from full mode to concise mode, here are the key changes:
```python theme={null}
from perplexity import Perplexity
client = Perplexity()
stream = client.chat.completions.create(
model="sonar-pro",
messages=[{"role": "user", "content": "What's the weather?"}],
stream=True
# stream_mode defaults to "full"
)
for chunk in stream:
# All chunks are chat.completion.chunk
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
# Search results may appear in multiple chunks
if hasattr(chunk, 'search_results'):
print(f"Sources: {len(chunk.search_results)}")
```
```python theme={null}
from perplexity import Perplexity
client = Perplexity()
stream = client.chat.completions.create(
model="sonar-pro",
messages=[{"role": "user", "content": "What's the weather?"}],
stream=True,
stream_mode="concise" # Enable concise mode
)
for chunk in stream:
# Multiple chunk types - route appropriately
if chunk.object == "chat.reasoning":
# New: Handle reasoning steps
if chunk.choices[0].delta.reasoning_steps:
print("Reasoning in progress...")
elif chunk.object == "chat.reasoning.done":
# New: Reasoning complete, search results available
if hasattr(chunk, 'search_results'):
print(f"Sources: {len(chunk.search_results)}")
elif chunk.object == "chat.completion.chunk":
# Content chunks (similar to full mode)
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
elif chunk.object == "chat.completion.done":
# Final chunk with complete metadata
print(f"\nTotal tokens: {chunk.usage.total_tokens}")
```
## When to Use Each Mode
* Simple integrations where you want the SDK to handle aggregation
* Backward compatibility with existing implementations
* When you don't need reasoning visibility
* Production applications optimizing for bandwidth
* Applications that need reasoning transparency
* Real-time chat interfaces with reasoning display
* Cost-sensitive applications
## Resources
* [Streaming Responses Guide](/guides/streaming-responses) - General streaming documentation
* [Chat Completions SDK](/guides/chat-completions-sdk) - Complete SDK guide
* [API Reference - Chat Completions](/api-reference/chat-completions-post) - API documentation
# Built-in Tool Capabilities
Source: https://docs.perplexity.ai/guides/pro-search-tools
Learn about Pro Search's built-in tools: web search and URL content fetching
## Overview
Pro Search provides two built-in tools that the model uses automatically to answer your queries. The model decides which tools to use and when—you don't need to configure anything. These tools are called automatically by the system; you cannot register custom tools.
All tool executions appear in the `reasoning_steps` array of streaming responses, giving you visibility into how the model researched your query.
## web\_search
Conducts web searches to find current information, statistics, and expert opinions.
**Example in action:**
```json theme={null}
{
"thought": "I need current data on EV market trends",
"type": "web_search",
"web_search": {
"search_keywords": [
"EV Statistics 2023-2024",
"electric vehicle sales data",
"global EV market trends"
],
"search_results": [
{
"title": "Trends in electric cars",
"url": "https://www.iea.org/reports/global-ev-outlook-2024/trends-in-electric-cars",
"date": "2024-03-15",
"last_updated": null,
"snippet": "Electric car sales neared 14 million in 2023, 95% of which were in China, Europe and the United States...",
"source": "web"
}
]
}
}
```
## fetch\_url\_content
Retrieves full content from specific URLs to access detailed information beyond search result snippets.
**Example in action:**
```json theme={null}
{
"thought": "This research paper contains detailed methodology I need to review",
"type": "fetch_url_content",
"fetch_url_content": {
"contents": [
{
"title": "Attention Is All You Need",
"url": "https://arxiv.org/pdf/1706.03762",
"date": null,
"last_updated": null,
"snippet": "The dominant sequence transduction models are based on complex recurrent or convolutional neural networks that include an encoder and a decoder...",
"source": "web"
}
]
}
}
```
## Multi-Tool Workflows
The model automatically combines multiple tools when needed. For example, when asked to research solar panel options, it might:
1. Use `web_search` to find current incentives and costs
2. Use `fetch_url_content` to read detailed policy documents
3. Use `web_search` again to verify electricity rates and compare providers
## Related Resources
Get started with Pro Search basics
Learn about streaming and real-time reasoning visibility
Complete API documentation
# Prompt Guide
Source: https://docs.perplexity.ai/guides/prompt-guide
## System Prompt
You can use the system prompt to provide instructions related to style, tone, and language of the response.
The real-time search component of our models does not attend to the system prompt.
**Example of a system prompt**
```
You are a helpful AI assistant.
Rules:
1. Provide only the final answer. It is important that you do not include any explanation on the steps below.
2. Do not show the intermediate steps information.
Steps:
1. Decide if the answer should be a brief sentence or a list of suggestions.
2. If it is a list of suggestions, first, write a brief and natural introduction based on the original query.
3. Followed by a list of suggestions, each suggestion should be split by two newlines.
```
## User Prompt
You should use the user prompt to pass in the actual query for which you need an answer for. The user prompt will be used to kick off a real-time web search to make sure the answer has the latest and the most relevant information needed.
**Example of a user prompt**
```
What are the best sushi restaurants in the world currently?
```
# Web Search Models: General Prompting Guidelines
Our web search-powered models combine the capabilities of LLMs with real-time web searches. Understanding how they differ from traditional LLMs will help you craft more effective prompts.
## Best Practices for Prompting Web Search Models
Unlike traditional LLMs, our web search models require specificity to retrieve relevant search results. Adding just 2-3 extra words of context can dramatically improve performance.
**Good Example**: "Explain recent advances in climate prediction models for urban planning"
**Poor Example**: "Tell me about climate models"
While few-shot prompting works well for traditional LLMs, it confuses web search models by triggering searches for your examples rather than your actual query.
**Good Example**: "Summarize the current research on mRNA vaccine technology"
**Poor Example**: "Here's an example of a good summary about vaccines: \[example text]. Now summarize the current research on mRNA vaccines."
Craft prompts with search-friendly terms that would appear on relevant web pages. Consider how experts in the field would describe the topic online.
**Good Example**: "Compare the energy efficiency ratings of heat pumps vs. traditional HVAC systems for residential use"
**Poor Example**: "Tell me which home heating is better"
Include critical context to guide the web search toward the most relevant content, but keep prompts concise and focused.
**Good Example**: "Explain the impact of the 2023 EU digital markets regulations on app store competition for small developers"
**Poor Example**: "What are the rules for app stores?"
## Web Search Model Pitfalls to Avoid
Generic prompts lead to scattered web search results and unfocused responses. Always narrow your scope.
**Avoid**: "What's happening in AI?"
**Instead**: "What are the three most significant commercial applications of generative AI in healthcare in the past year?"
Prompting strategies designed for traditional LLM often don't work well with web search models. Adapt your approach accordingly.
**Avoid**: "Act as an expert chef and give me a recipe for sourdough bread. Start by explaining the history of sourdough, then list ingredients, then..."
**Instead**: "What's a reliable sourdough bread recipe for beginners? Include ingredients and step-by-step instructions."
Complex prompts with multiple unrelated questions can confuse the search component. Focus on one topic per query.
**Avoid**: "Explain quantum computing, and also tell me about regenerative agriculture, and provide stock market predictions."
**Instead**: "Explain quantum computing principles that might impact cryptography in the next decade."
Don't assume the model will search for what you intended without specific direction. Be explicit about exactly what information you need.
**Avoid**: "Tell me about the latest developments."
**Instead**: "What are the latest developments in offshore wind energy technology announced in the past 6 months?"
## Handling URLs and Source Information
**Never ask for URLs or source links in your prompts.** The generative model cannot see the actual URLs from the web search, which means any URLs it provides in the response text are likely to be hallucinated and incorrect.
### The Right Way to Access Sources
URLs and source information are automatically returned in the `search_results` field of the API response. This field contains accurate information about the sources used, including:
* `title`: The title of the source page
* `url`: The actual URL of the source
* `date`: The publication date of the content
**Example of incorrect prompting:**
```
❌ BAD: "From the past 5 days, identify high-potential Canadian news stories...
For each item, include:
- A clear headline
- 1–2 sentence summary
- Include a link to a source"
```
**Example of correct prompting:**
```
✅ GOOD: "From the past 5 days, identify high-potential Canadian news stories...
For each item, include:
- A clear headline
- 1–2 sentence summary
- Why it matters from a thought-leadership perspective"
// Then parse URLs from the search_results field in the API response
```
### Why This Matters
The web search and language generation components work differently:
1. **Web Search Component**: Finds and retrieves content from specific URLs
2. **Language Generation Component**: Processes the retrieved content but doesn't have access to the original URLs
3. **API Response**: Provides both the generated text and the accurate source URLs separately
When you ask for URLs in your prompt, the language model will attempt to generate them based on patterns it has seen, but these will not be the actual URLs that were searched. Always use the `search_results` field for accurate source information.
## Preventing Hallucination in Search Results
**LLMs are designed to be "helpful" and may attempt to provide answers even when they lack sufficient information.** This can lead to hallucinated or inaccurate responses, especially when asking about sources that Sonar cannot access.
### Understanding the Helpfulness Problem
Large Language Models are trained to be assistive and will often try to provide an answer even when they're not confident about the information. This tendency can be problematic when:
* You request information from sources that Sonar cannot access (e.g., LinkedIn posts, private documents, paywalled content)
* The search doesn't return relevant results for your specific query
* You ask for very recent information that may not be indexed yet
### Common Scenarios That Lead to Hallucination
**Inaccessible Sources:**
```
❌ PROBLEMATIC: "What did the CEO of XYZ company post on LinkedIn yesterday about their new product launch?"
```
*Sonar may not be able to access LinkedIn content, but the model might still attempt to provide an answer based on general knowledge or patterns.*
**Overly Specific Recent Events:**
```
❌ PROBLEMATIC: "What was discussed in the closed-door meeting between Company A and Company B last week?"
```
*Private information that wouldn't be publicly searchable may still get a fabricated response.*
### How to Prevent Hallucination
**Use Explicit Instructions:**
Include clear guidance in your prompts about what to do when information isn't available:
```
✅ GOOD: "Search for recent developments in quantum computing breakthroughs.
If you are not able to get search results or find relevant information,
please state that clearly rather than providing speculative information."
```
**Set Clear Boundaries:**
```
✅ GOOD: "Based on publicly available sources from the past week, what are the latest policy changes in Canadian healthcare?
If no recent information is found, please indicate that no recent updates were discovered."
```
**Request Source Transparency:**
```
✅ GOOD: "Find information about Tesla's latest earnings report.
Only provide information that you can verify from your search results,
and clearly state if certain details are not available."
```
### Best Practices for Reliable Results
Always instruct the model to acknowledge when it cannot find information rather than guessing.
**Example**: "If you cannot find reliable sources for this information, please say so explicitly."
Stick to information that is likely to be publicly indexed and searchable.
**Avoid**: LinkedIn posts, private company documents, closed meetings
**Prefer**: News articles, public reports, official announcements
Frame requests with conditional statements that give the model permission to say "I don't know."
**Example**: "If available, provide details about... Otherwise, indicate what information could not be found."
For critical information, consider breaking complex requests into smaller, more specific queries to verify consistency.
**Strategy**: Ask the same question in different ways and compare results for consistency.
## Use Built-in Search Parameters, Not Prompts
**Always use Perplexity's built-in search parameters instead of trying to control search behavior through prompts.** API parameters are guaranteed to work and are much more effective than asking the model to filter results.
### Why Built-in Parameters Are Better
When you want to control search behavior—such as limiting sources, filtering by date, or adjusting search depth—use the API's built-in parameters rather than prompt instructions. The search component processes these parameters directly, ensuring reliable and consistent results.
### Common Mistakes: Prompt-Based Control
**❌ Ineffective - Trying to control via prompts:**
```json theme={null}
{
"model": "sonar-pro",
"messages": [
{
"role": "user",
"content": "Search only on Wikipedia and official government sites for information about climate change policies. Make sure to only look at sources from the past month."
}
]
}
```
### Correct Approach: Use API Parameters
**✅ Effective - Using built-in parameters:**
```json theme={null}
{
"model": "sonar-pro",
"messages": [
{
"role": "user",
"content": "What are the latest climate change policies?"
}
],
"search_domain_filter": ["wikipedia.org"]
}
```
### Available Search Parameters
### Benefits of Using Built-in Parameters
Built-in parameters are processed directly by the search engine, ensuring they're applied correctly every time.
Parameters filter results before they reach the language model, leading to more focused and relevant responses.
Keep your prompts focused on what you want the model to generate, not how to search.
API parameters provide predictable behavior across different queries and use cases.
### Advanced Techniques
We recommend for users *not* to tune language parameters such as `temperature`, as the default settings for these have already been optimized.
Adjust model parameters based on your specific needs:
* **Search Domain Filter**: Limit results to trusted sources for research-heavy queries.
* **Search Context Size**: Use "high" for comprehensive research questions and "low" for simple factual queries.
Example configuration for technical documentation:
```json theme={null}
{
"search_domain_filter": ["wikipedia.org", "docs.python.org"],
"web_search_options": {
"search_context_size": "medium"
}
}
```
### Tips for Different Query Types
| Query Type | Best Practices |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Factual Research** | • Use specific questions • Use search domain filters for academic sources • Consider "high" search context size |
| **Creative Content** | • Provide detailed style guidelines in system prompt • Specify tone, voice, and audience |
| **Technical Questions** | • Include relevant technical context • Specify preferred programming language/framework • Use domain filters for documentation sites |
| **Analysis & Insights** | • Request step-by-step reasoning • Ask for specific metrics or criteria |
# Rate Limits & Usage Tiers
Source: https://docs.perplexity.ai/guides/rate-limits-usage-tiers
## What are Usage Tiers?
Usage tiers determine your **rate limits** and access to **beta features** based on your cumulative API spending. As you spend more on API credits over time, you automatically advance to higher tiers with increased rate limits.
You can check your current usage tier by visiting your [API settings page](https://www.perplexity.ai/settings/api).
***
## Tier Progression
| Tier | Total Credits Purchased | Status |
| ---------- | ----------------------- | ---------------------------- |
| **Tier 0** | \$0 | New accounts, limited access |
| **Tier 1** | \$50+ | Light usage, basic limits |
| **Tier 2** | \$250+ | Regular usage |
| **Tier 3** | \$500+ | Heavy usage |
| **Tier 4** | \$1,000+ | Production usage |
| **Tier 5** | \$5,000+ | Enterprise usage |
Tiers are based on **cumulative purchases** across your account lifetime, not current balance.
***
## How Tiers Work
* **Automatic advancement** - Tiers increase based on your total lifetime credit purchases
* **Rate limit increases** - Higher tiers get significantly more requests per minute
* **Permanent status** - Once you reach a tier, you keep it (no downgrade)
## Rate Limits by Model
| Model | Requests per minute (RPM) |
| ------------------------------------------ | ------------------------- |
| `sonar-deep-research` | 5 |
| `sonar-reasoning-pro` | 50 |
| `sonar-pro` | 50 |
| `sonar` | 50 |
| POST `/async/chat/completions` | 5 |
| GET `/async/chat/completions` | 3000 |
| GET `/async/chat/completions/{request_id}` | 6000 |
| Model | Requests per minute (RPM) |
| ------------------------------------------ | ------------------------- |
| `sonar-deep-research` | 10 |
| `sonar-reasoning-pro` | 50 |
| `sonar-pro` | 50 |
| `sonar` | 50 |
| POST `/async/chat/completions` | 10 |
| GET `/async/chat/completions` | 3000 |
| GET `/async/chat/completions/{request_id}` | 6000 |
| Model | Requests per minute (RPM) |
| ------------------------------------------ | ------------------------- |
| `sonar-deep-research` | 20 |
| `sonar-reasoning-pro` | 500 |
| `sonar-pro` | 500 |
| `sonar` | 500 |
| POST `/async/chat/completions` | 20 |
| GET `/async/chat/completions` | 3000 |
| GET `/async/chat/completions/{request_id}` | 6000 |
| Model | Requests per minute (RPM) |
| ------------------------------------------ | ------------------------- |
| `sonar-deep-research` | 40 |
| `sonar-reasoning-pro` | 1,000 |
| `sonar-pro` | 1,000 |
| `sonar` | 1,000 |
| POST `/async/chat/completions` | 40 |
| GET `/async/chat/completions` | 3000 |
| GET `/async/chat/completions/{request_id}` | 6000 |
| Model | Requests per minute (RPM) |
| ------------------------------------------ | ------------------------- |
| `sonar-deep-research` | 60 |
| `sonar-reasoning-pro` | 2,000 |
| `sonar-pro` | 2,000 |
| `sonar` | 2,000 |
| POST `/async/chat/completions` | 60 |
| GET `/async/chat/completions` | 3000 |
| GET `/async/chat/completions/{request_id}` | 6000 |
| Model | Requests per minute (RPM) |
| ------------------------------------------ | ------------------------- |
| `sonar-deep-research` | 100 |
| `sonar-reasoning-pro` | 2,000 |
| `sonar-pro` | 2,000 |
| `sonar` | 2,000 |
| POST `/async/chat/completions` | 100 |
| GET `/async/chat/completions` | 3000 |
| GET `/async/chat/completions/{request_id}` | 6000 |
***
## Search Rate Limits
The Search API has separate rate limits that apply to all usage tiers:
| Endpoint | Rate Limit | Burst Capacity |
| -------------- | ---------------------- | -------------- |
| POST `/search` | 50 requests per second | 50 requests |
**Search Rate Limiter Behavior:**
* **Burst**: Can handle 50 requests instantly
* **Sustained**: Exactly 50 QPS average over time
Search rate limits are independent of your usage tier and apply consistently across all accounts using the same leaky bucket algorithm.
**Need Higher Search Rate Limits?**
If you require increased rate limits for the Search API beyond the standard 50 requests per second, please fill out our [rate limit increase request form](https://perplexity.typeform.com/to/yctmfyVT). We'll review your use case and work with you to accommodate your needs.
***
## How Rate Limiting Works
Our rate limiting system uses a **leaky bucket algorithm** that allows for burst traffic while maintaining strict long-term rate control.
### Technical Implementation
The leaky bucket algorithm works like a bucket with a small hole in the bottom:
* **Bucket Capacity**: Maximum number of requests you can make instantly (burst capacity)
* **Leak Rate**: How quickly tokens refill over time (your rate limit)
* **Token Refill**: New requests become available at regular intervals
**Key Benefits:**
* ✅ Allows legitimate burst traffic
* ✅ Prevents sustained abuse
* ✅ Predictable and fair rate enforcement
Let's examine how **50 requests per second** works in practice:
**Parameters:**
* Capacity: 50 tokens
* Leak rate: 50 tokens/second
* Refill: 1 token every 20ms
**Scenario 1: Burst Traffic**
```
Time 0.0s: Bucket full (50 tokens)
→ Send 50 requests instantly → ALL ALLOWED ✅
→ Send 51st request → REJECTED ❌ (bucket empty)
Time 0.020s: 1 token refilled
→ Send 1 request → ALLOWED ✅
→ Send 2nd request → REJECTED ❌
Time 0.040s: 1 more token refilled
→ Send 1 request → ALLOWED ✅
```
**Scenario 2: Steady 50 QPS**
```
Request every 20ms:
Time 0.0s: Request → ✅ (50→49 tokens)
Time 0.020s: Request → ✅ (49+1-1=49 tokens)
Time 0.040s: Request → ✅ (49+1-1=49 tokens)
... maintains 49-50 tokens, all requests pass
```
**Scenario 3: Slightly Over 50 QPS**
```
Request every 19ms (≈52.6 QPS):
→ Eventually tokens deplete faster than refill
→ Some requests start getting rejected
→ Achieves exactly 50 QPS on average
```
**What this means for your applications:**
**✅ Burst Tolerance:**
* Can handle your full rate limit instantly
* Perfect for batch operations or sudden traffic spikes
* No need to artificially spread requests
**✅ Predictable Behavior:**
* Strict average rate enforcement over time
* Quick recovery after burst usage
* Consistent performance across different usage patterns
**❌ Abuse Prevention:**
* Prevents sustained over-limit usage
* Blocks excessive burst attempts
* Maintains fair resource allocation
**Best Practices:**
* Take advantage of burst capacity for batch operations
* Monitor your usage patterns to optimize request timing
* Implement proper error handling for 429 responses
***
## What Happens When You Hit Rate Limits?
When you exceed your rate limits:
1. **429 Error** - Your request gets rejected with "Too Many Requests"
2. **Continuous Refill** - Tokens refill continuously based on your rate limit
3. **Immediate Recovery** - New requests become available as soon as tokens refill
**Example Recovery Times:**
* **50 QPS limit**: 1 token refills every 20ms
* **500 QPS limit**: 1 token refills every 2ms
* **1,000 QPS limit**: 1 token refills every 1ms
**Best Practices:**
* Monitor your usage to predict when you'll need higher tiers
* Consider upgrading your tier proactively for production applications
* Implement exponential backoff with jitter in your code
* Take advantage of burst capacity for batch operations
* Don't artificially spread requests if you have available burst capacity
***
## Upgrading Your Tier
Visit your [API settings page](https://www.perplexity.ai/settings/api) to see your current tier and total spending.
Add credits to your account through the billing section. Your tier will automatically upgrade once you reach the spending threshold.
Your new rate limits take effect immediately after the tier upgrade. Check your settings page to confirm.
Higher tiers significantly improve your API experience with increased rate limits, especially important for production applications.
# Returning Images with Sonar
Source: https://docs.perplexity.ai/guides/returning-images
Control image results with domain and format filters using Sonar models
## Overview
Sonar models can return images as part of their responses to enhance the information provided. You can control which images are returned using domain and format filters, giving you fine-grained control over the sources and file types of image results.
**SDK Installation Required**: Install the official SDK first - `pip install perplexityai` for Python or `npm install @perplexity-ai/perplexity_ai` for TypeScript/JavaScript.
The `image_domain_filter` and `image_format_filter` parameters allow you to control the sources and file types of image results returned by the Sonar models.
You can include a maximum of 10 entries in each of the filter lists. These filters currently apply only when `"return_images": true` is set in your request.
## Filter Types
### Domain Filtering
The `image_domain_filter` parameter controls which image sources are included or excluded:
* **Exclude domains**: Prefix with `-` (e.g., `-gettyimages.com`)
* **Include domains**: Use domain name directly (e.g., `wikimedia.org`)
### Format Filtering
The `image_format_filter` parameter restricts results to specific file formats:
* Use lowercase file extensions: `gif`, `jpg`, `png`, `webp`
* Omit the dot prefix: use `gif`, not `.gif`
## Basic Usage
To enable image returns, your request must include `"return_images": true`.
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"return_images": true,
"messages": [
{"role": "user", "content": "Show me images of Mount Everest"}
]
}' | jq
```
```python Python theme={null}
from perplexity import Perplexity
# Initialize the client
client = Perplexity()
# Request with image returns enabled
completion = client.chat.completions.create(
model="sonar",
return_images=True,
messages=[
{"role": "user", "content": "Show me images of Mount Everest"}
]
)
print(completion.choices[0].message.content)
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
// Initialize the client
const client = new Perplexity();
// Request with image returns enabled
const completion = await client.chat.completions.create({
model: 'sonar',
return_images: true,
messages: [
{ role: 'user', content: 'Show me images of Mount Everest' }
]
});
console.log(completion.choices[0].message.content);
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Initialize the client
const client = new Perplexity();
// Request with image returns enabled
const completion = await client.chat.completions.create({
model: 'sonar',
return_images: true,
messages: [
{ role: 'user', content: 'Show me images of Mount Everest' }
]
});
console.log(completion.choices[0].message.content);
```
## Filtering Examples
### 1. Exclude Specific Image Domains
Filter out images from specific providers like Getty Images:
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"return_images": true,
"image_domain_filter": ["-gettyimages.com"],
"messages": [
{"role": "user", "content": "What is the weather like today in London?"}
]
}' | jq
```
```python Python theme={null}
from perplexity import Perplexity
# Initialize the client
client = Perplexity()
# Exclude Getty Images from results
completion = client.chat.completions.create(
model="sonar",
return_images=True,
image_domain_filter=["-gettyimages.com"],
messages=[
{"role": "user", "content": "Show me images of Mount Everest"}
]
)
print(completion.choices[0].message.content)
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
// Initialize the client
const client = new Perplexity();
// Exclude Getty Images from results
const completion = await client.chat.completions.create({
model: 'sonar',
return_images: true,
image_domain_filter: ['-gettyimages.com'],
messages: [
{ role: 'user', content: 'Show me images of Mount Everest' }
]
});
console.log(completion.choices[0].message.content);
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Initialize the client
const client = new Perplexity();
// Exclude Getty Images from results
const completion = await client.chat.completions.create({
model: 'sonar',
return_images: true,
image_domain_filter: ['-gettyimages.com'],
messages: [
{ role: 'user', content: 'Show me images of Mount Everest' }
]
});
console.log(completion.choices[0].message.content);
```
### 2. Only Return GIFs
Restrict results to GIF images only:
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"return_images": true,
"image_format_filter": ["gif"],
"messages": [
{"role": "user", "content": "Show me a funny cat gif"}
]
}' | jq
```
```python Python theme={null}
from perplexity import Perplexity
# Initialize the client
client = Perplexity()
# Only return GIF images
completion = client.chat.completions.create(
model="sonar",
return_images=True,
image_format_filter=["gif"],
messages=[
{"role": "user", "content": "Show me a funny cat gif"}
]
)
print(completion.choices[0].message.content)
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
// Initialize the client
const client = new Perplexity();
// Only return GIF images
const completion = await client.chat.completions.create({
model: 'sonar',
return_images: true,
image_format_filter: ['gif'],
messages: [
{ role: 'user', content: 'Show me a funny cat gif' }
]
});
console.log(completion.choices[0].message.content);
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Initialize the client
const client = new Perplexity();
// Only return GIF images
const completion = await client.chat.completions.create({
model: 'sonar',
return_images: true,
image_format_filter: ['gif'],
messages: [
{ role: 'user', content: 'Show me a funny cat gif' }
]
});
console.log(completion.choices[0].message.content);
```
### 3. Combine Domain and Format Filters
Use both filters together for precise control:
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"return_images": true,
"image_domain_filter": ["-gettyimages.com"],
"image_format_filter": ["gif"],
"messages": [
{"role": "user", "content": "Show me a gif of a dog"}
]
}' | jq
```
```python Python theme={null}
from perplexity import Perplexity
# Initialize the client
client = Perplexity()
# Combine domain and format filtering
completion = client.chat.completions.create(
model="sonar",
return_images=True,
image_domain_filter=["-gettyimages.com"],
image_format_filter=["gif"],
messages=[
{"role": "user", "content": "Show me a gif of a dog"}
]
)
print(completion.choices[0].message.content)
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
// Initialize the client
const client = new Perplexity();
// Combine domain and format filtering
const completion = await client.chat.completions.create({
model: 'sonar',
return_images: true,
image_domain_filter: ['-gettyimages.com'],
image_format_filter: ['gif'],
messages: [
{ role: 'user', content: 'Show me a gif of a dog' }
]
});
console.log(completion.choices[0].message.content);
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
// Initialize the client
const client = new Perplexity();
// Combine domain and format filtering
const completion = await client.chat.completions.create({
model: 'sonar',
return_images: true,
image_domain_filter: ['-gettyimages.com'],
image_format_filter: ['gif'],
messages: [
{ role: 'user', content: 'Show me a gif of a dog' }
]
});
console.log(completion.choices[0].message.content);
```
## Advanced Filtering
### Multiple Domain Exclusions
```python theme={null}
# Exclude multiple image providers
completion = client.chat.completions.create(
model="sonar",
return_images=True,
image_domain_filter=["-gettyimages.com", "-shutterstock.com", "-stockphoto.com"],
messages=[
{"role": "user", "content": "Show me nature photography"}
]
)
```
### Multiple Format Types
```python theme={null}
# Allow multiple image formats
completion = client.chat.completions.create(
model="sonar",
return_images=True,
image_format_filter=["jpg", "png", "webp"],
messages=[
{"role": "user", "content": "Show me high-quality landscape images"}
]
)
```
### Include Specific Domains
```python theme={null}
# Include only Wikipedia images
completion = client.chat.completions.create(
model="sonar",
return_images=True,
image_domain_filter=["wikimedia.org"],
messages=[
{"role": "user", "content": "Show me historical images"}
]
)
```
## Common Use Cases
### Educational Content
```python theme={null}
# Get educational images from trusted sources
image_domain_filter = ["wikimedia.org", "nasa.gov", "archive.org"]
image_format_filter = ["jpg", "png"]
```
### Creative Projects
```python theme={null}
# Get animated content for presentations
image_format_filter = ["gif", "webp"]
image_domain_filter = ["-gettyimages.com", "-shutterstock.com"] # Avoid watermarked images
```
### High-Quality Photography
```python theme={null}
# Focus on professional photography formats
image_format_filter = ["jpg", "png"]
image_domain_filter = ["-lowres.com", "-thumbnail.com"] # Exclude low-quality sources
```
## Best Practices
* Use simple domain names like `example.com` or `-gettyimages.com`
* Do not include `http://`, `https://`, or subdomains
* Mix inclusion and exclusion in domain filters for precise control
* Keep lists short (≤10 entries) for performance and relevance
* File extensions must be lowercase: `["jpg"]`, not `["JPG"]`
* Omit dot prefix: use `gif`, not `.gif`
* Consider your use case: GIFs for animation, PNG for transparency, JPG for photos
* WebP offers good compression but may have limited compatibility
* Filters may slightly increase response time
* Overly restrictive filters may reduce result quality or quantity
* Test different filter combinations to find the right balance
* Monitor response times with different filter configurations
## Filter Reference
### Supported Image Formats
| Format | Extension | Best For |
| ------ | --------- | ------------------------------------- |
| JPEG | `jpg` | Photographs, complex images |
| PNG | `png` | Screenshots, images with transparency |
| WebP | `webp` | Modern format with good compression |
| GIF | `gif` | Animated images, simple graphics |
### Common Domain Exclusions
| Domain | Type | Reason |
| ------------------- | ------------ | ------------------------- |
| `-gettyimages.com` | Stock Photos | Watermarked content |
| `-shutterstock.com` | Stock Photos | Watermarked content |
| `-istockphoto.com` | Stock Photos | Watermarked content |
| `-pinterest.com` | Social Media | Mixed quality/attribution |
Start with broad filters and gradually refine them based on the quality and relevance of returned images.
## Limitations
* Maximum of 10 entries in each filter list
* Filters only apply when `"return_images": true` is set
* Some domains may not be filterable due to CDN usage
* Very restrictive filters may result in no images being returned
# Returning Videos with Sonar
Source: https://docs.perplexity.ai/guides/returning-videos
Learn how to return videos in API responses using media_response overrides with raw HTTP requests
## Overview
Sonar models can return videos as part of their responses to provide rich multimedia content that enhances the information delivered. You can control video returns using the `media_response` parameter with `overrides` to specify when videos should be included in responses.
Use the `media_response.overrides.return_videos` parameter to control when videos are returned in API responses.
Video returns may increase response size and processing time. Use this feature selectively for queries where video content adds significant value.
## Basic Usage
To enable video returns, include the `media_response` parameter with `overrides.return_videos` set to `true` in your request.
### Simple Video Request
```bash cURL theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{
"role": "user",
"content": "2024 Olympics highlights"
}
]
}' | jq
```
```python Python theme={null}
import requests
import json
import os
url = "https://api.perplexity.ai/chat/completions"
headers = {
"Authorization": f"Bearer {os.environ['PERPLEXITY_API_KEY']}",
"Content-Type": "application/json"
}
data = {
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": True
}
},
"messages": [
{
"role": "user",
"content": "2024 Olympics highlights"
}
]
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
print(json.dumps(result, indent=2))
```
```typescript TypeScript theme={null}
const response = await fetch('https://api.perplexity.ai/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PERPLEXITY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'sonar-pro',
media_response: {
overrides: {
return_videos: true
}
},
messages: [
{
role: 'user',
content: '2024 Olympics highlights'
}
]
})
});
const result = await response.json();
console.log(JSON.stringify(result, null, 2));
```
```json theme={null}
{
"id": "58dee6e4-d2de-4d7e-910f-4048caa6903d",
"model": "sonar-pro",
"created": 1758844959,
"usage": {
"prompt_tokens": 6,
"completion_tokens": 542,
"total_tokens": 548,
"search_context_size": "low",
"cost": {
"input_tokens_cost": 0.0,
"output_tokens_cost": 0.008,
"request_cost": 0.006,
"total_cost": 0.014
}
},
"citations": [
"https://en.wikipedia.org/wiki/2024_Summer_Olympics",
"https://www.teamusa.com/news/2024/august/13/top-moments-from-the-paris-2024-olympic-games",
"https://www.nbcolympics.com/news/olympic-track-and-field-paris-2024-biggest-stories-replays-medal-results-top-athletes-new",
"https://www.youtube.com/watch?v=WajxULWXIFE",
"https://www.nbcolympics.com/news/olympic-gymnastics-paris-2024-biggest-stories-replays-medal-results-top-athletes-new-records",
"https://www.youtube.com/watch?v=vy6FivZHRjQ",
"https://www.espn.com/olympics/story/_/id/40813327/2024-paris-summer-olympics-live-updates-highlights-results-sunday-closing-ceremony",
"https://www.youtube.com/watch?v=q4Mujt1wer4",
"https://www.youtube.com/olympics",
"https://www.youtube.com/watch?v=OFCVkSQYTjA",
"https://www.youtube.com/watch?v=7Xnr805bm4E",
"https://www.nbcolympics.com/videos"
],
"search_results": [
{
"title": "2024 Summer Olympics - Wikipedia",
"url": "https://en.wikipedia.org/wiki/2024_Summer_Olympics",
"date": "2006-03-05",
"last_updated": "2025-09-24",
"snippet": "Paris 2024 featured the debut of breaking as an Olympic sport, and was the final Olympic Games held during the IOC presidency of Thomas Bach. The 2024 Games ..."
},
{
"title": "Top Moments From the Paris 2024 Olympic Games | Team USA",
"url": "https://www.teamusa.com/news/2024/august/13/top-moments-from-the-paris-2024-olympic-games",
"date": "2024-08-13",
"last_updated": "2025-09-25",
"snippet": "Scottie Scheffler wins his first Olympic Gold Medal | Golf · Victor Montalvo Takes Bronze in Breaking | Breaking · Brooke Raboutou Secures Her ..."
},
{
"title": "Olympic track and field at Paris 2024: Biggest stories, replays, medal ...",
"url": "https://www.nbcolympics.com/news/olympic-track-and-field-paris-2024-biggest-stories-replays-medal-results-top-athletes-new",
"date": "2024-08-11",
"last_updated": "2024-08-11",
"snippet": "In the Paris Olympic men's 100m final, Lyles edged past Jamaican Kishane Thompson to win his first Olympic gold medal in a lifetime-best 9.784 ..."
},
{
"title": "When Every Millisecond Counts at the Olympics | Top Moments",
"url": "https://www.youtube.com/watch?v=WajxULWXIFE",
"date": "2025-01-31",
"last_updated": "2025-07-29",
"snippet": "Re-live ALL the incredible #Paris2024 action: ➡️ https://oly.ch/P24Replays The most thrilling finishes of the Olympic Games in Paris 2024 ..."
},
{
"title": "Olympic gymnastics at Paris 2024: Biggest stories, replays, medal ...",
"url": "https://www.nbcolympics.com/news/olympic-gymnastics-paris-2024-biggest-stories-replays-medal-results-top-athletes-new-records",
"date": "2024-08-11",
"last_updated": "2024-08-11",
"snippet": "Here's a look back at all the action, from highlights to medal results and everything in between. FULL EVENT REPLAYS:ARTISTIC GYMNASTICS"
},
{
"title": "Best of Olympic Games Paris 2024 - YouTube",
"url": "https://www.youtube.com/watch?v=vy6FivZHRjQ",
"date": "2024-10-21",
"last_updated": "2025-07-27",
"snippet": "the Paris 2024 Olympics! From jaw-dropping athletic feats to ... highlights, including iconic victories, emotional celebrations, and ..."
},
{
"title": "2024 Olympics: Highlights from Sunday in Paris - ESPN",
"url": "https://www.espn.com/olympics/story/_/id/40813327/2024-paris-summer-olympics-live-updates-highlights-results-sunday-closing-ceremony",
"date": "2024-08-11",
"last_updated": "2024-08-11",
"snippet": "The US Olympic run concluded with Team USA becoming the first team in any sport to win eight consecutive Olympic gold medals with a win over France."
},
{
"title": "Moments that Left Us SPEECHLESS at Paris 2024! ❤️ - YouTube",
"url": "https://www.youtube.com/watch?v=q4Mujt1wer4",
"date": "2025-01-13",
"last_updated": "2025-08-29",
"snippet": "I'll always love the moment between Tara Davis-Woodhall and her husband Hunter Woodhall, who'd later snag his first gold medal in the Paralympics later on."
},
{
"title": "Olympics - YouTube",
"url": "https://www.youtube.com/olympics",
"date": "2025-03-24",
"last_updated": "2025-03-26",
"snippet": "Witness the power, dedication, and skill of Olympic athletes as they compete for their chance to shine on the world stage."
},
{
"title": "♂️ Best Athletics Moments at #Paris2024 - YouTube",
"url": "https://www.youtube.com/watch?v=OFCVkSQYTjA",
"date": "2025-03-30",
"last_updated": "2025-07-29",
"snippet": "Receive the best athletics moments at the olympic games in Paris 2024 ♂️. #Paris2024 ..."
},
{
"title": "Men's 100m Final | Paris Champions - YouTube",
"url": "https://www.youtube.com/watch?v=7Xnr805bm4E",
"date": "2024-08-11",
"last_updated": "2025-07-28",
"snippet": "Re-live ALL the incredible #Paris2024 action: https://oly.ch/P24Replays Watch Noah Lyles of Team USA celebrate his gold medal victory ..."
},
{
"title": "All Highlights | NBC Olympics",
"url": "https://www.nbcolympics.com/videos",
"date": "2025-09-24",
"last_updated": "2025-09-25",
"snippet": "All Highlights · Melissa Jefferson-Wooden claps her hands in joy after winning the world women's 200m final · Three runners prepare to cross the finish line in ..."
}
],
"videos": [
{
"url": "https://www.youtube.com/watch?v=lmPuoxNSRr4",
"duration": null,
"thumbnail_width": 480,
"thumbnail_height": 360,
"thumbnail_url": "https://www.youtube.com/watch?v=lmPuoxNSRr4"
},
{
"url": "https://www.youtube.com/watch?v=cptEWh0yT4E",
"duration": null,
"thumbnail_width": 480,
"thumbnail_height": 360,
"thumbnail_url": "https://www.youtube.com/watch?v=cptEWh0yT4E"
},
{
"url": "https://www.youtube.com/watch?v=6bhS_AUKjtc",
"duration": null,
"thumbnail_width": 480,
"thumbnail_height": 360,
"thumbnail_url": "https://www.youtube.com/watch?v=6bhS_AUKjtc"
},
{
"url": "https://www.youtube.com/watch?v=vy6FivZHRjQ",
"duration": null,
"thumbnail_width": 480,
"thumbnail_height": 360,
"thumbnail_url": "https://www.youtube.com/watch?v=vy6FivZHRjQ"
},
{
"url": "https://www.youtube.com/watch?v=WajxULWXIFE",
"duration": null,
"thumbnail_width": 480,
"thumbnail_height": 360,
"thumbnail_url": "https://www.youtube.com/watch?v=WajxULWXIFE"
}
],
"object": "chat.completion",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "The 2024 Summer Olympics in Paris were marked by major milestones, standout athletic performances, record medal hauls, and historic firsts[1][2][3][6].\n\n**Key highlights:**\n\n- **Medal Table Leaders:** The United States and China finished tied with 40 gold medals each, but the U.S. claimed the top spot overall with 126 total medals; China followed with 91 total[1][2]. It was the first time the two Olympic powers tied in golds. Japan (20 golds), Australia (18 golds), and host nation France (16 golds) rounded out the top five[1].\n\n- **Breakdancing Debut:** Paris 2024 introduced **breaking** (breakdancing) as an Olympic sport for the first time[1].\n\n- **Athletics Dominance:** The U.S. displayed overwhelming strength in **track and field**, securing 34 medals—their best since 1984—and sweeping all four hurdle events for the first time[3]. Noah Lyles won his first Olympic gold in the men's 100m with a dramatic, lifetime-best 9.784 seconds[3][4]. Sydney McLaughlin-Levrone broke her own women's 400m hurdles world record yet again[3].\n\n- **Gymnastics Spectacle:** The games featured high drama and new records in **artistic gymnastics**, with full event replays and standout moments available for fans[5].\n\n- **Historic Firsts:** Several nations, including **Dominica, Saint Lucia, Cape Verde, and Albania**, celebrated their first-ever Olympic medals—some of them gold[1]. The **Refugee Olympic Team** won its first medal, a bronze in boxing by Cindy Ngamba[1].\n\n- **Iconic Performances:** Scottie Scheffler secured his first Olympic golf gold for Team USA; Victor Montalvo earned bronze in breaking; and Brooke Raboutou delivered in sport climbing[2].\n\n- **Intensity and Sportsmanship:** Multiple events featured finishes decided by milliseconds and millimeters, capturing the Olympic spirit, as showcased in event highlight reels and replays[4][6].\n\n- **Record-Breaking Tickets:** Paris 2024 broke Olympic records with over 9.5 million tickets sold (12.1 million including Paralympics), becoming a celebrated success despite some controversies around politics and logistics[1].\n\n**Notable Podium Sweep:** France swept all three medals in the men's BMX race, a moment of national pride[1].\n\nThe Paris Olympics were hailed as both a sporting and organizational triumph, celebrated by both locals and worldwide observers[1]."
},
"delta": {
"role": "assistant",
"content": ""
}
}
]
}
```
## Use Case Examples
### Sports and Events
Request videos for major sporting events or news:
```bash cURL theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{
"role": "user",
"content": "World Cup 2024 final match highlights"
}
]
}' | jq
```
```python Python theme={null}
import requests
import json
import os
response = requests.post(
"https://api.perplexity.ai/chat/completions",
headers={
"Authorization": f"Bearer {os.environ['PERPLEXITY_API_KEY']}",
"Content-Type": "application/json"
},
json={
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": True
}
},
"messages": [
{
"role": "user",
"content": "World Cup 2024 final match highlights"
}
]
}
)
print(json.dumps(response.json(), indent=2))
```
```typescript TypeScript theme={null}
const response = await fetch('https://api.perplexity.ai/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PERPLEXITY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'sonar-pro',
media_response: {
overrides: {
return_videos: true
}
},
messages: [
{
role: 'user',
content: 'World Cup 2024 final match highlights'
}
]
})
});
const result = await response.json();
console.log(JSON.stringify(result, null, 2));
```
### Educational Content
Get instructional videos for learning topics:
```bash cURL theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{
"role": "user",
"content": "How to perform CPR tutorial videos"
}
]
}' | jq
```
```python Python theme={null}
import requests
import os
response = requests.post(
"https://api.perplexity.ai/chat/completions",
headers={
"Authorization": f"Bearer {os.environ['PERPLEXITY_API_KEY']}",
"Content-Type": "application/json"
},
json={
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": True
}
},
"messages": [
{
"role": "user",
"content": "How to perform CPR tutorial videos"
}
]
}
)
print(response.json())
```
```typescript TypeScript theme={null}
const response = await fetch('https://api.perplexity.ai/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PERPLEXITY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'sonar-pro',
media_response: {
overrides: {
return_videos: true
}
},
messages: [
{
role: 'user',
content: 'How to perform CPR tutorial videos'
}
]
})
});
const result = await response.json();
console.log(result);
```
### Technology Demonstrations
Request videos showing product demos or tutorials:
```bash cURL theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{
"role": "user",
"content": "iPhone 16 pro camera features demonstration"
}
]
}' | jq
```
```python Python theme={null}
import requests
import os
response = requests.post(
"https://api.perplexity.ai/chat/completions",
headers={
"Authorization": f"Bearer {os.environ['PERPLEXITY_API_KEY']}",
"Content-Type": "application/json"
},
json={
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": True
}
},
"messages": [
{
"role": "user",
"content": "iPhone 16 pro camera features demonstration"
}
]
}
)
print(response.json())
```
```typescript TypeScript theme={null}
const response = await fetch('https://api.perplexity.ai/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PERPLEXITY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'sonar-pro',
media_response: {
overrides: {
return_videos: true
}
},
messages: [
{
role: 'user',
content: 'iPhone 16 pro camera features demonstration'
}
]
})
});
const result = await response.json();
console.log(result);
```
## Combined Media Responses
You can combine video returns with other media response options:
### Videos with Images
```bash theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": true,
"return_images": true
}
},
"messages": [
{
"role": "user",
"content": "Mars rover discoveries 2024"
}
]
}' | jq
```
### Videos with Search Filters
```bash theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"search_recency_filter": "week",
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{
"role": "user",
"content": "Latest SpaceX launch footage"
}
]
}' | jq
```
## Advanced Usage
### Streaming with Videos
Enable streaming responses while including video content:
```bash theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"stream": true,
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{
"role": "user",
"content": "Breaking news today with video coverage"
}
]
}'
```
### Multi-turn Conversation with Videos
Continue a conversation while maintaining video context:
```bash theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{
"role": "user",
"content": "Show me cooking videos for pasta recipes"
},
{
"role": "assistant",
"content": "Here are some great pasta cooking videos..."
},
{
"role": "user",
"content": "Now show me videos for making homemade sauce"
}
]
}' | jq
```
## Best Practices
* **Be specific**: Use descriptive queries that clearly indicate when video content would be valuable
* **Include context**: Mention specific events, products, or topics that commonly have video coverage
* **Use recency filters**: Combine with search filters to get the most current video content
* **Consider query intent**: Videos work best for demonstrations, tutorials, events, and visual explanations
* **Monitor response times**: Video-enabled requests may take longer to process
* **Handle larger payloads**: Responses containing videos will be larger than text-only responses
* **Implement timeouts**: Set appropriate timeout values for video-enabled requests
* **Cache strategically**: Consider caching video responses for frequently requested content
* **Verify video relevance**: Not all queries will return relevant video content
* **Handle empty results**: Implement fallback logic when no videos are available
* **Check video accessibility**: Ensure returned video content is accessible and appropriate
* **Validate video links**: Test that returned video URLs are functional before displaying
## Response Format
When videos are returned, they appear in the response content along with text. The videos will be included as part of the response structure, with video URLs and metadata available for display or processing.
## Common Use Cases
### News and Current Events
```bash theme={null}
# Get breaking news with video coverage
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"search_recency_filter": "day",
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{"role": "user", "content": "Latest political developments today"}
]
}'
```
### Product Reviews and Demonstrations
```bash theme={null}
# Get product demo videos
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{"role": "user", "content": "MacBook Pro M4 unboxing and first impressions"}
]
}'
```
### Educational and How-to Content
```bash theme={null}
# Get tutorial videos
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"media_response": {
"overrides": {
"return_videos": true
}
},
"messages": [
{"role": "user", "content": "How to change a car tire step by step"}
]
}'
```
## Troubleshooting
If your request doesn't return videos:
* Verify the `media_response.overrides.return_videos` parameter is set to `true`
* Check that your query is likely to have video content available
* Ensure you're using a model that supports video returns (sonar-pro recommended)
* Try different query phrasings that explicitly mention video content
For timeout issues:
* Increase your request timeout settings
* Use streaming responses for better user experience
* Consider breaking complex queries into smaller parts
* Implement retry logic for failed requests
When dealing with video-heavy responses:
* Implement proper JSON parsing for large payloads
* Consider pagination for multiple video results
* Use appropriate data structures to handle media content
* Implement progressive loading for video content
## Limitations
**Current Limitations:**
* Video returns may not be available for all query types
* Response times will be longer when videos are included
* Video content availability depends on external sources
* Some video content may be region-restricted
* No direct video format or quality control options currently available
## Environment Variables
For security, use environment variables for your API key:
```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```
```bash theme={null}
set PERPLEXITY_API_KEY=your_api_key_here
```
Then reference it in your requests:
```bash theme={null}
curl https://api.perplexity.ai/chat/completions \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "sonar-pro", ...}'
```
Start with simple queries to test video returns, then gradually build more complex requests as you understand the response patterns and performance characteristics.
# Best Practices
Source: https://docs.perplexity.ai/guides/search-best-practices
Learn best practices for optimizing search queries and implementing efficient async patterns with Perplexity's Search API.
## Overview
This guide covers essential best practices for getting the most out of Perplexity's Search API, including query optimization techniques and efficient async usage patterns for high-performance applications.
## Query Optimization
Use highly specific queries for more targeted results. For example, instead of searching for "AI", use a detailed query like "artificial intelligence machine learning healthcare applications 2024".
```python Python theme={null}
# Better: Specific query
search = client.search.create(
query="artificial intelligence medical diagnosis accuracy 2024",
max_results=10
)
# Avoid: Vague query
search = client.search.create(
query="AI medical",
max_results=10
)
```
```typescript TypeScript theme={null}
// Better: Specific query
const search = await client.search.create({
query: "artificial intelligence medical diagnosis accuracy 2024",
maxResults: 10
});
// Avoid: Vague query
const search = await client.search.create({
query: "AI medical",
maxResults: 10
});
```
Specific queries with context, time frames, and precise terminology yield more relevant and actionable results.
Break your main topic into related sub-queries to cover all aspects of your research. Use the multi-query search feature to run multiple related queries in a single request for more comprehensive and relevant information.
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Comprehensive research with related queries
search = client.search.create(
query=[
"artificial intelligence medical diagnosis accuracy 2024",
"machine learning healthcare applications FDA approval",
"AI medical imaging radiology deployment hospitals"
],
max_results=5
)
# Access results for each query
for i, query_results in enumerate(search.results):
print(f"Results for query {i+1}:")
for result in query_results:
print(f" {result.title}: {result.url}")
print("---")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Comprehensive research with related queries
const search = await client.search.create({
query: [
"artificial intelligence medical diagnosis accuracy 2024",
"machine learning healthcare applications FDA approval",
"AI medical imaging radiology deployment hospitals"
],
maxResults: 5
});
// Access results for each query
search.results.forEach((queryResults, i) => {
console.log(`Results for query ${i+1}:`);
queryResults.forEach(result => {
console.log(` ${result.title}: ${result.url}`);
});
console.log("---");
});
```
You can include up to 5 queries in a single multi-query request for efficient batch processing.
Implement exponential backoff for rate limit errors and use appropriate batching strategies.
```python Python theme={null}
import time
import random
from perplexity import RateLimitError
def search_with_retry(client, query, max_retries=3):
for attempt in range(max_retries):
try:
return client.search.create(query=query)
except RateLimitError:
if attempt < max_retries - 1:
# Exponential backoff with jitter
delay = (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
else:
raise
# Usage
try:
search = search_with_retry(client, "AI developments")
for result in search.results:
print(f"{result.title}: {result.url}")
except RateLimitError:
print("Maximum retries exceeded for search")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
async function searchWithRetry(
client: Perplexity,
query: string,
maxRetries: number = 3
) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.search.create({ query });
} catch (error) {
if (error instanceof Perplexity.RateLimitError && attempt < maxRetries - 1) {
// Exponential backoff with jitter
const delay = (2 ** attempt) + Math.random();
await new Promise(resolve => setTimeout(resolve, delay * 1000));
} else {
throw error;
}
}
}
throw new Error("Max retries exceeded");
}
// Usage
try {
const search = await searchWithRetry(client, "AI developments");
search.results.forEach(result => {
console.log(`${result.title}: ${result.url}`);
});
} catch (error) {
console.log("Maximum retries exceeded for search");
}
```
Use async for concurrent requests while respecting rate limits.
```python Python theme={null}
import asyncio
from perplexity import AsyncPerplexity
async def batch_search(queries, batch_size=3, delay_ms=1000):
async with AsyncPerplexity() as client:
results = []
for i in range(0, len(queries), batch_size):
batch = queries[i:i + batch_size]
batch_tasks = [
client.search.create(query=query, max_results=5)
for query in batch
]
batch_results = await asyncio.gather(*batch_tasks)
results.extend(batch_results)
# Add delay between batches
if i + batch_size < len(queries):
await asyncio.sleep(delay_ms / 1000)
return results
# Usage
queries = ["AI developments", "climate change", "space exploration"]
results = asyncio.run(batch_search(queries))
print(f"Processed {len(results)} searches")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
async function batchSearch(
queries: string[],
batchSize: number = 3,
delayMs: number = 1000
) {
const client = new Perplexity();
const results = [];
for (let i = 0; i < queries.length; i += batchSize) {
const batch = queries.slice(i, i + batchSize);
const batchPromises = batch.map(query =>
client.search.create({
query,
maxResults: 5
})
);
const batchResults = await Promise.all(batchPromises);
results.push(...batchResults);
// Add delay between batches
if (i + batchSize < queries.length) {
await new Promise(resolve => setTimeout(resolve, delayMs));
}
}
return results;
}
// Usage
const queries = ["AI developments", "climate change", "space exploration"];
const results = await batchSearch(queries);
console.log(`Processed ${results.length} searches`);
```
## Async Usage
For high-performance applications requiring concurrent requests, use the async client:
```python Python theme={null}
import asyncio
from perplexity import AsyncPerplexity
async def main():
async with AsyncPerplexity() as client:
# Concurrent searches for better performance
tasks = [
client.search.create(
query="artificial intelligence trends 2024",
max_results=5
),
client.search.create(
query="machine learning breakthroughs",
max_results=5
),
client.search.create(
query="deep learning applications",
max_results=5
)
]
results = await asyncio.gather(*tasks)
for i, search in enumerate(results):
print(f"Query {i+1} results:")
for result in search.results:
print(f" {result.title}: {result.url}")
print("---")
asyncio.run(main())
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
async function main() {
// Concurrent searches for better performance
const tasks = [
client.search.create({
query: "artificial intelligence trends 2024",
maxResults: 5
}),
client.search.create({
query: "machine learning breakthroughs",
maxResults: 5
}),
client.search.create({
query: "deep learning applications",
maxResults: 5
})
];
const results = await Promise.all(tasks);
results.forEach((search, i) => {
console.log(`Query ${i+1} results:`);
search.results.forEach(result => {
console.log(` ${result.title}: ${result.url}`);
});
console.log("---");
});
}
main();
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
const client = new Perplexity();
async function main() {
// Concurrent searches for better performance
const tasks = [
client.search.create({
query: "artificial intelligence trends 2024",
maxResults: 5
}),
client.search.create({
query: "machine learning breakthroughs",
maxResults: 5
}),
client.search.create({
query: "deep learning applications",
maxResults: 5
})
];
const results = await Promise.all(tasks);
results.forEach((search, i) => {
console.log(`Query ${i+1} results:`);
search.results.forEach(result => {
console.log(` ${result.title}: ${result.url}`);
});
console.log("---");
});
}
main();
```
### Advanced Async Patterns
#### Rate-Limited Concurrent Processing
For large-scale applications, implement controlled concurrency with rate limiting:
```python Python theme={null}
import asyncio
from perplexity import AsyncPerplexity
class SearchManager:
def __init__(self, max_concurrent=5, delay_between_batches=1.0):
self.max_concurrent = max_concurrent
self.delay_between_batches = delay_between_batches
self.semaphore = asyncio.Semaphore(max_concurrent)
async def search_single(self, client, query):
async with self.semaphore:
return await client.search.create(query=query, max_results=5)
async def search_many(self, queries):
async with AsyncPerplexity() as client:
tasks = [
self.search_single(client, query)
for query in queries
]
results = await asyncio.gather(*tasks, return_exceptions=True)
# Filter out exceptions and return successful results
successful_results = [
result for result in results
if not isinstance(result, Exception)
]
return successful_results
# Usage
async def main():
manager = SearchManager(max_concurrent=3)
queries = [
"AI research 2024",
"quantum computing advances",
"renewable energy innovations",
"biotechnology breakthroughs",
"space exploration updates"
]
results = await manager.search_many(queries)
print(f"Successfully processed {len(results)} out of {len(queries)} searches")
asyncio.run(main())
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
class SearchManager {
private maxConcurrent: number;
private delayBetweenBatches: number;
constructor(maxConcurrent: number = 5, delayBetweenBatches: number = 1000) {
this.maxConcurrent = maxConcurrent;
this.delayBetweenBatches = delayBetweenBatches;
}
async searchMany(queries: string[]) {
const client = new Perplexity();
const results = [];
// Process in batches to respect rate limits
for (let i = 0; i < queries.length; i += this.maxConcurrent) {
const batch = queries.slice(i, i + this.maxConcurrent);
const batchPromises = batch.map(query =>
client.search.create({ query, maxResults: 5 })
.catch(error => ({ error, query }))
);
const batchResults = await Promise.all(batchPromises);
// Filter out errors and collect successful results
const successfulResults = batchResults.filter(
result => !('error' in result)
);
results.push(...successfulResults);
// Add delay between batches
if (i + this.maxConcurrent < queries.length) {
await new Promise(resolve =>
setTimeout(resolve, this.delayBetweenBatches)
);
}
}
return results;
}
}
// Usage
async function main() {
const manager = new SearchManager(3, 1000);
const queries = [
"AI research 2024",
"quantum computing advances",
"renewable energy innovations",
"biotechnology breakthroughs",
"space exploration updates"
];
const results = await manager.searchMany(queries);
console.log(`Successfully processed ${results.length} out of ${queries.length} searches`);
}
main();
```
#### Error Handling in Async Operations
Implement robust error handling for async search operations:
```python Python theme={null}
import asyncio
import logging
from perplexity import AsyncPerplexity, APIStatusError, RateLimitError
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
async def resilient_search(client, query, max_retries=3):
for attempt in range(max_retries):
try:
result = await client.search.create(query=query, max_results=5)
logger.info(f"Search successful for: {query}")
return result
except RateLimitError as e:
if attempt < max_retries - 1:
delay = 2 ** attempt
logger.warning(f"Rate limited for '{query}', retrying in {delay}s")
await asyncio.sleep(delay)
else:
logger.error(f"Max retries exceeded for: {query}")
return None
except APIStatusError as e:
logger.error(f"API error for '{query}': {e}")
return None
except Exception as e:
logger.error(f"Unexpected error for '{query}': {e}")
return None
async def main():
async with AsyncPerplexity() as client:
queries = ["AI developments", "invalid query", "tech trends"]
tasks = [resilient_search(client, query) for query in queries]
results = await asyncio.gather(*tasks)
successful_results = [r for r in results if r is not None]
print(f"Successful searches: {len(successful_results)}/{len(queries)}")
asyncio.run(main())
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
async function resilientSearch(
client: Perplexity,
query: string,
maxRetries: number = 3
) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const result = await client.search.create({ query, maxResults: 5 });
console.log(`Search successful for: ${query}`);
return result;
} catch (error: any) {
if (error.constructor.name === 'RateLimitError') {
if (attempt < maxRetries - 1) {
const delay = 2 ** attempt * 1000;
console.warn(`Rate limited for '${query}', retrying in ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
console.error(`Max retries exceeded for: ${query}`);
return null;
}
} else {
console.error(`Error for '${query}':`, error.message);
return null;
}
}
}
return null;
}
async function main() {
const client = new Perplexity();
const queries = ["AI developments", "invalid query", "tech trends"];
const tasks = queries.map(query => resilientSearch(client, query));
const results = await Promise.all(tasks);
const successfulResults = results.filter(r => r !== null);
console.log(`Successful searches: ${successfulResults.length}/${queries.length}`);
}
main();
```
## Performance Optimization Tips
Request only the number of results you actually need. More results = longer response times.
```python theme={null}
# Good: Request only what you need
search = client.search.create(query="tech news", max_results=5)
# Avoid: Over-requesting results
search = client.search.create(query="tech news", max_results=50)
```
Implement caching for queries that don't need real-time results.
```python Python theme={null}
import time
from typing import Dict, Tuple, Optional
class SearchCache:
def __init__(self, ttl_seconds=3600): # 1 hour default
self.cache: Dict[str, Tuple[any, float]] = {}
self.ttl = ttl_seconds
def get(self, query: str) -> Optional[any]:
if query in self.cache:
result, timestamp = self.cache[query]
if time.time() - timestamp < self.ttl:
return result
else:
del self.cache[query]
return None
def set(self, query: str, result: any):
self.cache[query] = (result, time.time())
# Usage
cache = SearchCache(ttl_seconds=1800) # 30 minutes
def cached_search(client, query):
cached_result = cache.get(query)
if cached_result:
return cached_result
result = client.search.create(query=query)
cache.set(query, result)
return result
```
```typescript TypeScript theme={null}
class SearchCache {
private cache: Map = new Map();
private ttl: number;
constructor(ttlSeconds: number = 3600) { // 1 hour default
this.ttl = ttlSeconds * 1000; // Convert to milliseconds
}
get(query: string): any | null {
const cached = this.cache.get(query);
if (cached) {
if (Date.now() - cached.timestamp < this.ttl) {
return cached.result;
} else {
this.cache.delete(query);
}
}
return null;
}
set(query: string, result: any): void {
this.cache.set(query, { result, timestamp: Date.now() });
}
}
// Usage
const cache = new SearchCache(1800); // 30 minutes
async function cachedSearch(client: Perplexity, query: string) {
const cachedResult = cache.get(query);
if (cachedResult) {
return cachedResult;
}
const result = await client.search.create({ query });
cache.set(query, result);
return result;
}
```
## Related Resources
Get started with basic search functionality
Explore the full SDK capabilities for enhanced performance
Complete Search API documentation
# Sonar Search Context Size
Source: https://docs.perplexity.ai/guides/search-context-size-guide
The `search_context_size` parameter allows you to control how much search context is retrieved from the web during query resolution, letting you balance cost and comprehensiveness.
* Default `search_context_size` is `low`
* Selecting `"high"` increases search costs due to more extensive web retrieval. Use `"low"` when cost efficiency is critical.
## Overview
The `search_context_size` field—passed via the `web_search_options` object—determines how much search context is retrieved by the Sonar models. This setting can help you optimize for either:
* Cost savings with minimal search input (`low`)
* Comprehensive answers by maximizing retrieved information (`high`)
* A balance of both (`medium`)
This flexibility allows teams to tune their API usage to their budget and use case.
To enable this feature, include the web\_search\_options.search\_context\_size parameter in your request payload:
```bash theme={null}
"web_search_options": {
"search_context_size": "medium"
}
```
## Best Practices
**Choosing the Right Context Size**
* `low`: Best for short factual queries or when operating under strict token cost constraints.
* `medium`: The default and best suited for general use cases.
* `high`: Use for deep research, exploratory questions, or when citations and evidence coverage are critical.
**Cost Optimization**
* Selecting `low` or `medium` can significantly reduce overall token usage, especially at scale.
* Consider defaulting to `low` for high-volume endpoints and selectively upgrading to `high` for complex user prompts.
Combining with Other Filters
* You can use `search_context_size` alongside other features like `search_domain_filter` to further control the scope of search.
* Combining `medium` with a focused domain filter often gives a good tradeoff between quality and cost.
Performance Considerations
* Larger context sizes may slightly increase response latency due to more extensive search and reranking.
* If you’re batching queries or supporting real-time interfaces, test with different settings to balance user experience and runtime.
## Examples
**1. Minimal Search Context ("low")**
This option limits the search context retrieved for the model, reducing cost per request while still producing useful responses for simpler questions.
## Request
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"messages": [
{
"role": "system",
"content": "Be precise and concise."
},
{
"role": "user",
"content": "How many stars are there in our galaxy?"
}
],
"web_search_options": {
"search_context_size": "low"
}
}' | jq
```
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar",
messages=[
{"role": "system", "content": "Be precise and concise."},
{"role": "user", "content": "How many stars are there in our galaxy?"}
],
web_search_options={
"search_context_size": "low"
}
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar",
messages: [
{"role": "system", "content": "Be precise and concise."},
{"role": "user", "content": "How many stars are there in our galaxy?"}
],
web_search_options: {
"search_context_size": "low"
}
});
console.log(completion.choices[0].message.content);
```
**Pro-tip**: Use `low` when cost optimization is more important than answer completeness.
**2. Comprehensive Search Context ("high")**
This option maximizes the amount of search context used to answer the question, resulting in more thorough and nuanced responses.
## Request
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"messages": [
{
"role": "system",
"content": "Be precise and concise."
},
{
"role": "user",
"content": "Explain the economic causes of the 2008 financial crisis."
}
],
"web_search_options": {
"search_context_size": "high"
}
}' | jq
```
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar",
messages=[
{"role": "system", "content": "Be precise and concise."},
{"role": "user", "content": "Explain the economic causes of the 2008 financial crisis."}
],
web_search_options={
"search_context_size": "high"
}
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar",
messages: [
{"role": "system", "content": "Be precise and concise."},
{"role": "user", "content": "Explain the economic causes of the 2008 financial crisis."}
],
web_search_options: {
"search_context_size": "high"
}
});
console.log(completion.choices[0].message.content);
```
**Pro-tip**: Use `high` for research-heavy or nuanced queries where coverage matters more than cost.
⸻
# Sonar Web Search Control
Source: https://docs.perplexity.ai/guides/search-control-guide
Control when Sonar models search the web using the search classifier or by disabling search altogether.
## Overview
Sonar models provide powerful web search capabilities, but there are times when you want to control when and how searches are performed. Perplexity offers two main approaches for search control:
* **Search Classifier** - Let AI intelligently decide when to search based on the query context
* **Disable Search** - Turn off web search completely for specific requests
Search control is available across all Sonar models.
Pricing remains the same regardless of whether search is triggered or not. Search control features are designed for performance optimization and user experience, not cost reduction.
## Search Classifier
The search classifier is a trained model that automatically determines whether a web search is necessary based on the context and content of your query. This helps optimize performance and costs by only searching when beneficial.
### How It Works
The classifier analyzes your query and decides whether:
* **Search is needed** - For questions requiring current information, facts, or research
* **Search is unnecessary** - For creative tasks, math problems, or general knowledge that doesn't require real-time data
### When to Use Search Classifier
Use the search classifier when you want to:
* **Improve response speed** - Skip search for queries that don't benefit from it
* **Automatic intelligence** - Let AI decide the best approach for each query
* **Optimal user experience** - Ensure search is only used when it adds value
```python theme={null}
import requests
# API configuration
API_URL = "https://api.perplexity.ai/chat/completions"
API_KEY = "your-api-key-here"
headers = {
"accept": "application/json",
"authorization": f"Bearer {API_KEY}",
"content-type": "application/json"
}
# Query that benefits from search classifier
user_query = "What are the latest developments in quantum computing?"
payload = {
"model": "sonar-pro",
"messages": [{"role": "user", "content": user_query}],
"stream": False,
"enable_search_classifier": True
}
response = requests.post(API_URL, json=payload, headers=headers)
print(response.json())
```
```typescript theme={null}
interface ChatCompletionRequest {
model: string;
messages: Array<{role: string; content: string}>;
stream?: boolean;
enable_search_classifier?: boolean;
}
const API_URL = "https://api.perplexity.ai/chat/completions";
const API_KEY = "your-api-key-here";
const headers = {
"accept": "application/json",
"authorization": `Bearer ${API_KEY}`,
"content-type": "application/json"
};
// Query that benefits from search classifier
const userQuery = "What are the latest developments in quantum computing?";
const payload: ChatCompletionRequest = {
model: "sonar-pro",
messages: [{role: "user", content: userQuery}],
stream: false,
enable_search_classifier: true
};
fetch(API_URL, {
method: "POST",
headers: headers,
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log(data));
```
```bash theme={null}
curl -X POST "https://api.perplexity.ai/chat/completions" \
-H "accept: application/json" \
-H "authorization: Bearer $SONAR_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "sonar",
"messages": [
{
"role": "user",
"content": "What is 2+2?"
}
],
"stream": false,
"enable_search_classifier": true
}' | jq
```
### Search Classifier Examples
* "What happened in the stock market today?"
* "Latest news about renewable energy"
* "Current weather in San Francisco"
* "Recent research on machine learning"
* "What is 2 + 2?"
* "Write a creative story about a dragon"
* "Explain the concept of recursion"
* "Generate a business name for a bakery"
## Disabling Search Completely
For certain use cases, you may want to disable web search entirely. This is useful when:
* **Offline-like responses** - Get responses based only on training data
* **Creative tasks** - Focus on generation without external influence
* **Deterministic responses** - Ensure consistent outputs based only on training data
### Implementation
To disable search completely, set the `disable_search` parameter to `true`:
```python theme={null}
import requests
# API configuration
API_URL = "https://api.perplexity.ai/chat/completions"
API_KEY = "your-api-key-here"
headers = {
"accept": "application/json",
"authorization": f"Bearer {API_KEY}",
"content-type": "application/json"
}
# Query that doesn't need web search
user_query = "What is 2 + 2?"
payload = {
"model": "sonar-pro",
"messages": [{"role": "user", "content": user_query}],
"stream": False,
"disable_search": True
}
response = requests.post(API_URL, json=payload, headers=headers)
print(response.json())
```
```typescript theme={null}
interface ChatCompletionRequest {
model: string;
messages: Array<{role: string; content: string}>;
stream?: boolean;
disable_search?: boolean;
}
const API_URL = "https://api.perplexity.ai/chat/completions";
const API_KEY = "your-api-key-here";
const headers = {
"accept": "application/json",
"authorization": `Bearer ${API_KEY}`,
"content-type": "application/json"
};
// Query that doesn't need web search
const userQuery = "What is 2 + 2?";
const payload: ChatCompletionRequest = {
model: "sonar-pro",
messages: [{role: "user", content: userQuery}],
stream: false,
disable_search: true
};
fetch(API_URL, {
method: "POST",
headers: headers,
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log(data));
```
```bash theme={null}
curl -X POST "https://api.perplexity.ai/chat/completions" \
-H "accept: application/json" \
-H "authorization: Bearer your-api-key-here" \
-H "content-type: application/json" \
-d '{
"model": "sonar-pro",
"messages": [
{
"role": "user",
"content": "What is 2 + 2?"
}
],
"stream": false,
"disable_search": true
}'
```
When search is disabled, responses will be based solely on the model's training data and may not include the most current information.
## Comparison and Best Practices
### When to Use Each Approach
**Best for:**
* Mixed workloads with varying query types
* Performance optimization without manual intervention
* General-purpose applications
* Unknown query patterns
**Best for:**
* Creative content generation
* Mathematical computations
* Sensitive data processing
* Offline-like experiences
### Performance Considerations
**Search Classifier:** Variable response time depending on whether search is triggered
**Disabled Search:** Consistently faster responses since no search operations occur
**Search Classifier:** Provides current information when search is triggered
**Disabled Search:** Limited to training data cutoff date
## Complete Examples
### Search Classifier in Action
```python theme={null}
payload = {
"model": "sonar-pro",
"messages": [{"role": "user", "content": "Explain machine learning"}],
"enable_search_classifier": True
}
```
The classifier will likely skip search for this general concept explanation.
```python theme={null}
payload = {
"model": "sonar-pro",
"messages": [{"role": "user", "content": "Latest AI news this week"}],
"enable_search_classifier": True
}
```
The classifier will trigger search for this time-sensitive query.
### Creative Task with Disabled Search
Here's an example of using disabled search for creative content generation:
```python theme={null}
import requests
payload = {
"model": "sonar-pro",
"messages": [
{
"role": "user",
"content": "Write a short science fiction story about time travel"
}
],
"disable_search": True,
"temperature": 0.8
}
response = requests.post(
"https://api.perplexity.ai/chat/completions",
headers={
"authorization": "Bearer your-api-key-here",
"content-type": "application/json"
},
json=payload
)
```
## Troubleshooting
**Common causes:**
* API key doesn't have access to classifier features
* Using an unsupported model
* Incorrect parameter syntax
**Solutions:**
* Verify your API key permissions
* Ensure you're using a Sonar model
* Check parameter spelling: `enable_search_classifier`
This is expected behavior when search is disabled. The model can only use information from its training data.
**Solutions:**
* Re-enable search for queries requiring current information
* Use search classifier for automatic optimization
* Clearly document when search is disabled for your users
Start with the search classifier for most applications, then selectively disable search for specific use cases where you want guaranteed offline-like behavior.
# Search Date and Time Filters
Source: https://docs.perplexity.ai/guides/search-date-time-filters
The `search_after_date` and `search_before_date` parameters allow you to restrict search results to a specific publication date range. Only results with publication dates falling between these dates will be returned.
The `last_updated_after_filter` and `last_updated_before_filter` parameters allow you to filter by when content was last modified or updated, rather than when it was originally published.
The `search_recency_filter` parameter provides a convenient way to filter results by predefined time periods (e.g., "day", "week", "month", "year") relative to the current date.
Specific date filters must be provided in the "%m/%d/%Y" format (e.g., "3/1/2025"). Recency filters use predefined values like "day", "week", "month", or "year". All filters are optional—you may supply either specific dates or recency filters as needed.
## Overview
Date and time filters for the Search API allow you to control which search results are returned by limiting them to specific time periods. There are three types of date and time filters available:
### Publication Date Filters
The `search_after_date` and `search_before_date` parameters filter results based on when content was **originally created or published**. This is useful when you need to:
* Find content published within a specific timeframe
* Exclude outdated or overly recent publications
* Focus on content from a particular publication period
### Last Updated Date Filters
The `last_updated_after_filter` and `last_updated_before_filter` parameters filter results based on when content was **last modified or updated**. This is useful when you need to:
* Find recently updated or maintained content
* Exclude stale content that hasn't been updated recently
* Focus on content that has been refreshed within a specific period
### Search Recency Filter
The `search_recency_filter` parameter provides a simple way to filter results by predefined time periods relative to the current date. This is useful when you need to:
* Find content from the past day, week, month, or year
* Get recent results without specifying exact dates
* Quickly filter for timely information
**Available values:**
* `"day"` - Content from the past 24 hours
* `"week"` - Content from the past 7 days
* `"month"` - Content from the past 30 days
* `"year"` - Content from the past 365 days
**Important:** Publication filters use the original creation/publication date, last updated filters use the modification date, while recency filters use a relative time period from the current date.
To constrain search results by publication date:
```bash theme={null}
"search_after_date": "3/1/2025",
"search_before_date": "3/5/2025"
```
To constrain search results by last updated date:
```bash theme={null}
"last_updated_after_filter": "07/01/2025",
"last_updated_before_filter": "12/30/2025"
```
To constrain search results by recency:
```bash theme={null}
"search_recency_filter": "week"
```
These filters will be applied in addition to any other search parameters.
## Examples
**1. Limiting Results by Publication Date Range**
This example limits search results to content published between March 1, 2025, and March 5, 2025.
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
response = client.search(
query="latest AI developments",
max_results=10,
search_after_date="3/1/2025",
search_before_date="3/5/2025"
)
print(response)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const response = await client.search({
query: "latest AI developments",
max_results: 10,
search_after_date: "3/1/2025",
search_before_date: "3/5/2025"
});
console.log(response);
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "latest AI developments",
"max_results": 10,
"search_after_date": "3/1/2025",
"search_before_date": "3/5/2025"
}' | jq
```
**2. Filtering with a Single Publication Date Parameter**
If you only wish to restrict the results to those published on or after a specific date, include just the `search_after_date`:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
response = client.search(
query="tech news published after March 1, 2025",
max_results=10,
search_after_date="3/1/2025"
)
print(response)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const response = await client.search({
query: "tech news published after March 1, 2025",
max_results: 10,
search_after_date: "3/1/2025"
});
console.log(response);
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "tech news published after March 1, 2025",
"max_results": 10,
"search_after_date": "3/1/2025"
}' | jq
```
**3. Filtering by Last Updated Date Range**
This example limits search results to content that was last updated between July 1, 2025, and December 30, 2025. This is useful for finding recently maintained or refreshed content.
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
response = client.search(
query="recently updated tech articles",
max_results=10,
last_updated_after_filter="07/01/2025",
last_updated_before_filter="12/30/2025"
)
print(response)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const response = await client.search({
query: "recently updated tech articles",
max_results: 10,
last_updated_after_filter: "07/01/2025",
last_updated_before_filter: "12/30/2025"
});
console.log(response);
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "recently updated tech articles",
"max_results": 10,
"last_updated_after_filter": "07/01/2025",
"last_updated_before_filter": "12/30/2025"
}' | jq
```
**4. Using Search Recency Filter**
The `search_recency_filter` provides a convenient way to filter results by predefined time periods without specifying exact dates:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
response = client.search(
query="latest AI developments",
max_results=10,
search_recency_filter="week"
)
print(response)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const response = await client.search({
query: "latest AI developments",
max_results: 10,
search_recency_filter: "week"
});
console.log(response);
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "latest AI developments",
"max_results": 10,
"search_recency_filter": "week"
}' | jq
```
This example will return only content from the past 7 days, automatically calculated from the current date.
**5. Different Recency Filter Options**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Get content from the past day
day_response = client.search(
query="breaking tech news",
max_results=5,
search_recency_filter="day"
)
# Get content from the past month
month_response = client.search(
query="AI research developments",
max_results=10,
search_recency_filter="month"
)
# Get content from the past year
year_response = client.search(
query="major tech trends",
max_results=15,
search_recency_filter="year"
)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Get content from the past day
const dayResponse = await client.search({
query: "breaking tech news",
max_results: 5,
search_recency_filter: "day"
});
// Get content from the past month
const monthResponse = await client.search({
query: "AI research developments",
max_results: 10,
search_recency_filter: "month"
});
// Get content from the past year
const yearResponse = await client.search({
query: "major tech trends",
max_results: 15,
search_recency_filter: "year"
});
```
```bash cURL theme={null}
# Get content from the past day
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "breaking tech news",
"max_results": 5,
"search_recency_filter": "day"
}' | jq
# Get content from the past month
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "AI research developments",
"max_results": 10,
"search_recency_filter": "month"
}' | jq
```
## Parameter Reference
### `search_after_date`
* **Type**: String
* **Format**: "%m/%d/%Y" (e.g., "3/1/2025")
* **Description**: Filters search results to only include content published after this date
* **Optional**: Yes
* **Example**: `"search_after_date": "1/1/2025"`
### `search_before_date`
* **Type**: String
* **Format**: "%m/%d/%Y" (e.g., "3/1/2025")
* **Description**: Filters search results to only include content published before this date
* **Optional**: Yes
* **Example**: `"search_before_date": "12/31/2025"`
### `last_updated_after_filter`
* **Type**: String
* **Format**: "%m/%d/%Y" (e.g., "07/01/2025")
* **Description**: Filters search results to only include content last updated after this date
* **Optional**: Yes
* **Example**: `"last_updated_after_filter": "07/01/2025"`
### `last_updated_before_filter`
* **Type**: String
* **Format**: "%m/%d/%Y" (e.g., "12/30/2025")
* **Description**: Filters search results to only include content last updated before this date
* **Optional**: Yes
* **Example**: `"last_updated_before_filter": "12/30/2025"`
### `search_recency_filter`
* **Type**: String
* **Allowed Values**: "day", "week", "month", "year"
* **Description**: Filters search results to content from the specified time period relative to the current date
* **Optional**: Yes
* **Example**: `"search_recency_filter": "week"`
## Best Practices
**Date Format**
* Strict Format: Dates must match the "%m/%d/%Y" format exactly. For example, "3/1/2025" or "03/01/2025" is acceptable.
* Consistency: Use one or both date filters consistently based on your search needs. Combining both provides a clear range.
**Filter Selection**
* Choose the Right Filter Type: Use publication date filters (`search_after_date`/`search_before_date`) when you care about when content was originally created. Use last updated filters (`last_updated_after_filter`/`last_updated_before_filter`) when you need recently maintained content. Use recency filters (`search_recency_filter`) for quick, relative time filtering.
* Recency vs. Exact Dates: Use `search_recency_filter` for convenience when you want recent content (e.g., "past week"). Use specific date filters when you need precise control over the time range.
* Combining Filters: You can use both publication and last updated filters together to find content that meets both criteria (e.g., published in 2024 but updated recently). Note that `search_recency_filter` cannot be combined with specific date filters (`search_after_date`/`search_before_date` or `last_updated_after_filter`/`last_updated_before_filter`).
**Client-Side Validation**
* Regex Check: Validate date strings on the client side using a regex such as:
```bash theme={null}
date_regex='^(0?[1-9]|1[0-2])/(0?[1-9]|[12][0-9]|3[01])/[0-9]{4}$'
```
```python theme={null}
date_regex = r'^(0?[1-9]|1[0-2])/(0?[1-9]|[12]\d|3[01])/\d{4}$'
```
This ensures that dates conform to the required format before sending the request.
**Performance Considerations**
* Narrowing the Search: Applying date range filters typically reduces the number of results, which may improve response times and result relevance.
* Avoid Over-Restriction: Ensure that the date range is neither too narrow (limiting useful results) nor too broad (defeating the purpose of the filter).
## Advanced Usage Patterns
**Finding Breaking News**
Use the `search_recency_filter` with "day" to find the most recent breaking news:
```python theme={null}
response = client.search(
query="breaking news technology",
max_results=5,
search_recency_filter="day"
)
```
**Historical Research**
Use specific date ranges to research historical events or trends:
```python theme={null}
response = client.search(
query="AI developments",
max_results=20,
search_after_date="1/1/2023",
search_before_date="12/31/2023"
)
```
**Finding Recently Maintained Content**
Use last updated filters to find content that has been refreshed or maintained recently:
```python theme={null}
response = client.search(
query="React best practices",
max_results=10,
last_updated_after_filter="07/01/2025"
)
```
**Trend Analysis**
Compare different time periods by making multiple searches:
```python theme={null}
# Recent trends
recent = client.search(
query="machine learning trends",
search_recency_filter="month"
)
# Older trends for comparison
older = client.search(
query="machine learning trends",
search_after_date="1/1/2023",
search_before_date="1/31/2023"
)
```
## Error Handling
When using date filters, ensure proper error handling for invalid date formats:
```python Python theme={null}
from perplexity import Perplexity
import re
def validate_date_format(date_string):
pattern = r'^(0?[1-9]|1[0-2])/(0?[1-9]|[12]\d|3[01])/\d{4}$'
return bool(re.match(pattern, date_string))
def search_with_date_filter(query, after_date=None, before_date=None):
client = Perplexity()
# Validate date formats
if after_date and not validate_date_format(after_date):
raise ValueError(f"Invalid date format: {after_date}")
if before_date and not validate_date_format(before_date):
raise ValueError(f"Invalid date format: {before_date}")
try:
response = client.search(
query=query,
search_after_date=after_date,
search_before_date=before_date
)
return response
except Exception as e:
print(f"Search failed: {e}")
return None
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
function validateDateFormat(dateString: string): boolean {
const pattern = /^(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01])\/\d{4}$/;
return pattern.test(dateString);
}
async function searchWithDateFilter(
query: string,
afterDate?: string,
beforeDate?: string
) {
const client = new Perplexity();
// Validate date formats
if (afterDate && !validateDateFormat(afterDate)) {
throw new Error(`Invalid date format: ${afterDate}`);
}
if (beforeDate && !validateDateFormat(beforeDate)) {
throw new Error(`Invalid date format: ${beforeDate}`);
}
try {
const response = await client.search({
query,
search_after_date: afterDate,
search_before_date: beforeDate
});
return response;
} catch (error) {
console.error('Search failed:', error);
return null;
}
}
```
# Search Domain Filter
Source: https://docs.perplexity.ai/guides/search-domain-filter-guide
The `search_domain_filter` parameter allows you to limit search results to specific domains or exclude certain domains from search results. This supports domain-level filtering for precise content control.
You can add a maximum of 20 domains to the `search_domain_filter` list. The filter works in either allowlist mode (include only) or denylist mode (exclude), but not both simultaneously.
Domain filters allow you to specify which domains to include or exclude in search results. You can filter by specific domains, top-level domains (TLDs), or domain parts. You can specify up to 20 domains per request. Domains should be provided without the protocol (e.g., "nature.com" not "[https://nature.com](https://nature.com)").
## Overview
The domain filter for the Search API allows you to control which sources appear in your search results by limiting them to specific domains or excluding certain domains. This is particularly useful when you need to:
* Focus research on authoritative or trusted sources
* Filter out specific domains from search results
* Search within specific publication networks or organizations
* Build domain-specific search applications
* Conduct competitive research within specific industry domains
The `search_domain_filter` parameter accepts an array of domain strings. The filter operates in two modes:
* **Allowlist mode**: Include only the specified domains (no `-` prefix)
* **Denylist mode**: Exclude the specified domains (use `-` prefix)
```bash theme={null}
# Allowlist: Only search these domains
"search_domain_filter": ["nature.com", "science.org", "cell.com"]
# Denylist: Exclude these domains
"search_domain_filter": ["-reddit.com", "-pinterest.com", "-quora.com"]
```
## Filtering Capabilities
Domain filters support flexible matching across different domain components:
### Root Domain Filtering
Specify a root domain to match all content from that domain and its subdomains:
```bash theme={null}
"search_domain_filter": ["wikipedia.org"]
```
This will match:
* `en.wikipedia.org`
* `fr.wikipedia.org`
* `de.wikipedia.org`
* Any other Wikipedia language subdomain
### Top-Level Domain (TLD) Filtering
Filter by top-level domain to target specific categories of sites:
```bash theme={null}
"search_domain_filter": [".gov"]
```
This will match all government domains:
* `nasa.gov`
* `cdc.gov`
* `irs.gov`
* Any other `.gov` domain
TLD filtering is particularly useful for targeting specific types of organizations, such as `.gov` for government sites, `.edu` for educational institutions, or country-specific TLDs like `.uk` or `.ca`.
### Domain Part Filtering
Any part of a domain can be used as a filter. The system will match domains containing that component.
## Examples
**1. Allowlist Specific Domains**
This example limits search results to authoritative academic publishers:
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
response = client.search.create(
query="climate change research",
max_results=10,
search_domain_filter=[
"nature.com",
"science.org",
"cell.com"
]
)
for result in response.results:
print(f"{result.title}: {result.url}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const response = await client.search.create({
query: "climate change research",
maxResults: 10,
searchDomainFilter: [
"nature.com",
"science.org",
"cell.com"
]
});
for (const result of response.results) {
console.log(`${result.title}: ${result.url}`);
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "climate change research",
"max_results": 10,
"search_domain_filter": [
"nature.com",
"science.org",
"cell.com"
]
}' | jq
```
**2. Tech News Sources**
Search across major technology news websites:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
response = client.search.create(
query="latest tech trends 2025",
max_results=10,
search_domain_filter=[
"techcrunch.com",
"theverge.com",
"arstechnica.com",
"wired.com"
]
)
for result in response.results:
print(f"{result.title}")
print(f"Source: {result.url}")
print(f"Date: {result.date}")
print("---")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const response = await client.search.create({
query: "latest tech trends 2025",
maxResults: 10,
searchDomainFilter: [
"techcrunch.com",
"theverge.com",
"arstechnica.com",
"wired.com"
]
});
for (const result of response.results) {
console.log(`${result.title}`);
console.log(`Source: ${result.url}`);
console.log(`Date: ${result.date}`);
console.log("---");
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "latest tech trends 2025",
"max_results": 10,
"search_domain_filter": [
"techcrunch.com",
"theverge.com",
"arstechnica.com",
"wired.com"
]
}' | jq
```
**3. Government and Educational Sources (TLD Filtering)**
Use top-level domain filtering to search across all government or educational institutions:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Search all .gov and .edu domains
response = client.search.create(
query="climate change policy research",
max_results=15,
search_domain_filter=[
".gov",
".edu"
]
)
for result in response.results:
print(f"{result.title}")
print(f"Source: {result.url}")
print("---")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Search all .gov and .edu domains
const response = await client.search.create({
query: "climate change policy research",
maxResults: 15,
searchDomainFilter: [
".gov",
".edu"
]
});
for (const result of response.results) {
console.log(`${result.title}`);
console.log(`Source: ${result.url}`);
console.log("---");
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "climate change policy research",
"max_results": 15,
"search_domain_filter": [
".gov",
".edu"
]
}' | jq
```
**4. Wikipedia Across Languages (Subdomain Matching)**
Search across all Wikipedia language editions by specifying the root domain:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Matches en.wikipedia.org, fr.wikipedia.org, de.wikipedia.org, etc.
response = client.search.create(
query="quantum mechanics",
max_results=10,
search_domain_filter=["wikipedia.org"]
)
for result in response.results:
print(f"{result.title}")
print(f"URL: {result.url}")
print("---")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Matches en.wikipedia.org, fr.wikipedia.org, de.wikipedia.org, etc.
const response = await client.search.create({
query: "quantum mechanics",
maxResults: 10,
searchDomainFilter: ["wikipedia.org"]
});
for (const result of response.results) {
console.log(`${result.title}`);
console.log(`URL: ${result.url}`);
console.log("---");
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "quantum mechanics",
"max_results": 10,
"search_domain_filter": ["wikipedia.org"]
}' | jq
```
**5. Denylist Specific Domains**
This example shows how to exclude specific domains from search results by prefixing the domain name with a minus sign (`-`):
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Exclude social media and Q&A sites from search results
response = client.search.create(
query="latest advancements in renewable energy",
max_results=10,
search_domain_filter=[
"-pinterest.com",
"-reddit.com",
"-quora.com"
]
)
for result in response.results:
print(f"{result.title}: {result.url}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Exclude social media and Q&A sites from search results
const response = await client.search.create({
query: "latest advancements in renewable energy",
maxResults: 10,
searchDomainFilter: [
"-pinterest.com",
"-reddit.com",
"-quora.com"
]
});
for (const result of response.results) {
console.log(`${result.title}: ${result.url}`);
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "latest advancements in renewable energy",
"max_results": 10,
"search_domain_filter": [
"-pinterest.com",
"-reddit.com",
"-quora.com"
]
}' | jq
```
**6. Combining Domain Filter with Other Filters**
Domain filters work seamlessly with other search parameters for precise control:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Combine domain filter with date and language filters
response = client.search.create(
query="quantum computing breakthroughs",
max_results=20,
search_domain_filter=[
"nature.com",
"science.org",
"arxiv.org"
],
search_recency_filter="month",
search_language_filter=["en"]
)
for result in response.results:
print(f"{result.title}")
print(f"URL: {result.url}")
print(f"Date: {result.date}")
print("---")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Combine domain filter with date and language filters
const response = await client.search.create({
query: "quantum computing breakthroughs",
maxResults: 20,
searchDomainFilter: [
"nature.com",
"science.org",
"arxiv.org"
],
searchRecencyFilter: "month",
searchLanguageFilter: ["en"]
});
for (const result of response.results) {
console.log(`${result.title}`);
console.log(`URL: ${result.url}`);
console.log(`Date: ${result.date}`);
console.log("---");
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "quantum computing breakthroughs",
"max_results": 20,
"search_domain_filter": [
"nature.com",
"science.org",
"arxiv.org"
],
"search_recency_filter": "month",
"search_language_filter": ["en"]
}' | jq
```
## Parameter Reference
### `search_domain_filter`
* **Type**: Array of strings
* **Format**:
* Domain names without protocol (e.g., "example.com")
* Prefix with `-` for denylisting (e.g., "-reddit.com")
* **Description**: Filters search results to include or exclude content from specified domains
* **Optional**: Yes
* **Maximum**: 20 domains per request
* **Modes**:
* Allowlist mode: Include only specified domains (no `-` prefix)
* Denylist mode: Exclude specified domains (use `-` prefix)
* **Example**:
* Allowlist: `"search_domain_filter": ["nature.com", "science.org"]`
* Denylist: `"search_domain_filter": ["-reddit.com", "-pinterest.com"]`
## Domain Format Guidelines
**Correct Domain Formats:**
* `"nature.com"` - Root domain (matches nature.com and all subdomains)
* `"blog.example.com"` - Specific subdomain
* `"arxiv.org"` - Root domain (matches all subdomains)
* `".gov"` - Top-level domain (matches all .gov sites)
* `".edu"` - Top-level domain (matches all .edu sites)
* `".uk"` - Country-code TLD (matches all .uk sites)
* `"wikipedia.org"` - Matches en.wikipedia.org, fr.wikipedia.org, etc.
* `"-reddit.com"` - Exclude entire domain and all subdomains
* `"-pinterest.com"` - Exclude domain
* `"-.gov"` - Exclude all .gov domains
**Incorrect Domain Formats:**
* ❌ `"https://nature.com"` - Don't include protocol
* ❌ `"nature.com/"` - Don't include trailing slash
* ❌ `"nature.com/articles"` - Don't include path (path filtering coming soon)
* ❌ `"www.nature.com"` - Avoid www prefix (use root domain)
## Best Practices
### Domain Selection Strategy
* **Use Root Domains for Broad Coverage**: Specify root domains (e.g., "wikipedia.org") to match all subdomains automatically, including different language versions and regional sites.
* **Use TLDs for Categorical Filtering**: Target specific organization types with TLD filters like `.gov` for government, `.edu` for education, or `.org` for non-profits.
* **Be Specific When Needed**: Choose specific domains that are directly relevant to your search query to ensure high-quality results.
* **Quality Over Quantity**: Using fewer, highly relevant domains often produces better results than maximizing the 20-domain limit.
* **Consider Domain Authority**: Prioritize authoritative sources in your field for more reliable information.
* **Choose Your Mode**: Use either allowlist mode (include only) OR denylist mode (exclude), but not both in the same request. Denylisting is useful when you want broad search coverage but need to exclude specific low-quality or irrelevant sources.
### Locale and Regional Targeting
While domain filters don't directly filter by user location, you can target specific locales using:
* **Country-code TLDs**: Use filters like `.uk`, `.ca`, `.de`, `.jp` to target country-specific domains
* **Subdomain matching**: Specify regional subdomains when available (e.g., "uk.domain.com")
* **Combined approach**: Mix country TLDs with specific trusted domains for precise regional filtering
For international research, combine TLD filtering with the `search_language_filter` parameter to refine results by both location and language.
### Domain Selection
* **Use Trusted Sources**: Select a specific set of trusted sources you want to search within (e.g., academic research, official documentation).
* **Leverage TLD Filtering**: When researching topics that span many sites of the same type, use TLD filters to cast a wider net (e.g., `.gov` for policy research).
* **Focus on Quality**: Choose authoritative domains that consistently provide reliable information relevant to your queries.
### Client-Side Validation
Validate domain formats on the client side before sending requests:
```python Python theme={null}
import re
def validate_domain(domain):
"""Validate domain format including TLD filters."""
# TLD filter (e.g., .gov, .edu)
if domain.startswith('.'):
tld_pattern = r'^\.[a-zA-Z]{2,}$'
return bool(re.match(tld_pattern, domain))
# Standard domain validation pattern
pattern = r'^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'
return bool(re.match(pattern, domain))
def validate_domain_filter(domains):
"""Validate domain filter array."""
if len(domains) > 20:
raise ValueError("Maximum 20 domains allowed")
for domain in domains:
if not validate_domain(domain):
raise ValueError(f"Invalid domain format: {domain}")
return True
# Usage examples
try:
# Mix of regular domains and TLD filters
domains = ["nature.com", "science.org", ".gov", ".edu"]
validate_domain_filter(domains)
response = client.search.create(
query="research topic",
search_domain_filter=domains
)
except ValueError as e:
print(f"Validation error: {e}")
```
```typescript TypeScript theme={null}
function validateDomain(domain: string): boolean {
// TLD filter (e.g., .gov, .edu)
if (domain.startsWith('.')) {
const tldPattern = /^\.[a-zA-Z]{2,}$/;
return tldPattern.test(domain);
}
// Standard domain validation pattern
const pattern = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
return pattern.test(domain);
}
function validateDomainFilter(domains: string[]): void {
if (domains.length > 20) {
throw new Error("Maximum 20 domains allowed");
}
for (const domain of domains) {
if (!validateDomain(domain)) {
throw new Error(`Invalid domain format: ${domain}`);
}
}
}
// Usage examples
try {
// Mix of regular domains and TLD filters
const domains = ["nature.com", "science.org", ".gov", ".edu"];
validateDomainFilter(domains);
const response = await client.search.create({
query: "research topic",
searchDomainFilter: domains
});
} catch (error) {
console.error("Validation error:", error.message);
}
```
### Performance Considerations
* **Result Availability**: Narrowing to specific domains may reduce the number of available results. Be prepared to handle cases where fewer results are returned than requested.
* **Domain Coverage**: Ensure the domains you specify actually contain content relevant to your query. Overly restrictive filters may return zero results.
* **Combination Effects**: Domain filters combined with other restrictive filters (date, language) can significantly reduce result counts.
For best results, combine domain filtering with other filters like `search_recency_filter` or `search_language_filter` to narrow down your search to highly relevant, timely content from your target sources. Use TLD filters like `.gov` or `.edu` when you need broad coverage across an entire category of authoritative sites.
# Sonar Domain Filter Guide
Source: https://docs.perplexity.ai/guides/search-domain-filters
The `search_domain_filter` feature allows you to limit search results to specific domains/URLs or exclude certain domains/URLs from search results. This supports both broad domain-level filtering and granular URL-level filtering for precise content control.
You can add a maximum of 20 domains or URLs to the `search_domain_filter` list. The filter works in either allowlist mode (include only) or denylist mode (exclude), but not both simultaneously.
Before adding URLs to your allowlist, test that they are accessible via the API by making a sample request. URLs that are blocked, require authentication, or have access restrictions may not return search results, which can significantly impact response quality when using allowlist mode.
## Overview
The `search_domain_filter` parameter allows you to control which websites are included in or excluded from the search results used by the Sonar models. This feature is particularly useful when you want to:
* Restrict search results to trusted sources
* Filter out specific domains from search results
* Focus research on particular websites
Enabling domain filtering can be done by adding a `search_domain_filter` field in the request:
```
"search_domain_filter": [
"",
"",
...
]
```
Each entry in the list can be a domain name or a specific URL. The filter operates in two modes:
* **Allowlist mode**: Include only the specified domains/URLs (no `-` prefix)
* **Denylist mode**: Exclude the specified domains/URLs (use `-` prefix)
## Filtering Capabilities
### Domain-Level Filtering
Filter entire domains for broad control:
```json theme={null}
// Allowlist: Only search these domains
"search_domain_filter": ["wikipedia.org", "github.com", "stackoverflow.com"]
// Denylist: Exclude these domains
"search_domain_filter": ["-reddit.com", "-pinterest.com", "-quora.com"]
```
### URL-Level Filtering
Target specific pages or sections for granular control:
```json theme={null}
// Allowlist: Only search these specific URLs
"search_domain_filter": [
"https://en.wikipedia.org/wiki/Chess",
"https://stackoverflow.com/questions/tagged/python",
"https://docs.python.org/3/tutorial/"
]
// Denylist: Exclude these specific URLs
"search_domain_filter": [
"-https://en.wikipedia.org/wiki/FIDE_rankings",
"-https://reddit.com/r/politics"
]
```
This granular approach allows you to:
* Include or exclude specific Wikipedia articles while keeping/removing the rest
* Target particular sections of large sites like Stack Overflow or Reddit
* Filter specific documentation pages or subdirectories
## Examples
### 1. Allowlist Specific Domains
This example shows how to limit search results to only include content from specific domains.
**Request**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me about the James Webb Space Telescope discoveries."}
],
search_domain_filter=[
"nasa.gov",
"wikipedia.org",
"space.com"
]
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar",
messages: [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me about the James Webb Space Telescope discoveries."}
],
search_domain_filter: [
"nasa.gov",
"wikipedia.org",
"space.com"
]
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me about the James Webb Space Telescope discoveries."}
],
"search_domain_filter": [
"nasa.gov",
"wikipedia.org",
"space.com"
]
}' | jq
```
**Best Practice**: Use simple domain names (e.g., `wikipedia.org`) without additional elements like `https://` or `www.` prefixes.
### 2. Denylist Specific Domains
This example shows how to exclude specific domains from search results by prefixing the domain name with a minus sign (`-`).
**Request**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are the latest advancements in renewable energy?"}
],
search_domain_filter=[
"-pinterest.com",
"-reddit.com",
"-quora.com"
]
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar",
messages: [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are the latest advancements in renewable energy?"}
],
search_domain_filter: [
"-pinterest.com",
"-reddit.com",
"-quora.com"
]
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What are the latest advancements in renewable energy?"}
],
"search_domain_filter": [
"-pinterest.com",
"-reddit.com",
"-quora.com"
]
}' | jq
```
**Best Practice**: Use simple domain names with a minus prefix (e.g., `-pinterest.com`) to exclude domains from search results.
### 3. URL-Level Filtering for Granular Control
This example shows how to exclude specific pages while keeping the rest of the domain accessible.
**Request**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me about chess rankings and tournaments."}
],
search_domain_filter=[
"-https://en.wikipedia.org/wiki/FIDE_rankings"
]
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me about chess rankings and tournaments."}
],
search_domain_filter: [
"-https://en.wikipedia.org/wiki/FIDE_rankings"
]
});
console.log(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me about chess rankings and tournaments."}
],
"search_domain_filter": [
"-https://en.wikipedia.org/wiki/FIDE_rankings"
]
}' | jq
```
**Result**: This will search all websites except the specific FIDE rankings Wikipedia page, while keeping all other Wikipedia content accessible.
**Alternative - Allowlist specific URLs only:**
```json theme={null}
"search_domain_filter": [
"https://en.wikipedia.org/wiki/Chess",
"https://en.wikipedia.org/wiki/World_Chess_Championship",
"https://chess.com"
]
```
This would only search those three specific sources and ignore all other websites.
## Best Practices
### Domain and URL Specification
* **Domain filtering**: Use simple domain names (e.g., `example.com`) without protocol prefixes for broad filtering.
* **URL filtering**: Use complete URLs including protocol (e.g., `https://en.wikipedia.org/wiki/FIDE_rankings`) for specific page targeting.
* **Subdomain behavior**: Using a main domain (e.g., `nytimes.com`) will filter all subdomains as well.
* **Granular control**: URL-level filtering allows you to include/exclude specific pages while keeping the rest of the domain.
### Filter Optimization
* **Be specific**: Use domains/URLs that are most relevant to your query to get the best results.
* **Choose your mode**: Use either allowlist mode (include only) OR denylist mode (exclude), but not both in the same request.
* **Limit filter size**: You can add up to 20 domains or URLs. Using fewer, more targeted entries often yields better results.
* **URL precision**: Use full URLs (including `https://`) when targeting specific pages for maximum precision.
### Performance Considerations
* Adding domain filters may slightly increase response time as the search engine needs to apply additional filtering.
* Overly restrictive domain filters might result in fewer search results, potentially affecting the quality of the response.
# Search Language Filter
Source: https://docs.perplexity.ai/guides/search-language-filter
The `search_language_filter` parameter allows you to filter search results by language using ISO 639-1 language codes. Only results in the specified languages will be returned.
Language codes must be valid 2-letter ISO 639-1 codes (e.g., "en", "ru", "fr"). You can filter by up to 10 languages per request.
## Overview
The language filter for the Search API allows you to control which search results are returned by limiting them to specific languages. This is particularly useful when you need to:
* Search for content in specific languages
* Conduct multilingual research across multiple languages
* Focus on regional content in local languages
* Build language-specific applications or features
The `search_language_filter` parameter accepts an array of ISO 639-1 language codes and returns only results that match those languages.
To filter search results by language:
```bash theme={null}
"search_language_filter": ["en", "fr", "de"]
```
This filter will be applied in addition to any other search parameters.
## Examples
**1. Single Language Filter**
This example limits search results to English language content only.
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
response = client.search.create(
query="artificial intelligence",
max_results=10,
search_language_filter=["en"]
)
for result in response.results:
print(f"{result.title}: {result.url}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const response = await client.search.create({
query: "artificial intelligence",
maxResults: 10,
searchLanguageFilter: ["en"]
});
for (const result of response.results) {
console.log(`${result.title}: ${result.url}`);
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "artificial intelligence",
"max_results": 10,
"search_language_filter": ["en"]
}' | jq
```
**2. Multiple Language Filter**
Search across multiple languages to gather diverse perspectives or multilingual content:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Search for content in English, French, and German
response = client.search.create(
query="renewable energy innovations",
max_results=15,
search_language_filter=["en", "fr", "de"]
)
for result in response.results:
print(f"{result.title}: {result.url}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Search for content in English, French, and German
const response = await client.search.create({
query: "renewable energy innovations",
maxResults: 15,
searchLanguageFilter: ["en", "fr", "de"]
});
for (const result of response.results) {
console.log(`${result.title}: ${result.url}`);
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "renewable energy innovations",
"max_results": 15,
"search_language_filter": ["en", "fr", "de"]
}' | jq
```
**3. Regional Language Search**
Focus on content from specific regions by using their local languages:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Search for Asian market news in Chinese, Japanese, and Korean
response = client.search.create(
query="technology market trends",
max_results=10,
search_language_filter=["zh", "ja", "ko"]
)
# Search for European tech news in multiple European languages
eu_response = client.search.create(
query="tech startups",
max_results=10,
search_language_filter=["en", "de", "fr", "es", "it"]
)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Search for Asian market news in Chinese, Japanese, and Korean
const response = await client.search.create({
query: "technology market trends",
maxResults: 10,
searchLanguageFilter: ["zh", "ja", "ko"]
});
// Search for European tech news in multiple European languages
const euResponse = await client.search.create({
query: "tech startups",
maxResults: 10,
searchLanguageFilter: ["en", "de", "fr", "es", "it"]
});
```
```bash cURL theme={null}
# Search for Asian market news
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "technology market trends",
"max_results": 10,
"search_language_filter": ["zh", "ja", "ko"]
}' | jq
```
**4. Combining with Other Filters**
Language filters work seamlessly with other search parameters for precise control:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Combine language filter with date and domain filters
response = client.search.create(
query="climate change research",
max_results=20,
search_language_filter=["en", "de"],
search_domain_filter=["nature.com", "science.org"],
search_recency_filter="month"
)
for result in response.results:
print(f"{result.title}")
print(f"URL: {result.url}")
print(f"Date: {result.date}")
print("---")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Combine language filter with date and domain filters
const response = await client.search.create({
query: "climate change research",
maxResults: 20,
searchLanguageFilter: ["en", "de"],
searchDomainFilter: ["nature.com", "science.org"],
searchRecencyFilter: "month"
});
for (const result of response.results) {
console.log(`${result.title}`);
console.log(`URL: ${result.url}`);
console.log(`Date: ${result.date}`);
console.log("---");
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer $PERPLEXITY_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "climate change research",
"max_results": 20,
"search_language_filter": ["en", "de"],
"search_domain_filter": ["nature.com", "science.org"],
"search_recency_filter": "month"
}' | jq
```
## Parameter Reference
### `search_language_filter`
* **Type**: Array of strings
* **Format**: ISO 639-1 language codes (2 lowercase letters)
* **Description**: Filters search results to only include content in the specified languages
* **Optional**: Yes
* **Maximum**: 10 language codes per request
* **Example**: `"search_language_filter": ["en", "fr", "de"]`
## Common Language Codes
Here's a comprehensive list of frequently used ISO 639-1 language codes:
| Language | Code | Language | Code |
| ---------- | ---- | ---------- | ---- |
| English | `en` | Portuguese | `pt` |
| Spanish | `es` | Dutch | `nl` |
| French | `fr` | Polish | `pl` |
| German | `de` | Swedish | `sv` |
| Italian | `it` | Norwegian | `no` |
| Russian | `ru` | Danish | `da` |
| Chinese | `zh` | Finnish | `fi` |
| Japanese | `ja` | Czech | `cs` |
| Korean | `ko` | Hungarian | `hu` |
| Arabic | `ar` | Greek | `el` |
| Hindi | `hi` | Turkish | `tr` |
| Bengali | `bn` | Hebrew | `he` |
| Indonesian | `id` | Thai | `th` |
| Vietnamese | `vi` | Ukrainian | `uk` |
For a complete list of ISO 639-1 language codes, see the [ISO 639-1 standard](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
## Best Practices
### Language Code Validation
* **Use Valid Codes**: Always use valid 2-letter ISO 639-1 codes. Invalid codes will result in an API error.
* **Lowercase Only**: Language codes must be lowercase (e.g., "en" not "EN").
* **Client-Side Validation**: Validate language codes on the client side using a regex pattern:
```python Python theme={null}
import re
def validate_language_code(code):
pattern = r'^[a-z]{2}$'
return bool(re.match(pattern, code))
def validate_language_filters(codes):
if len(codes) > 10:
raise ValueError("Maximum 10 language codes allowed")
for code in codes:
if not validate_language_code(code):
raise ValueError(f"Invalid language code: {code}")
return True
# Usage
try:
codes = ["en", "fr", "de"]
validate_language_filters(codes)
response = client.search.create(
query="technology news",
search_language_filter=codes
)
except ValueError as e:
print(f"Validation error: {e}")
```
```typescript TypeScript theme={null}
function validateLanguageCode(code: string): boolean {
const pattern = /^[a-z]{2}$/;
return pattern.test(code);
}
function validateLanguageFilters(codes: string[]): void {
if (codes.length > 10) {
throw new Error("Maximum 10 language codes allowed");
}
for (const code of codes) {
if (!validateLanguageCode(code)) {
throw new Error(`Invalid language code: ${code}`);
}
}
}
// Usage
try {
const codes = ["en", "fr", "de"];
validateLanguageFilters(codes);
const response = await client.search.create({
query: "technology news",
searchLanguageFilter: codes
});
} catch (error) {
console.error("Validation error:", error.message);
}
```
### Strategic Language Selection
* **Be Specific**: Choose languages that are most relevant to your research or application needs.
* **Consider Your Audience**: Select languages that match your target audience's preferences.
* **Regional Relevance**: Combine language filters with geographic filters (`country` parameter) for better regional targeting.
* **Content Availability**: Some topics may have limited content in certain languages. Start broad and narrow down as needed.
### Performance Considerations
* **Filter Size**: While you can specify up to 10 languages, using fewer languages may improve response times.
* **Result Quality**: More languages mean a broader search scope, which can dilute result relevance. Be strategic about which languages to include.
* **Combination Effects**: Language filters combined with other restrictive filters (domain, date) may significantly reduce the number of results.
## Advanced Usage Patterns
### Multilingual Research
Conduct comprehensive research by searching across multiple languages:
```python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Research a global topic in multiple languages
languages = [
["en"], # English-speaking countries
["zh", "ja"], # East Asia
["es", "pt"], # Latin America and Iberia
["fr", "de", "it"] # Western Europe
]
results_by_region = {}
for lang_group in languages:
response = client.search.create(
query="sustainable development goals progress",
max_results=10,
search_language_filter=lang_group
)
results_by_region[", ".join(lang_group)] = response.results
# Analyze results by language/region
for region, results in results_by_region.items():
print(f"Results in {region}: {len(results)} found")
```
### Content Localization Research
Find examples and references in target languages for localization projects:
```python theme={null}
# Find product reviews in target markets
target_languages = ["ja", "ko", "zh"] # Asian markets
response = client.search.create(
query="smartphone reviews 2024",
max_results=15,
search_language_filter=target_languages,
search_recency_filter="month"
)
```
### Academic Research Across Languages
Access scholarly content in different languages:
```python theme={null}
# Search for research papers in multiple languages
response = client.search.create(
query="quantum computing algorithms",
max_results=20,
search_language_filter=["en", "de", "fr", "ru"],
search_domain_filter=["arxiv.org", "nature.com", "science.org"]
)
```
### News Monitoring by Language
Track news stories across different language regions:
```python theme={null}
# Monitor breaking news in different languages
news_queries = {
"English": ["en"],
"Chinese": ["zh"],
"Spanish": ["es"],
"Arabic": ["ar"]
}
for region, langs in news_queries.items():
response = client.search.create(
query="breaking news technology",
max_results=5,
search_language_filter=langs,
search_recency_filter="day"
)
print(f"{region} News: {len(response.results)} articles")
```
## Error Handling
When using language filters, implement proper error handling for validation issues:
```python Python theme={null}
from perplexity import Perplexity, BadRequestError
client = Perplexity()
def safe_language_search(query, languages):
"""
Perform a language-filtered search with error handling.
"""
try:
# Validate language codes
if not isinstance(languages, list):
raise ValueError("Languages must be provided as a list")
if len(languages) > 10:
raise ValueError("Maximum 10 language codes allowed")
# Validate each code format
for lang in languages:
if not isinstance(lang, str) or len(lang) != 2 or not lang.islower():
raise ValueError(f"Invalid language code format: {lang}")
# Perform search
response = client.search.create(
query=query,
search_language_filter=languages,
max_results=10
)
return response
except ValueError as e:
print(f"Validation error: {e}")
return None
except BadRequestError as e:
print(f"API error: {e.message}")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
# Usage
results = safe_language_search(
"artificial intelligence",
["en", "fr", "de"]
)
if results:
print(f"Found {len(results.results)} results")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
async function safeLanguageSearch(
query: string,
languages: string[]
): Promise {
try {
// Validate language codes
if (!Array.isArray(languages)) {
throw new Error("Languages must be provided as an array");
}
if (languages.length > 10) {
throw new Error("Maximum 10 language codes allowed");
}
// Validate each code format
for (const lang of languages) {
if (typeof lang !== 'string' ||
lang.length !== 2 ||
lang !== lang.toLowerCase()) {
throw new Error(`Invalid language code format: ${lang}`);
}
}
// Perform search
const response = await client.search.create({
query,
searchLanguageFilter: languages,
maxResults: 10
});
return response;
} catch (error) {
if (error instanceof Perplexity.BadRequestError) {
console.error("API error:", error.message);
} else if (error instanceof Error) {
console.error("Error:", error.message);
}
return null;
}
}
// Usage
const results = await safeLanguageSearch(
"artificial intelligence",
["en", "fr", "de"]
);
if (results) {
console.log(`Found ${results.results.length} results`);
}
```
For best results, combine language filtering with other filters like `search_domain_filter` or `search_recency_filter` to narrow down your search to highly relevant, timely content in your target languages.
# Perplexity Search API
Source: https://docs.perplexity.ai/guides/search-quickstart
Access real-time web search results with Perplexity's Search API. Get ranked results, domain filtering, multi-query search, and content extraction for developers.
## Overview
Test search queries and parameters in real time, **no API key required**.
Perplexity's Search API provides developers with real-time access to ranked web search results from a continuously refreshed index. Unlike traditional search APIs, Perplexity returns structured results with advanced filtering by domain, language, and region.
Use the Search API when you need raw, ranked web results with control over sources, regions, and extracted content. For LLM-generated summaries, use our [Sonar models](/getting-started/quickstart).
We recommend using our [official SDKs](/guides/perplexity-sdk) for a more convenient and type-safe way to interact with the Search API.
## Installation
Install the SDK for your preferred language:
```bash Python theme={null}
pip install perplexityai
```
```bash TypeScript/JavaScript theme={null}
npm install @perplexity-ai/perplexity_ai
```
## Authentication
Set your API key as an environment variable. The SDK will automatically read it:
```bash theme={null}
export PERPLEXITY_API_KEY="your_api_key_here"
```
```powershell theme={null}
setx PERPLEXITY_API_KEY "your_api_key_here"
```
Or use a `.env` file in your project:
```bash .env theme={null}
PERPLEXITY_API_KEY=your_api_key_here
```
All SDK examples below automatically use the `PERPLEXITY_API_KEY` environment variable. You can also pass the key explicitly if needed.
## Basic Usage
Start with a basic search query to get relevant web results. See the [API Reference](/api-reference/search-post) for complete parameter documentation.
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
search = client.search.create(
query="latest AI developments 2024",
max_results=5,
max_tokens_per_page=2048
)
for result in search.results:
print(f"{result.title}: {result.url}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const search = await client.search.create({
query: "latest AI developments 2024",
maxResults: 5,
maxTokensPerPage: 2048
});
for (const result of search.results) {
console.log(`${result.title}: ${result.url}`);
}
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
const client = new Perplexity();
async function main() {
const search = await client.search.create({
query: "latest AI developments 2024",
maxResults: 5,
maxTokensPerPage: 2048
});
for (const result of search.results) {
console.log(`${result.title}: ${result.url}`);
}
}
main();
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "latest AI developments 2024",
"max_results": 5,
"max_tokens_per_page": 2048
}' | jq
```
```json theme={null}
{
"results": [
{
"title": "2024: A year of extraordinary progress and advancement in AI - Google Blog",
"url": "https://blog.google/technology/ai/2024-ai-extraordinary-progress-advancement/",
"snippet": "## Relentless innovation in models, products and technologies\n\n2024 was a year of experimenting, fast shipping, and putting our latest technologies in the hands of developers.\n\nIn December 2024, we released the first models in our Gemini 2.0 experimental series — AI models designed for the agentic era. First out of the gate was Gemini 2.0 Flash, our workhorse model, followed by prototypes from the frontiers of our agentic research including: an updated Project Astra, which explores the capabilities of a universal AI assistant; Project Mariner, an early prototype capable of taking actions in Chrome as an experimental extension; and Jules, an AI-powered code agent. We're looking forward to bringing Gemini 2.0’s powerful capabilities to our flagship products — in Search, we've already started testing in AI Overviews, which are now used by over a billion people to ask new types of questions.\n\nWe also released Deep Research, a new agentic feature in Gemini Advanced that saves people hours of research work by creating and executing multi-step plans for finding answers to complicated questions; and introduced Gemini 2.0 Flash Thinking Experimental, an experimental model that explicitly shows its thoughts.\n\nThese advances followed swift progress earlier in the year, from incorporating Gemini's capabilities into more Google products to the release of Gemini 1.5 Pro and Gemini 1.5 Flash — a model optimized for speed and efficiency. 1.5 Flash's compact size made it more cost-efficient to serve, and in 2024 it became our most popular model for developers.... ## The architecture of intelligence: advances in robotics, hardware and computing\n\nAs our multimodal models become more capable and gain a better understanding of the world and its physics, they are making possible incredible new advances in robotics and bringing us closer to our goal of ever-more capable and helpful robots.\n\nWith ALOHA Unleashed, our robot learned to tie a shoelace, hang a shirt, repair another robot, insert a gear and even clean a kitchen.\n\nAt the beginning of the year, we introduced AutoRT, SARA-RT and RT-Trajectory, extensions of our Robotics Transformers work intended to help robots better understand and navigate their environments, and make decisions faster. We also published ALOHA Unleashed, a breakthrough in teaching robots on how to use two robotic arms in coordination, and DemoStart, which uses a reinforcement learning algorithm to improve real-world performance on a multi-fingered robotic hand by using simulations.\n\nRobotic Transformer 2 (RT-2) is a novel vision-language-action model that learns from both web and robotics data.\n\nBeyond robotics, our AlphaChip reinforcement learning method for accelerating and improving chip floorplanning is transforming the design process for chips found in data centers, smartphones and more. To accelerate adoption of these techniques, we released a pre-trained checkpoint to enable external parties to more easily make use of the AlphaChip open source release for their own chip designs. And we made Trillium, our sixth-generation and most performant TPU to date, generally available to Google Cloud customers. Advances in computer chips have accelerated AI. And now, AI can return the favor.... We are exploring how machine learning can help medical fields struggling with access to imaging expertise, such as radiology, dermatology and pathology. In the past year, we released two research tools, Derm Foundation and Path Foundation, that can help develop models for diagnostic tasks, image indexing and curation and biomarker discovery and validation. We collaborated with physicians at Stanford Medicine on an open-access, inclusive Skin Condition Image Network (SCIN) dataset. And we unveiled CT Foundation, a medical imaging embedding tool used for rapidly training models for research.\n\nWith regard to learning, we explored new generative AI tools to support educators and learners. We introduced LearnLM, our new family of models fine-tuned for learning and used it to enhance learning experiences in products like Search, YouTube and Gemini; a recent report showed LearnLM outperformed other leading AI models. We also made it available to developers as an experimental model in AI Studio. Our new conversational learning companion, LearnAbout, uses AI to help you dive deeper into any topic you're curious about, while Illuminate lets you turn content into engaging AI-generated audio discussions.\n\nIn the fields of disaster forecasting and preparedness, we announced several breakthroughs. We introduced GenCast, our new high-resolution AI ensemble model, which improves day-to-day weather and extreme events forecasting across all possible weather trajectories. We also introduced our NeuralGCM model, able to simulate over 70,000 days of the atmosphere in the time it would take a physics-based model to simulate only 19 days. And GraphCast won the 2024 MacRobert Award for engineering innovation.",
"date": "2025-01-23",
"last_updated": "2025-09-25"
},
{
"title": "The 2025 AI Index Report | Stanford HAI",
"url": "https://hai.stanford.edu/ai-index/2025-ai-index-report",
"snippet": "Read the translation\n\nIn 2023, researchers introduced new benchmarks—MMMU, GPQA, and SWE-bench—to test the limits of advanced AI systems. Just a year later, performance sharply increased: scores rose by 18.8, 48.9, and 67.3 percentage points on MMMU, GPQA, and SWE-bench, respectively. Beyond benchmarks, AI systems made major strides in generating high-quality video, and in some settings, language model agents even outperformed humans in programming tasks with limited time budgets.\n\nFrom healthcare to transportation, AI is rapidly moving from the lab to daily life. In 2023, the FDA approved 223 AI-enabled medical devices, up from just six in 2015. On the roads, self-driving cars are no longer experimental: Waymo, one of the largest U.S. operators, provides over 150,000 autonomous rides each week, while Baidu's affordable Apollo Go robotaxi fleet now serves numerous cities across China.\n\nIn 2024, U.S. private AI investment grew to $109.1 billion—nearly 12 times China's $9.3 billion and 24 times the U.K.'s $4.5 billion. Generative AI saw particularly strong momentum, attracting $33.9 billion globally in private investment—an 18.7% increase from 2023. AI business usage is also accelerating: 78% of organizations reported using AI in 2024, up from 55% the year before. Meanwhile, a growing body of research confirms that AI boosts productivity and, in most cases, helps narrow skill gaps across the workforce.... In 2024, U.S.-based institutions produced 40 notable AI models, significantly outpacing China's 15 and Europe's three. While the U.S. maintains its lead in quantity, Chinese models have rapidly closed the quality gap: performance differences on major benchmarks such as MMLU and HumanEval shrank from double digits in 2023 to near parity in 2024. Meanwhile, China continues to lead in AI publications and patents. At the same time, model development is increasingly global, with notable launches from regions such as the Middle East, Latin America, and Southeast Asia.\n\nAI-related incidents are rising sharply, yet standardized RAI evaluations remain rare among major industrial model developers. However, new benchmarks like HELM Safety, AIR-Bench, and FACTS offer promising tools for assessing factuality and safety. Among companies, a gap persists between recognizing RAI risks and taking meaningful action. In contrast, governments are showing increased urgency: In 2024, global cooperation on AI governance intensified, with organizations including the OECD, EU, U.N., and African Union releasing frameworks focused on transparency, trustworthiness, and other core responsible AI principles.\n\nIn countries like China (83%), Indonesia (80%), and Thailand (77%), strong majorities see AI products and services as more beneficial than harmful. In contrast, optimism remains far lower in places like Canada (40%), the United States (39%), and the Netherlands (36%). Still, sentiment is shifting: since 2022, optimism has grown significantly in several previously skeptical countries—including Germany (+10%), France (+10%), Canada (+8%), Great Britain (+8%), and the United States (+4%).... Driven by increasingly capable small models, the inference cost for a system performing at the level of GPT-3.5 dropped over 280-fold between November 2022 and October 2024. At the hardware level, costs have declined by 30% annually, while energy efficiency has improved by 40% each year. Open-weight models are also closing the gap with closed models, reducing the performance difference from 8% to just 1.7% on some benchmarks in a single year. Together, these trends are rapidly lowering the barriers to advanced AI.\n\nIn 2024, U.S. federal agencies introduced 59 AI-related regulations—more than double the number in 2023—and issued by twice as many agencies. Globally, legislative mentions of AI rose 21.3% across 75 countries since 2023, marking a ninefold increase since 2016. Alongside growing attention, governments are investing at scale: Canada pledged $2.4 billion, China launched a $47.5 billion semiconductor fund, France committed €109 billion, India pledged $1.25 billion, and Saudi Arabia's Project Transcendence represents a $100 billion initiative.\n\nTwo-thirds of countries now offer or plan to offer K–12 CS education—twice as many as in 2019—with Africa and Latin America making the most progress. In the U.S., the number of graduates with bachelor's degrees in computing has increased 22% over the last 10 years. Yet access remains limited in many African countries due to basic infrastructure gaps like electricity. In the U.S., 81% of K–12 CS teachers say AI should be part of foundational CS education, but less than half feel equipped to teach it.",
"date": "2024-09-10",
"last_updated": "2025-09-25"
}
],
"id": "e38104d5-6bd7-4d82-bc4e-0a21179d1f77"
}
```
The `max_results` parameter accepts values from 1 to 20, with a default maximum of 10 results per search. See [pricing](/getting-started/pricing) for details on search costs.
## Regional Web Search
You can refine your search results by specifying a country to get more geographically relevant results:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Search for results from a specific country
search = client.search.create(
query="government policies on renewable energy",
country="US", # ISO country code
max_results=5
)
for result in search.results:
print(f"{result.title}: {result.url}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Search for results from a specific country
const search = await client.search.create({
query: "government policies on renewable energy",
country: "US", // ISO country code
maxResults: 5
});
for (const result of search.results) {
console.log(`${result.title}: ${result.url}`);
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "government policies on renewable energy",
"country": "US",
"max_results": 5
}' | jq
```
Use ISO 3166-1 alpha-2 country codes (e.g., "US", "GB", "DE", "JP") to target specific regions. This is particularly useful for queries about local news, regulations, or region-specific information.
## Multi-Query Web Search
Execute multiple related queries in a single request for comprehensive research:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
search = client.search.create(
query=[
"artificial intelligence trends 2024",
"machine learning breakthroughs recent",
"AI applications in healthcare"
],
max_results=5
)
# Access results for each query
for i, query_results in enumerate(search.results):
print(f"Results for query {i+1}:")
for result in query_results:
print(f" {result.title}: {result.url}")
print("---")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const search = await client.search.create({
query: [
"artificial intelligence trends 2024",
"machine learning breakthroughs recent",
"AI applications in healthcare"
],
maxResults: 5
});
// Access results for each query
search.results.forEach((queryResults, i) => {
console.log(`Results for query ${i+1}:`);
queryResults.forEach(result => {
console.log(` ${result.title}: ${result.url}`);
});
console.log("---");
});
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": [
"artificial intelligence trends 2024",
"machine learning breakthroughs recent",
"AI applications in healthcare"
],
"max_results": 5
}' | jq
```
Multi-query search is ideal for research tasks where you need to explore different angles of a topic. Each query is processed independently, giving you comprehensive coverage.
For single queries, `search.results` is a flat list. For multi-query requests, results are grouped per query in the same order.
You can include up to 5 queries in a single multi-query request for efficient batch processing.
## Domain Filtering for Search Results
The `search_domain_filter` parameter allows you to limit search results to specific domains (allowlist) or exclude certain domains (denylist) for focused research. The filter works in two modes:
* **Allowlist mode**: Include only specified domains (no `-` prefix)
* **Denylist mode**: Exclude specified domains (use `-` prefix)
**Note**: You can use either allowlist or denylist mode, but not both simultaneously in the same request.
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
search = client.search.create(
query="climate change research",
search_domain_filter=[
"science.org",
"pnas.org",
"cell.com"
],
max_results=10
)
for result in search.results:
print(f"{result.title}: {result.url}")
print(f"Published: {result.date}")
print("---")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const search = await client.search.create({
query: "climate change research",
searchDomainFilter: [
"science.org",
"pnas.org",
"cell.com"
],
maxResults: 10
});
for (const result of search.results) {
console.log(`${result.title}: ${result.url}`);
console.log(`Published: ${result.date}`);
console.log("---");
}
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
const client = new Perplexity();
async function main() {
const search = await client.search.create({
query: "climate change research",
searchDomainFilter: [
"science.org",
"pnas.org",
"cell.com"
],
maxResults: 10
});
for (const result of search.results) {
console.log(`${result.title}: ${result.url}`);
console.log(`Published: ${result.date}`);
console.log("---");
}
}
main();
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "climate change research",
"search_domain_filter": [
"science.org",
"pnas.org",
"cell.com"
],
"max_results": 10
}' | jq
```
You can add a maximum of 20 domains to the `search_domain_filter` list. The filter works in either allowlist mode (include only) or denylist mode (exclude), but not both simultaneously. See the [domain filter guide](/guides/search-domain-filter-guide) for advanced usage patterns.
### Denylisting Example
You can also exclude specific domains from search results:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Exclude social media sites from search results
search = client.search.create(
query="renewable energy innovations",
search_domain_filter=[
"-pinterest.com",
"-reddit.com",
"-quora.com"
],
max_results=10
)
for result in search.results:
print(f"{result.title}: {result.url}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Exclude social media sites from search results
const search = await client.search.create({
query: "renewable energy innovations",
searchDomainFilter: [
"-pinterest.com",
"-reddit.com",
"-quora.com"
],
maxResults: 10
});
for (const result of search.results) {
console.log(`${result.title}: ${result.url}`);
}
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "renewable energy innovations",
"search_domain_filter": [
"-pinterest.com",
"-reddit.com",
"-quora.com"
],
"max_results": 10
}' | jq
```
## Language Filtering for Web Search
The `search_language_filter` parameter allows you to filter search results by language using ISO 639-1 language codes:
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Search for English, French, and German language results
search = client.search.create(
query="latest AI news",
search_language_filter=["en", "fr", "de"],
max_results=10
)
for result in search.results:
print(f"{result.title}: {result.url}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Search for English, French, and German language results
const search = await client.search.create({
query: "latest AI news",
searchLanguageFilter: ["en", "fr", "de"],
maxResults: 10
});
for (const result of search.results) {
console.log(`${result.title}: ${result.url}`);
}
```
```javascript JavaScript theme={null}
const Perplexity = require('@perplexity-ai/perplexity_ai');
const client = new Perplexity();
async function main() {
// Search for English, French, and German language results
const search = await client.search.create({
query: "latest AI news",
searchLanguageFilter: ["en", "fr", "de"],
maxResults: 10
});
for (const result of search.results) {
console.log(`${result.title}: ${result.url}`);
}
}
main();
```
```bash cURL theme={null}
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "latest AI news",
"search_language_filter": ["en", "fr", "de"],
"max_results": 10
}' | jq
```
Language codes must be valid 2-letter ISO 639-1 codes (e.g., "en", "ru", "fr"). You can add a maximum of 10 language codes per request. See the [language filter guide](/guides/search-language-filter) for the complete list of supported codes.
## Content Extraction Control
The `max_tokens_per_page` parameter controls how much content is extracted from each webpage during search processing. This allows you to balance between comprehensive content coverage and processing efficiency.
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Extract more content for comprehensive analysis
detailed_search = client.search.create(
query="artificial intelligence research methodology",
max_results=5,
max_tokens_per_page=2048
)
# Use default extraction for faster processing
quick_search = client.search.create(
query="AI news headlines",
max_results=10,
max_tokens_per_page=512
)
for result in detailed_search.results:
print(f"{result.title}: {result.snippet[:100]}...")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Extract more content for comprehensive analysis
const detailedSearch = await client.search.create({
query: "artificial intelligence research methodology",
maxResults: 5,
maxTokensPerPage: 2048
});
// Use default extraction for faster processing
const quickSearch = await client.search.create({
query: "AI news headlines",
maxResults: 3,
maxTokensPerPage: 512
});
for (const result of detailedSearch.results) {
console.log(`${result.title}: ${result.snippet.substring(0, 100)}...`);
}
```
```bash cURL theme={null}
# Comprehensive content extraction
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "artificial intelligence research methodology",
"max_results": 5,
"max_tokens_per_page": 2048
}' | jq
# Lighter content extraction
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "AI news headlines",
"max_results": 3,
"max_tokens_per_page": 512
}' | jq
```
The `max_tokens_per_page` parameter defaults to 2048 tokens. Higher values provide more comprehensive content extraction but may increase processing time. Lower values enable faster processing with more focused content.
Use lower `max_tokens_per_page` values (256-512) for quick information retrieval or when processing large result sets.
## Total Content Budget Control
The `max_tokens` parameter sets the maximum total tokens of webpage content returned across all search results. This controls how much content appears in the `snippet` fields. Use it together with `max_tokens_per_page` to control content distribution across results.
The `max_tokens` parameter defaults to 25,000 tokens. The maximum allowed value is 1,000,000 tokens.
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
# Higher token budget = more content in snippets
detailed_search = client.search.create(
query="renewable energy technologies",
max_results=10,
max_tokens=50000, # Total content budget across all results
max_tokens_per_page=2048 # Per-result limit
)
# Lower token budget = shorter snippets
brief_search = client.search.create(
query="latest stock market news",
max_results=5,
max_tokens=5000
)
for result in detailed_search.results:
print(f"{result.title}: {len(result.snippet)} chars")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Higher token budget = more content in snippets
const detailedSearch = await client.search.create({
query: "renewable energy technologies",
maxResults: 10,
maxTokens: 50000, // Total content budget across all results
maxTokensPerPage: 2048 // Per-result limit
});
// Lower token budget = shorter snippets
const briefSearch = await client.search.create({
query: "latest stock market news",
maxResults: 5,
maxTokens: 5000
});
for (const result of detailedSearch.results) {
console.log(`${result.title}: ${result.snippet.length} chars`);
}
```
```bash cURL theme={null}
# Higher token budget for detailed content
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "renewable energy technologies",
"max_results": 10,
"max_tokens": 50000,
"max_tokens_per_page": 2048
}' | jq
# Lower token budget for brief snippets
curl -X POST 'https://api.perplexity.ai/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"query": "latest stock market news",
"max_results": 5,
"max_tokens": 5000
}' | jq
```
Search API charges per request only, with no additional token-based pricing.
**When to adjust each parameter:**
* `max_tokens` controls the total content returned across all results—increase for longer snippets
* `max_tokens_per_page` controls content per individual result—increase to get more from each page
* Both parameters work together: `max_tokens` is the total budget, `max_tokens_per_page` is the per-result cap
## Next Steps
Optimize your queries and implement async patterns
## Explore More
Complete API documentation for the Perplexity Search API
Type-safe SDK for Python and TypeScript
Filter search results by recency and date ranges
Advanced domain allowlist and denylist patterns
# SEC Filings Filter Guide
Source: https://docs.perplexity.ai/guides/sec-guide
The `search_mode: "sec"` parameter allows you to tailor your searches specifically to U.S. Securities and Exchange Commission (SEC) filings, prioritizing official financial documents, disclosures, and regulatory filings from public companies.
## Overview
The SEC filter allows users to target their searches specifically to official SEC filings. This is especially useful for investors, analysts, journalists, and professionals who require authoritative financial documents, such as 10-Ks, 10-Qs, 8-Ks, and other regulatory filings, rather than general web content or news articles.
When you activate the SEC filter by setting `search_mode: "sec"`, Perplexity limits results to the SEC's EDGAR database and other reputable sources of regulatory filings, filtering out non-official or general web sources. This ensures that the answers you receive are grounded in official disclosures and regulatory compliance.
## Key Features and Functionality
* **Source Filtering**: Prioritizes SEC filings such as 10-K, 10-Q, 8-K, S-1, and more
* **Regulatory Focus**: Returns results based on official financial and regulatory documents
* **Enhanced Precision**: Provides more accurate and up-to-date information for financial and compliance queries
## Usage Examples
### Basic SEC Filings Search
This example shows how to perform a basic search using the SEC filter.
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "accept: application/json" \
--header "authorization: Bearer $SONAR_API_KEY" \
--header "content-type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [{"role": "user", "content": "Prepare me for markets opening."}],
"search_mode": "sec"
}' | jq
```
```python Python theme={null}
import requests
url = "https://api.perplexity.ai/chat/completions"
headers = {
"accept": "application/json",
"authorization": "Bearer YOUR_API_KEY",
"content-type": "application/json"
}
payload = {
"model": "sonar-pro",
"messages": [{"role": "user", "content": "Prepare me for markets opening."}],
"search_mode": "sec"
}'
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
```javascript Node.js theme={null}
const axios = require('axios');
const url = "https://api.perplexity.ai/chat/completions";
const headers = {
"accept": "application/json",
"authorization": "Bearer YOUR_API_KEY",
"content-type": "application/json"
};
const payload = {
"model": "sonar-pro",
"messages": [{"role": "user", "content": "Prepare me for markets opening."}],
"stream": false,
"search_mode": "sec"
};
axios.post(url, payload, { headers })
.then(response => console.log(response.data))
.catch(error => console.error(error));
```
### Combining SEC Mode with Other Parameters
You can combine the SEC filter with other parameters for more refined searches:
```bash cURL theme={null}
curl --request POST \
--url https://api.perplexity.ai/chat/completions \
--header "accept: application/json" \
--header "authorization: Bearer $SONAR_API_KEY" \
--header "content-type: application/json" \
--data '{
"model": "sonar",
"messages": [{"role": "user", "content": "Summarize the latest 10-K filings for Apple Inc."}],
"stream": false,
"search_mode": "sec",
"search_after_date_filter": "1/1/2023"
}' | jq
```
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar",
messages=[{"role": "user", "content": "Summarize the latest 10-K filings for Apple Inc."}],
search_mode="sec",
search_after_date_filter="1/1/2023"
)
print(completion.choices[0].message.content)
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: "sonar",
messages: [{"role": "user", "content": "Summarize the latest 10-K filings for Apple Inc."}],
search_mode: "sec",
search_after_date_filter: "1/1/2023"
});
console.log(completion.choices[0].message.content);
```
## Recommended Use Cases
The SEC filter is particularly valuable for:
1. **Financial Analysis**: When you need to review official financial statements and disclosures
2. **Regulatory Compliance**: For questions requiring up-to-date regulatory filings and compliance information
3. **Market Research**: When tracking company events, earnings, and risk factors
4. **Due Diligence**: For investors and analysts evaluating public companies
## Best Practices
### Optimizing SEC Filings Searches
* **Be Specific**: Reference the type of filing (e.g., 10-K, 8-K) and company name for more precise results
* **Use Financial Terminology**: Include terms like "earnings," "risk factors," or "management discussion" to target relevant sections
* **Combine with Date Filters**: For the most recent filings, combine with `search_after_date_filter`
* **Adjust Context Size**: Use higher `search_context_size` values for more comprehensive responses
### Limitations
* Availability is limited to filings made public through the SEC's EDGAR system
* Some filings may be delayed or amended after initial publication
* Only covers U.S. public companies and registered entities
⸻
# Streaming Responses
Source: https://docs.perplexity.ai/guides/streaming-responses
Learn how to stream real-time responses using Perplexity's SDKs and APIs
## Overview
Streaming allows you to receive partial responses from the Perplexity API as they are generated, rather than waiting for the complete response. This is particularly useful for:
* **Real-time user experiences** - Display responses as they're generated
* **Long responses** - Start showing content immediately for lengthy analyses
* **Interactive applications** - Provide immediate feedback to users
Streaming is supported across all Perplexity models including Sonar, Sonar Pro, and reasoning models.
## Quick Start
The easiest way to get started is with the Perplexity SDKs, which handle all the streaming parsing automatically.
To enable streaming, set `stream=True` (Python) or `stream: true` (TypeScript) when creating completions:
```python theme={null}
from perplexity import Perplexity
# Initialize the client (uses PERPLEXITY_API_KEY environment variable)
client = Perplexity()
# Create streaming completion
stream = client.chat.completions.create(
model="sonar",
messages=[{"role": "user", "content": "What is the latest in AI research?"}],
stream=True
)
# Process streaming response
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
```
```typescript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
// Create streaming completion
const stream = await client.chat.completions.create({
model: "sonar",
messages: [{ role: "user", content: "What is the latest in AI research?" }],
stream: true
});
// Process streaming response
for await (const chunk of stream) {
if (chunk.choices[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
```
```bash theme={null}
curl -X POST "https://api.perplexity.ai/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar",
"messages": [{"role": "user", "content": "What is the latest in AI research?"}],
"stream": true
}'
```
## Search Results and Metadata During Streaming
Search results and metadata are delivered in the **final chunk(s)** of a streaming response, not progressively during the stream.
### How Metadata Works with Streaming
When streaming, you receive:
1. **Content chunks** which arrive progressively in real-time
2. **Search results** (delivered in the final chunk(s))
3. **Usage stats** and other metadata
### Collecting Metadata During Streaming
```python theme={null}
from perplexity import Perplexity
def stream_with_metadata():
client = Perplexity()
stream = client.chat.completions.create(
model="sonar",
messages=[{"role": "user", "content": "Explain quantum computing"}],
stream=True
)
content = ""
search_results = []
usage_info = None
for chunk in stream:
# Process content
if chunk.choices[0].delta.content:
content_piece = chunk.choices[0].delta.content
content += content_piece
print(content_piece, end='', flush=True)
# Collect metadata from final chunks
if hasattr(chunk, 'search_results') and chunk.search_results:
search_results = chunk.search_results
if hasattr(chunk, 'usage') and chunk.usage:
usage_info = chunk.usage
# Check if streaming is complete
if chunk.choices[0].finish_reason:
print(f"\n\nSearch Results: {search_results}")
print(f"Usage: {usage_info}")
return content, search_results, usage_info
stream_with_metadata()
```
```typescript theme={null}
async function streamWithMetadata(query: string) {
const client = new Perplexity();
const stream = await client.chat.completions.create({
model: "sonar",
messages: [{ role: "user", content: query }],
stream: true
});
let content = "";
let searchResults: any[] = [];
let usage: any = undefined;
for await (const chunk of stream) {
// Process content
if (chunk.choices[0]?.delta?.content) {
const contentPiece = chunk.choices[0].delta.content;
content += contentPiece;
process.stdout.write(contentPiece);
}
// Collect metadata from final chunks
if (chunk.search_results) {
searchResults = chunk.search_results;
}
if (chunk.usage) {
usage = chunk.usage;
}
// Check if streaming is complete
if (chunk.choices[0]?.finish_reason) {
console.log(`\n\nSearch Results:`, searchResults);
console.log(`Usage:`, usage);
}
}
return { content, searchResults, usage };
}
// Usage
const result = await streamWithMetadata("Explain quantum computing");
```
```python theme={null}
import requests
import json
def stream_with_requests_metadata():
url = "https://api.perplexity.ai/chat/completions"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"model": "sonar",
"messages": [{"role": "user", "content": "Explain quantum computing"}],
"stream": True
}
response = requests.post(url, headers=headers, json=payload, stream=True)
content = ""
metadata = {}
for line in response.iter_lines():
if line:
line = line.decode('utf-8')
if line.startswith('data: '):
data_str = line[6:]
if data_str == '[DONE]':
break
try:
chunk = json.loads(data_str)
# Process content
if 'choices' in chunk and chunk['choices'][0]['delta'].get('content'):
content_piece = chunk['choices'][0]['delta']['content']
content += content_piece
print(content_piece, end='', flush=True)
# Collect metadata
for key in ['search_results', 'usage']:
if key in chunk:
metadata[key] = chunk[key]
# Check if streaming is complete
if chunk['choices'][0].get('finish_reason'):
print(f"\n\nMetadata: {metadata}")
except json.JSONDecodeError:
continue
return content, metadata
stream_with_requests_metadata()
```
## Error Handling
Proper error handling is important to ensure your application can recover from errors and provide a good user experience.
```python theme={null}
import perplexity
from perplexity import Perplexity
client = Perplexity()
try:
stream = client.chat.completions.create(
model="sonar-pro",
messages=[
{"role": "user", "content": "Explain machine learning concepts"}
],
stream=True
)
content = ""
for chunk in stream:
if chunk.choices[0].delta.content:
content_chunk = chunk.choices[0].delta.content
content += content_chunk
print(content_chunk, end="")
except perplexity.APIConnectionError as e:
print(f"Network connection failed: {e}")
except perplexity.RateLimitError as e:
print(f"Rate limit exceeded, please retry later: {e}")
except perplexity.APIStatusError as e:
print(f"API error {e.status_code}: {e.response}")
except Exception as e:
print(f"Unexpected error: {e}")
```
```typescript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
try {
const stream = await client.chat.completions.create({
model: "sonar-pro",
messages: [
{ role: "user", content: "Explain machine learning concepts" }
],
stream: true
});
for await (const chunk of stream) {
if (chunk.choices[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
} catch (error) {
if (error instanceof Perplexity.APIConnectionError) {
console.error("Network connection failed:", error.cause);
} else if (error instanceof Perplexity.RateLimitError) {
console.error("Rate limit exceeded, please retry later");
} else if (error instanceof Perplexity.APIError) {
console.error(`API error ${error.status}: ${error.message}`);
} else {
console.error("Unexpected error:", error);
}
}
```
```python theme={null}
import requests
import time
import json
def stream_with_retry(max_retries=3):
url = "https://api.perplexity.ai/chat/completions"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
"Accept": "application/json"
}
data = {
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "Be precise and concise."},
{"role": "user", "content": "Explain machine learning concepts"}
],
"stream": True,
"max_tokens": 1000,
"temperature": 0.2
}
for attempt in range(max_retries):
try:
with requests.post(url, headers=headers, json=data, stream=True, timeout=300) as resp:
resp.raise_for_status()
for line in resp.iter_lines(decode_unicode=True):
if line and line.startswith("data: "):
chunk_data = line[len("data: "):]
if chunk_data == "[DONE]":
break
try:
chunk = json.loads(chunk_data)
content = chunk["choices"][0].get("delta", {}).get("content")
if content:
print(content, end="", flush=True)
except json.JSONDecodeError:
continue
break
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
else:
raise
stream_with_retry()
```
## Proper SSE Parsing
For production use, you should properly parse Server-Sent Events (SSE) format:
```python theme={null}
# pip install sseclient-py
import sseclient
import requests
import json
def stream_with_proper_sse():
url = "https://api.perplexity.ai/chat/completions"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"model": "sonar",
"messages": [{"role": "user", "content": "Explain quantum computing"}],
"stream": True
}
response = requests.post(url, headers=headers, json=payload, stream=True)
client = sseclient.SSEClient(response)
for event in client.events():
if event.data == '[DONE]':
break
try:
chunk_data = json.loads(event.data)
content = chunk_data['choices'][0]['delta'].get('content', '')
if content:
print(content, end='')
except json.JSONDecodeError:
continue
stream_with_proper_sse()
```
```javascript theme={null}
// For browser environments
function streamInBrowser() {
const eventSource = new EventSource('/api/stream'); // Your server endpoint
eventSource.onmessage = function(event) {
if (event.data === '[DONE]') {
eventSource.close();
return;
}
try {
const chunk = JSON.parse(event.data);
const content = chunk.choices[0]?.delta?.content;
if (content) {
document.getElementById('output').innerHTML += content;
}
} catch (e) {
console.error('Error parsing chunk:', e);
}
};
eventSource.onerror = function(event) {
console.error('EventSource failed:', event);
eventSource.close();
};
}
```
```python theme={null}
import requests
import json
def stream_with_manual_parsing():
url = "https://api.perplexity.ai/chat/completions"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"model": "sonar",
"messages": [{"role": "user", "content": "Explain quantum computing"}],
"stream": True
}
response = requests.post(url, headers=headers, json=payload, stream=True)
for line in response.iter_lines():
if line:
line = line.decode('utf-8')
if line.startswith('data: '):
data_str = line[6:] # Remove 'data: ' prefix
if data_str == '[DONE]':
break
try:
chunk_data = json.loads(data_str)
content = chunk_data['choices'][0]['delta'].get('content', '')
if content:
print(content, end='')
except json.JSONDecodeError:
continue
stream_with_manual_parsing()
```
## Advanced Streaming Patterns
### Buffered Streaming
For applications that need to process chunks in batches:
```python theme={null}
from perplexity import Perplexity
import time
def buffered_streaming(buffer_size=50, flush_interval=1.0):
client = Perplexity()
stream = client.chat.completions.create(
model="sonar",
messages=[{"role": "user", "content": "Write a detailed explanation of machine learning"}],
stream=True
)
buffer = ""
last_flush = time.time()
for chunk in stream:
if chunk.choices[0].delta.content:
buffer += chunk.choices[0].delta.content
# Flush buffer if it's full or enough time has passed
if len(buffer) >= buffer_size or (time.time() - last_flush) >= flush_interval:
print(buffer, end='', flush=True)
buffer = ""
last_flush = time.time()
# Flush remaining buffer
if buffer:
print(buffer, end='', flush=True)
buffered_streaming()
```
```typescript theme={null}
async function bufferedStreaming(bufferSize: number = 50, flushInterval: number = 1000) {
const client = new Perplexity();
const stream = await client.chat.completions.create({
model: "sonar",
messages: [{ role: "user", content: "Write a detailed explanation of machine learning" }],
stream: true
});
let buffer = "";
let lastFlush = Date.now();
for await (const chunk of stream) {
if (chunk.choices[0]?.delta?.content) {
buffer += chunk.choices[0].delta.content;
// Flush buffer if it's full or enough time has passed
if (buffer.length >= bufferSize || (Date.now() - lastFlush) >= flushInterval) {
process.stdout.write(buffer);
buffer = "";
lastFlush = Date.now();
}
}
}
// Flush remaining buffer
if (buffer) {
process.stdout.write(buffer);
}
}
bufferedStreaming();
```
### Stream Processing with Callbacks
For applications that need to process chunks with custom logic:
```python theme={null}
from perplexity import Perplexity
from typing import Callable, Optional
def stream_with_callbacks(
query: str,
on_content: Optional[Callable[[str], None]] = None,
on_search_results: Optional[Callable[[list], None]] = None,
on_complete: Optional[Callable[[str, dict], None]] = None
):
client = Perplexity()
stream = client.chat.completions.create(
model="sonar",
messages=[{"role": "user", "content": query}],
stream=True
)
full_content = ""
metadata = {}
for chunk in stream:
# Handle content chunks
if chunk.choices[0].delta.content:
content_piece = chunk.choices[0].delta.content
full_content += content_piece
if on_content:
on_content(content_piece)
# Handle search results
if hasattr(chunk, 'search_results') and chunk.search_results:
metadata['search_results'] = chunk.search_results
if on_search_results:
on_search_results(chunk.search_results)
# Handle other metadata
if hasattr(chunk, 'usage') and chunk.usage:
metadata['usage'] = chunk.usage
# Handle completion
if chunk.choices[0].finish_reason:
if on_complete:
on_complete(full_content, metadata)
return full_content, metadata
# Usage example
def print_content(content: str):
print(content, end='', flush=True)
def handle_search_results(results: list):
print(f"\n[Found {len(results)} sources]", end='')
def handle_completion(content: str, metadata: dict):
print(f"\n\nCompleted. Total length: {len(content)} characters")
if 'usage' in metadata:
print(f"Token usage: {metadata['usage']}")
stream_with_callbacks(
"Explain the latest developments in renewable energy",
on_content=print_content,
on_search_results=handle_search_results,
on_complete=handle_completion
)
```
```typescript theme={null}
interface StreamCallbacks {
onContent?: (content: string) => void;
onSearchResults?: (results: any[]) => void;
onComplete?: (content: string, metadata: any) => void;
}
async function streamWithCallbacks(query: string, callbacks: StreamCallbacks = {}) {
const client = new Perplexity();
const stream = await client.chat.completions.create({
model: "sonar",
messages: [{ role: "user", content: query }],
stream: true
});
let fullContent = "";
const metadata: any = {};
for await (const chunk of stream) {
// Handle content chunks
if (chunk.choices[0]?.delta?.content) {
const contentPiece = chunk.choices[0].delta.content;
fullContent += contentPiece;
callbacks.onContent?.(contentPiece);
}
// Handle search results
if (chunk.search_results) {
metadata.search_results = chunk.search_results;
callbacks.onSearchResults?.(chunk.search_results);
}
// Handle other metadata
if (chunk.usage) {
metadata.usage = chunk.usage;
}
// Handle completion
if (chunk.choices[0]?.finish_reason) {
callbacks.onComplete?.(fullContent, metadata);
}
}
return { content: fullContent, metadata };
}
// Usage example
const result = await streamWithCallbacks(
"Explain the latest developments in renewable energy",
{
onContent: (content) => process.stdout.write(content),
onSearchResults: (results) => process.stdout.write(`\n[Found ${results.length} sources]`),
onComplete: (content, metadata) => {
console.log(`\n\nCompleted. Total length: ${content.length} characters`);
if (metadata.usage) {
console.log(`Token usage:`, metadata.usage);
}
}
}
);
```
## Best Practices
Implement reconnection logic for robust streaming applications.
```python theme={null}
import time
import random
from perplexity import Perplexity
import perplexity
def robust_streaming(query: str, max_retries: int = 3):
client = Perplexity()
for attempt in range(max_retries):
try:
stream = client.chat.completions.create(
model="sonar",
messages=[{"role": "user", "content": query}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end='', flush=True)
return # Success, exit retry loop
except (perplexity.APIConnectionError, perplexity.APITimeoutError) as e:
if attempt < max_retries - 1:
delay = (2 ** attempt) + random.uniform(0, 1)
print(f"\nConnection error, retrying in {delay:.1f}s...")
time.sleep(delay)
else:
print(f"\nFailed after {max_retries} attempts: {e}")
raise
robust_streaming("Explain quantum computing")
```
```typescript theme={null}
async function robustStreaming(query: string, maxRetries: number = 3) {
const client = new Perplexity();
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const stream = await client.chat.completions.create({
model: "sonar",
messages: [{ role: "user", content: query }],
stream: true
});
for await (const chunk of stream) {
if (chunk.choices[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
return; // Success, exit retry loop
} catch (error) {
if (error instanceof Perplexity.APIConnectionError && attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000;
console.log(`\nConnection error, retrying in ${delay / 1000:.1f}s...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
console.error(`\nFailed after ${maxRetries} attempts:`, error);
throw error;
}
}
}
}
robustStreaming("Explain quantum computing");
```
Use appropriate buffering strategies for your application's needs.
```python theme={null}
# For real-time chat applications
buffer_size = 1 # Character-by-character for immediate display
# For document processing
buffer_size = 100 # Larger chunks for efficiency
# For API responses
buffer_size = 500 # Balance between responsiveness and efficiency
```
Remember that search results and metadata arrive at the end of the stream.
```python theme={null}
# Don't expect search results until the stream is complete
if chunk.choices[0].finish_reason == "stop":
# Now search results and usage info are available
process_search_results(chunk.search_results)
log_usage_stats(chunk.usage)
```
Choose streaming parameters based on your application requirements.
```python theme={null}
# Optimize for immediate response
stream = client.chat.completions.create(
model="sonar",
messages=messages,
stream=True,
max_tokens=1000, # Reasonable limit
temperature=0.7 # Balanced creativity
)
```
```python theme={null}
# Optimize for quality and completeness
stream = client.chat.completions.create(
model="sonar-pro",
messages=messages,
stream=True,
max_tokens=4000, # Longer responses
temperature=0.3 # More focused
)
```
**Important**: If you need search results immediately for your user interface, consider using non-streaming requests for use cases where search result display is critical to the real-time user experience.
## Resources
* [The Perplexity SDK Guide](/guides/perplexity-sdk) - The Perplexity SDK guide
* [Chat Completions SDK](/guides/chat-completions-sdk) - Complete chat completions guide
* [API Reference - Chat Completions](/api-reference/chat-completions-post) - Complete API documentation
# Structured Outputs Guide
Source: https://docs.perplexity.ai/guides/structured-outputs
## Overview
Structured outputs enable you to enforce specific response formats from Perplexity's models, ensuring consistent, machine-readable data that can be directly integrated into your applications without manual parsing.
We currently support two types of structured outputs: **JSON Schema** and **Regex**. LLM responses will work to match the specified format, except for the following cases:
* The output exceeds `max_tokens`
Enabling the structured outputs can be done by adding a `response_format` field in the request:
**JSON Schema**
* `response_format: { type: "json_schema", json_schema: {"schema": object} }` .
* The schema should be a valid JSON schema object.
**Regex** (only available for `sonar` right now)
* `response_format: { type: "regex", regex: {"regex": str} }` .
* The regex is a regular expression string.
**Improve Schema Compliance**: Give the LLM some hints about the output format in your prompts to improve adherence to the structured format.
For example, include phrases like "Please return the data as a JSON object with the following structure..." or "Extract the information and format it as specified in the schema."
The first request with a new JSON Schema or Regex expects to incur delay on the first token. Typically, it takes 10 to 30 seconds to prepare the new schema, and may result in timeout errors. Once the schema has been prepared, the subsequent requests will not see such delay.
## Examples
### 1. Financial Analysis with JSON Schema
```python Python theme={null}
from perplexity import Perplexity
from typing import List, Optional
from pydantic import BaseModel
class FinancialMetrics(BaseModel):
company: str
quarter: str
revenue: float
net_income: float
eps: float
revenue_growth_yoy: Optional[float] = None
key_highlights: Optional[List[str]] = None
client = Perplexity()
completion = client.chat.completions.create(
model="sonar-pro",
messages=[
{
"role": "user",
"content": "Analyze the latest quarterly earnings report for Apple Inc. Extract key financial metrics."
}
],
response_format={
"type": "json_schema",
"json_schema": {
"schema": FinancialMetrics.model_json_schema()
}
}
)
metrics = FinancialMetrics.model_validate_json(completion.choices[0].message.content)
print(f"Revenue: ${metrics.revenue}B")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
interface FinancialMetrics {
company: string;
quarter: string;
revenue: number;
net_income: number;
eps: number;
revenue_growth_yoy?: number;
key_highlights?: string[];
}
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: 'Analyze the latest quarterly earnings report for Apple Inc. Extract key financial metrics.'
}
],
response_format: {
type: 'json_schema',
json_schema: {
schema: {
type: 'object',
properties: {
company: { type: 'string' },
quarter: { type: 'string' },
revenue: { type: 'number' },
net_income: { type: 'number' },
eps: { type: 'number' },
revenue_growth_yoy: { type: 'number' },
key_highlights: {
type: 'array',
items: { type: 'string' }
}
},
required: ['company', 'quarter', 'revenue', 'net_income', 'eps']
}
}
}
});
const metrics: FinancialMetrics = JSON.parse(completion.choices[0].message.content);
```
```bash cURL theme={null}
curl -X POST "https://api.perplexity.ai/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar-pro",
"messages": [
{
"role": "user",
"content": "Analyze the latest quarterly earnings report for Apple Inc. Extract key financial metrics."
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"schema": {
"type": "object",
"properties": {
"company": {"type": "string"},
"quarter": {"type": "string"},
"revenue": {"type": "number"},
"net_income": {"type": "number"},
"eps": {"type": "number"},
"revenue_growth_yoy": {"type": "number"},
"key_highlights": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["company", "quarter", "revenue", "net_income", "eps"]
}
}
}
}' | jq
```
### 2. Extract Contact Information with Regex
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
model="sonar",
messages=[
{
"role": "user",
"content": "Find the direct email address for the investor relations contact at Tesla Inc."
}
],
response_format={
"type": "regex",
"regex": {
"regex": r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
}
}
)
email = completion.choices[0].message.content
print(f"Investor Relations Email: {email}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
model: 'sonar',
messages: [
{
role: 'user',
content: 'Find the direct email address for the investor relations contact at Tesla Inc.'
}
],
response_format: {
type: 'regex',
regex: {
regex: '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}'
}
}
});
const email = completion.choices[0].message.content;
```
```bash cURL theme={null}
curl -X POST "https://api.perplexity.ai/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sonar",
"messages": [
{
"role": "user",
"content": "Find the direct email address for the investor relations contact at Tesla Inc."
}
],
"response_format": {
"type": "regex",
"regex": {
"regex": "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"
}
}
}' | jq
```
## Best Practices
### Generating responses in a JSON Format
For Python users, we recommend using the Pydantic library to [generate JSON schema](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_json_schema).
**Unsupported JSON Schemas**
Recursive JSON schema is not supported. As a result of that, unconstrained objects are not supported either. Here's a few example of unsupported schemas:
```
# UNSUPPORTED!
from typing import Any
class UnconstrainedDict(BaseModel):
unconstrained: dict[str, Any]
class RecursiveJson(BaseModel):
value: str
child: list["RecursiveJson"]
```
**Links in JSON Responses**: Requesting links as part of a JSON response may not always work reliably and can result in hallucinations or broken links. Models may generate invalid URLs when forced to include links directly in structured outputs.
To ensure all links are valid, use the links returned in the `citations` or `search_results` fields from the API response. Never count on the model to return valid links directly as part of the JSON response content.
### Generating responses using a regex
**Supported Regex**
* Characters: `\d`, `\w`, `\s` , `.`
* Character classes: `[0-9A-Fa-f]` , `[^x]`
* Quantifiers: `*`, `?` , `+`, `{3}`, `{2,4}` , `{3,}`
* Alternation: `|`
* Group: `( ... )`
* Non-capturing group: `(?: ... )`
**Unsupported Regex**
* Contents of group: `\1`
* Anchors: `^`, `$`, `\b`
* Positive lookahead: `(?= ... )`
* Negative lookahead: `(?! ... )`
* Positive look-behind: `(?<= ... )`
* Negative look-behind: `(?` section containing reasoning tokens, immediately followed by the structured output. The `response_format` parameter does not remove these reasoning tokens from the output, so the final response will need to be parsed manually.
**Sample Response:**
```
I need to provide information about France in a structured JSON format with specific fields: country, capital, population, official_language.
For France:
- Country: France
- Capital: Paris
- Population: About 67 million (as of 2023)
- Official Language: French
Let me format this information as required.
{"country":"France","capital":"Paris","population":67750000,"official_language":"French"}
```
For a reusable implementation to extract JSON from reasoning model outputs, see our [example utility on GitHub](https://github.com/ppl-ai/api-discussion/blob/main/utils/extract_json_reasoning_models.py).
# User Location Filter Guide
Source: https://docs.perplexity.ai/guides/user-location-filter-guide
The `user_location` parameter within `web_search_options` allows you to refine search results based on the user's approximate geographic location. This helps provide more contextually relevant information.
You can specify the location using latitude/longitude coordinates, country code, city, and region. For the most accurate results, we recommend providing as much location information as possible, including `city` and `region` fields. For supported country codes, please refer to the list [here](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).
The `city` and `region` fields significantly improve location accuracy. We strongly recommend including them alongside coordinates and country code for the best results.
Latitude and longitude must be provided alongside the country parameter, they cannot be provided on their own.
## Overview
The `user_location` filter helps tailor search results by incorporating geographic context. This is particularly useful for queries where location significantly impacts relevance, such as:
* Finding local businesses or services.
* Getting information about regional events or news.
* Understanding location-specific regulations or customs.
To refine search results by location, include the `user_location` object within the `web_search_options` in your request payload. You can provide coordinates, country code, city, region, or combine them for maximum accuracy:
**Using All Available Fields (Recommended for Best Accuracy):**
```json theme={null}
"web_search_options": {
"user_location": {
"country": "US",
"region": "California",
"city": "San Francisco",
"latitude": 37.7749,
"longitude": -122.4194
}
}
```
**Using City and Region with Country:**
```json theme={null}
"web_search_options": {
"user_location": {
"country": "US",
"region": "New York",
"city": "New York City"
}
}
```
**Using Latitude/Longitude:**
```json theme={null}
"web_search_options": {
"user_location": {
"country":"US",
"latitude": 37.7749,
"longitude": -122.4194
}
}
```
**Using Country Code Only:**
```json theme={null}
"web_search_options": {
"user_location": {
"country": "US"
}
}
```
These filters work alongside other search parameters like date range or domain filters.
## Examples
**1. Refining Results with All Location Fields (Recommended)**
This example provides all available location fields for San Francisco to get the most accurate geographically relevant search results.
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
messages=[
{"role": "system", "content": "You are a helpful local guide."},
{"role": "user", "content": "What are some good coffee shops nearby?"}
],
model="sonar-pro",
web_search_options={
"user_location": {
"country": "US",
"region": "California",
"city": "San Francisco",
"latitude": 37.7749,
"longitude": -122.4194
}
}
)
print(f"Response: {completion.choices[0].message.content}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
messages: [
{"role": "system", "content": "You are a helpful local guide."},
{"role": "user", "content": "What are some good coffee shops nearby?"}
],
model: "sonar-pro",
web_search_options: {
user_location: {
country: "US",
region: "California",
city: "San Francisco",
latitude: 37.7749,
longitude: -122.4194
}
}
});
console.log(`Response: ${completion.choices[0].message.content}`);
```
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are a helpful local guide."},
{"role": "user", "content": "What are some good coffee shops nearby?"}
],
"web_search_options": {
"user_location": {
"country": "US",
"region": "California",
"city": "San Francisco",
"latitude": 37.7749,
"longitude": -122.4194
}
}
}' | jq
```
**2. Refining Results with Country Code**
This example uses a two-letter ISO country code (United States) to provide broader geographic context.
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
messages=[
{"role": "system", "content": "You are an expert on international news."},
{"role": "user", "content": "Summarize political news from today."}
],
model="sonar-pro",
web_search_options={
"user_location": {
"country": "US"
}
}
)
print(f"Response: {completion.choices[0].message.content}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
messages: [
{"role": "system", "content": "You are an expert on international news."},
{"role": "user", "content": "Summarize political news from today."}
],
model: "sonar-pro",
web_search_options: {
user_location: {
country: "US"
}
}
});
console.log(`Response: ${completion.choices[0].message.content}`);
```
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are an expert on international news."},
{"role": "user", "content": "Summarize political news from today."}
],
"web_search_options": {
"user_location": {
"country": "US"
}
}
}' | jq
```
**3. Using City and Region for Better Accuracy**
This example shows how to use `city` and `region` fields along with coordinates for Paris, France to achieve maximum location accuracy.
**Request Example**
```python Python theme={null}
from perplexity import Perplexity
client = Perplexity()
completion = client.chat.completions.create(
messages=[
{"role": "system", "content": "You are an expert on French news and events."},
{"role": "user", "content": "What major events are happening in the capital this week?"}
],
model="sonar-pro",
web_search_options={
"user_location": {
"country": "FR",
"region": "Île-de-France",
"city": "Paris",
"latitude": 48.8566,
"longitude": 2.3522
}
}
)
print(f"Response: {completion.choices[0].message.content}")
```
```typescript TypeScript theme={null}
import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const completion = await client.chat.completions.create({
messages: [
{"role": "system", "content": "You are an expert on French news and events."},
{"role": "user", "content": "What major events are happening in the capital this week?"}
],
model: "sonar-pro",
web_search_options: {
user_location: {
country: "FR",
region: "Île-de-France",
city: "Paris",
latitude: 48.8566,
longitude: 2.3522
}
}
});
console.log(`Response: ${completion.choices[0].message.content}`);
```
```bash cURL theme={null}
curl --location 'https://api.perplexity.ai/chat/completions' \
--header "Authorization: Bearer $SONAR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "sonar-pro",
"messages": [
{"role": "system", "content": "You are an expert on French news and events."},
{"role": "user", "content": "What major events are happening in the capital this week?"}
],
"web_search_options": {
"user_location": {
"country": "FR",
"region": "Île-de-France",
"city": "Paris",
"latitude": 48.8566,
"longitude": 2.3522
}
}
}' | jq
```
## Best Practices
**Choosing the Right Specificity**
* **All Fields (Recommended):** For maximum accuracy, provide country, region, city, latitude, and longitude. This combination gives the best results for location-specific queries.
* **City and Region:** Use these fields to significantly improve location accuracy without needing exact coordinates. Particularly useful for metropolitan areas and regional searches.
* **Latitude/Longitude:** Use for high precision when the exact location is known and relevant (e.g., finding nearby points of interest).
* **Country Code:** Use for broader context when country-level relevance is sufficient (e.g., national news, country-specific regulations).
* **Combining Fields:** We strongly recommend providing as many location fields as possible. Each additional field improves search accuracy and relevance.
**Data Accuracy**
* Ensure the provided location data is as accurate as possible. Incorrect data may lead to irrelevant results.
* Latitude values must be between -90 and 90. Longitude values must be between -180 and 180.
* Country codes should be valid two-letter ISO 3166-1 alpha-2 codes (e.g., "US", "GB", "DE").
* City names should match commonly used names (e.g., "New York City" or "NYC" for New York).
* Region names should match standard administrative divisions (states, provinces, etc.).
**Privacy Considerations**
* Be mindful of user privacy when collecting and transmitting location data. Only use location when necessary and with user consent where applicable.
**Client-Side Validation**
* Consider validating location inputs before sending the request:
* Check latitude/longitude ranges.
* Validate country code format (two uppercase letters).
* Sanitize city and region inputs for special characters.
# System Status
Source: https://docs.perplexity.ai/status/status
You can check the real-time status of our services at [status.perplexity.ai](https://status.perplexity.ai).