Skip to main content

Competitor Buzz Tracker

A command-line example that turns a product and its competitors into a one-page competitive news report (PDF): how many of the articles in the news right now mention each brand, and each brand’s share of the total. You hand the tool a basket — a few searches plus keyword rules — and the model does the rest. It does this by writing the code itself. Driving the sandbox tool, the model writes Python, runs it in the sandbox, and loops — searching the web, deduplicating and classifying the results, fixing its own errors, and re-running — all server-side. You never run any analysis or charting code locally: the script just submits the requests, polls the background responses, and downloads the finished PDF. Every number on the chart is computed, not guessed.
Competitor Buzz Tracker PDF: horizontal bar chart of news mentions for Galaxy, iPhone, Pixel, and Other, each labeled with its total and share of voice.

What the sandbox does here

  • Runs the analysis as code, not from memory. Like a code interpreter, the sandbox lets the model solve a quantitative task by writing and running Python instead of guessing. The mention counts and share-of-voice percentages come from code it actually executed over the search results — so the numbers are real, not plausible-sounding. The script enforces this: it checks the response contains a sandbox_results item and refuses the result otherwise, so the model can’t skip the tool and return invented counts.
  • Searches the web in the same run. The sandbox can reach Perplexity search from inside the run, so the model pulls the articles itself and classifies them in the same request — no separate scraping step, no glue code, no extra tool to wire up.
  • Returns a real file with zero setup on your side. matplotlib and the runtime live in the sandbox; the model renders the chart, shares it with share_file, and you download the .pdf from the response by id. One request in, one file out — nothing to install or host locally. A plain chat completion would only return text.

Without the sandbox

To build the same report yourself, you’d stand up a runtime: a machine with Python and matplotlib, the search and classification code, and somewhere to execute it and capture the file. With the sandbox tool the model writes and runs that code server-side and hands back the finished PDF — nothing to install, host, or keep running — and it adapts the code to whatever the search returns instead of you maintaining a rigid pipeline.

Installation

Keep the project files in the same directory: competitor_buzz_tracker.py, observability.py (imported by the script), requirements.txt, and your basket.yaml.
  1. Install the dependencies — the Perplexity Python SDK, PyYAML (to read the basket config), and Pydantic (for the response schema). They’re pinned in requirements.txt:
requirements.txt
  1. Set your Perplexity API key:
The SDK reads the key from this environment variable.
This example uses the Agent API sandbox tool. See the Sandbox docs for setup and usage details.

Usage

You describe the job in a small YAML basket: a chart title, the search queries to run, and the keyword rules that classify each result. One article can match several keywords — a story that mentions both Pixel and Galaxy counts for both; one that matches none counts under “Other”. More queries mean broader coverage.
basket.yaml
Each keyword’s regex is a single case-insensitive pattern — use | for alternatives (e.g. "galaxy|samsung"). Save it as basket.yaml, then run:
This writes competitor-buzz-<date>_<time>.pdf to the current directory. Add --show-code to also print the Python the agent wrote and ran in the sandbox.

How it works

You describe the job in plain language and hand the model the sandbox tool; from there it writes the Python, runs it, fixes its own errors, and hands back the counts and the chart — you never touch the analysis code yourself. This example splits that work across two chained requests rather than one. Analysis and rendering are different jobs, and splitting them keeps each prompt short, lets you run the mechanical step on a cheaper model (openai/gpt-5.4) and the rendering on the flagship (openai/gpt-5.5), and puts an inspectable checkpoint in the middle. Request 1 (analytics) gets the sandbox tool and a response_format schema. The model searches each query from inside the sandbox, pools the results, deduplicates by URL, regex-matches each article against the keyword rules, and counts mentions per brand plus its share of voice. The schema turns its answer into a typed contract instead of prose:
Request 2 (chart) gets only that JSON and the sandbox tool, then renders the horizontal bar chart to report.pdf and shares it with share_file. There’s no shared memory between the two: the script validates request 1’s JSON against the schema and passes it into request 2, so the intermediate is plain data you can print or unit-test before anything is drawn. Both requests run with background=True and are polled until they finish, because a sandbox run can take a while.

Prompting guidance

You don’t write the analysis code — each request describes its job as a plain prompt, about as long as a chat message, and the model turns that into Python it runs in the sandbox. The analytics request just sends the basket’s queries and keyword rules as its prompt:
The keyword rules live in the YAML, not in code, so you change what’s tracked by editing the basket — not by touching any Python.
With --show-code, the script prints every sandbox cell the model ran. On the run above the analytics agent took five cells — including one that just inspected a search result to learn its fields — before settling on the code below. Lightly condensed, it’s what it actually executed: search each query, canonicalize and deduplicate URLs, regex-classify each result, count mentions, and print the JSON the schema expects.
It’s regular Python you can read and sanity-check — no framework, no hidden state. The model writes fresh code each run, so the exact shape varies between runs. pplx_sdk is the search interface available inside the sandbox.

Full code

The script is one file; cost reporting and the --show-code helper live in a small observability.py beside it (off the critical path, so it’s easy to drop or move into shared tooling later).

Example Output

A real run — python competitor_buzz_tracker.py --config basket.yaml (results vary with live coverage):
The PDF is a horizontal bar chart of mentions per brand, sorted, each bar labeled with its total and share of voice, under a subtitle showing the article count and snapshot <date>. Every count comes from search results the model actually classified with the keyword rules — not from its training data. (Shares are rounded to one decimal, so they may not sum to exactly 100%.)

Limitations

  • Coverage varies. Output depends on live news, so counts differ by topic and over time.
  • Billing. This makes two Agent API requests, so each run is billed for two sets of model tokens and two sandbox sessions, plus the in-sandbox searches in request 1, at their standard rates.

Resources