Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.perplexity.ai/llms.txt

Use this file to discover all available pages before exploring further.

Search News Monitor

A command-line tool that uses Perplexity’s Search API (client.search.create(...)) to monitor real-time news across multiple topics. Configure topics, domain filters, and recency windows to build a continuous news monitoring pipeline.

Features

  • Monitor multiple topics in a single run using the Search API
  • Filter results by domain with search_domain_filter (allowlist or denylist)
  • Control recency with search_recency_filter (day, week, month, year)
  • Access structured result fields: title, url, snippet, date
  • Configurable polling interval for continuous monitoring
  • Output as formatted text or JSON for downstream processing

Installation

pip install perplexityai

API Key Setup

Set your Perplexity API key as an environment variable. The SDK reads it automatically:
export PERPLEXITY_API_KEY="your_api_key_here"

Usage

# Monitor default topics
python news_monitor.py

# Specify custom topics
python news_monitor.py --topics "artificial intelligence" "climate policy" "space exploration"

# Filter to specific domains (allowlist)
python news_monitor.py --topics "AI regulation" --domains reuters.com apnews.com bbc.co.uk

# Exclude domains (denylist)
python news_monitor.py --topics "technology" --exclude-domains pinterest.com reddit.com

# Set recency filter
python news_monitor.py --topics "semiconductor industry" --recency day

# Run in continuous monitoring mode
python news_monitor.py --topics "cybersecurity" --watch --interval 300

# Export as JSON
python news_monitor.py --topics "renewable energy" --json > news.json

How It Works

  1. The CLI accepts a list of topics and optional filtering parameters.
  2. For each topic, it calls client.search.create(query=..., max_results=...) with the configured domain and recency filters.
  3. Each search result contains title, url, snippet, and date fields, which are extracted and formatted.
  4. In watch mode, the tool repeats the search at a configurable interval, displaying only new results since the last poll.
Use the search_recency_filter parameter with values like "day", "week", "month", or "year" to focus on recent news. This is simpler than specifying exact date ranges and works well for monitoring workflows.
Domain filters operate in either allowlist or denylist mode, not both simultaneously. Use --domains for allowlist or --exclude-domains for denylist, but not both in the same request. A maximum of 20 domains can be specified.

Full Code

import sys
import json
import time
import argparse
from typing import List, Optional
from perplexity import Perplexity

DEFAULT_TOPICS = ["artificial intelligence", "climate change", "cybersecurity"]


def search_topic(
    client, topic, max_results=5, domains=None, exclude_domains=None, recency=None,
):
    """Search for news on a single topic and return structured results."""
    params = {"query": topic, "max_results": max_results}
    if domains:
        params["search_domain_filter"] = domains
    elif exclude_domains:
        params["search_domain_filter"] = [f"-{d}" for d in exclude_domains]
    if recency:
        params["search_recency_filter"] = recency

    search = client.search.create(**params)
    return [
        {
            "title": item.title,
            "url": item.url,
            "snippet": item.snippet[:200] if item.snippet else "",
            "date": item.date if hasattr(item, "date") else None,
        }
        for item in search.results
    ]


def monitor_once(client, topics, max_results, domains, exclude_domains, recency):
    """Run a single monitoring pass across all topics."""
    return {
        topic: search_topic(client, topic, max_results, domains, exclude_domains, recency)
        for topic in topics
    }


def format_results(all_results):
    """Format monitoring results as human-readable text."""
    lines = [f"NEWS MONITOR - {time.strftime('%Y-%m-%d %H:%M:%S')}", "=" * 60]
    for topic, results in all_results.items():
        lines.append(f"\n[ {topic.upper()} ] - {len(results)} results")
        lines.append("-" * 40)
        if not results:
            lines.append("  No results found.")
            continue
        for i, r in enumerate(results, 1):
            lines.append(f"  {i}. {r['title']}")
            lines.append(f"     {r['url']}")
            if r["date"]:
                lines.append(f"     Published: {r['date']}")
            if r["snippet"]:
                lines.append(f"     {r['snippet']}...")
            lines.append("")
    return "\n".join(lines)


def main():
    parser = argparse.ArgumentParser(description="Search News Monitor")
    parser.add_argument("--topics", nargs="+", default=DEFAULT_TOPICS)
    parser.add_argument("--max-results", type=int, default=5)
    parser.add_argument("--domains", nargs="+", help="Allowlist domains")
    parser.add_argument("--exclude-domains", nargs="+", help="Denylist domains")
    parser.add_argument("--recency", choices=["day", "week", "month", "year"], default="week")
    parser.add_argument("--watch", action="store_true", help="Continuous monitoring")
    parser.add_argument("--interval", type=int, default=300, help="Poll interval (seconds)")
    parser.add_argument("--json", action="store_true", help="Output as JSON")
    args = parser.parse_args()

    if args.domains and args.exclude_domains:
        print("Error: Use --domains or --exclude-domains, not both.", file=sys.stderr)
        sys.exit(1)

    client = Perplexity()
    print(f"Monitoring {len(args.topics)} topics: {', '.join(args.topics)}")
    print(f"Recency: {args.recency} | Max results per topic: {args.max_results}\n")

    seen_urls = set()
    while True:
        all_results = monitor_once(
            client, args.topics, args.max_results, args.domains, args.exclude_domains, args.recency,
        )
        if args.watch:
            filtered = {}
            for topic, results in all_results.items():
                new = [r for r in results if r["url"] not in seen_urls]
                seen_urls.update(r["url"] for r in new)
                filtered[topic] = new
            all_results = filtered

        print(json.dumps(all_results, indent=2) if args.json else format_results(all_results))

        if not args.watch:
            break
        print(f"\nNext check in {args.interval} seconds... (Ctrl+C to stop)\n")
        time.sleep(args.interval)


if __name__ == "__main__":
    main()

Example Output

python news_monitor.py --topics "artificial intelligence" "climate policy" --recency day
Monitoring 2 topics: artificial intelligence, climate policy
Recency: day | Max results per topic: 5

NEWS MONITOR - 2026-02-26 14:30:00
============================================================

[ ARTIFICIAL INTELLIGENCE ] - 5 results
----------------------------------------
  1. OpenAI Announces New Enterprise AI Safety Framework
     https://www.reuters.com/technology/openai-enterprise-safety-2026
     Published: 2026-02-26
     OpenAI introduced a comprehensive safety framework for enterprise
     deployments, addressing concerns about autonomous agent behavior...

  2. EU AI Act Enforcement Begins for High-Risk Systems
     https://www.bbc.co.uk/news/technology-ai-act-enforcement
     Published: 2026-02-26
     The European Union has started enforcing new requirements for
     high-risk AI systems under the AI Act...

[ CLIMATE POLICY ] - 3 results
----------------------------------------
  1. G7 Nations Agree on Carbon Border Adjustment Timeline
     https://www.reuters.com/sustainability/g7-carbon-border-2026
     Published: 2026-02-26
     G7 leaders reached consensus on implementing coordinated carbon
     border adjustment mechanisms by 2028...
The Search API returns structured results with title, url, snippet, and date fields. Unlike the Agent API or Sonar API, it does not generate AI summaries — it returns raw ranked web results. See the Search API quickstart for full details.

Continuous Monitoring Tips

  1. Set appropriate intervals. For breaking news, use 60-120 second intervals. For general topic monitoring, 300-600 seconds is sufficient.
  2. Combine recency with domain filters. Use --recency day with trusted news domains for a curated news feed.
  3. Pipe JSON output to other tools. Use --json with tools like jq or downstream scripts for alerting and aggregation.
  4. Track seen URLs. The watch mode automatically deduplicates results across polling cycles using URL tracking.

Limitations

  • The Search API charges per request. Frequent polling across many topics will increase costs.
  • The search_recency_filter is relative to the current time and cannot specify exact date ranges. For precise date filtering, use search_after_date_filter and search_before_date_filter instead.
  • Search result availability depends on web indexing. Very recent content (within minutes) may not appear immediately.
  • The snippet field length varies by result and may be truncated for long pages.