Published on March 14, 2026
Track Your Competitors in AI Search Results via API
What you'll learn: How to use the Sellm API to monitor competitor mentions, rankings, and share of voice across ChatGPT, Claude, Perplexity, Gemini, Grok, and Copilot - and build automated competitive intelligence workflows.
When someone asks ChatGPT "What's the best analytics platform for e-commerce?" or Perplexity "Top product analytics tools for online stores," the AI doesn't just recommend one brand. It lists several - and the order, frequency, and sentiment of those mentions define each brand's competitive position in AI search. If your competitor is consistently ranked first across AI engines and you're buried at position four, that's a visibility gap you need to know about.
The Sellm API provides structured competitor data for every analysis run. This guide shows you how to extract that data, build a competitor tracking workflow, and turn raw API responses into actionable competitive intelligence.
How Competitor Data Works in the API
Every time Sellm runs an analysis, it sends your configured prompts to AI providers and parses the responses. The analysis extracts not only whether your brand was mentioned, but every other brand that appeared alongside it. This data surfaces in the API response from GET /v1/async-analysis/{'{'}analysisId{'}'}, which includes a top-level summary and a promptBreakdown array with per-prompt competitor details.
Summary: Aggregate KPIs
The GET /v1/async-analysis/{'{'}analysisId{'}'} endpoint returns the full analysis result once the status is succeeded. The summary object contains your brand's aggregate KPIs:
curl -s "https://sellm.io/api/v1/async-analysis/aa_01abc123" \
-H "Authorization: Bearer sellm_your_api_key" | python3 -m json.tool
The response includes:
{
"data": {
"id": "aa_01abc123",
"status": "succeeded",
"prompt": "best analytics platform for e-commerce",
"summary": {
"sovPct": 29,
"coveragePct": 72,
"avgPos": 2.3,
"sentiment": 0.76
},
"promptBreakdown": [
{
"prompt": "best analytics platform for e-commerce",
"sovPct": 29,
"coverage": 72,
"avgPos": 2.3,
"sentiment": 0.76,
"volume": 50,
"topCompetitors": ["mixpanel", "amplitude"],
"details": {
"brandHits": 36,
"competitorHits": { "mixpanel": 42, "amplitude": 31, "heap": 18 },
"positions": [2, 3, 1, 2, 3],
"sentiments": [0.8, 0.7, 0.9, 0.75, 0.65]
}
}
],
"providerBreakdown": {
"sovByProvider": [
{ "provider": "ChatGPT", "sov": 33 },
{ "provider": "Claude", "sov": 25 },
{ "provider": "Perplexity", "sov": 29 }
],
"coverageByProvider": [
{ "provider": "ChatGPT", "coverage": 80 },
{ "provider": "Claude", "coverage": 60 },
{ "provider": "Perplexity", "coverage": 75 }
],
"sentimentByProvider": [
{ "provider": "ChatGPT", "sentiment": 0.82 },
{ "provider": "Claude", "sentiment": 0.70 },
{ "provider": "Perplexity", "sentiment": 0.76 }
]
}
}
}
This gives you an instant snapshot: Mixpanel has 42 mentions versus your 36, making it the top competitor. Amplitude trails you, and Heap appears less frequently but still shows up in over a third of responses.
Prompt-Level Breakdown: competitorHits
The promptBreakdown array drills down to individual prompts. Each entry includes a topCompetitors string array (the top 2 competitors by mention count) and a details.competitorHits object showing exact mention counts per brand:
{
"promptBreakdown": [
{
"prompt": "best analytics platform for e-commerce",
"sovPct": 22,
"coverage": 80,
"avgPos": 3.0,
"sentiment": 0.72,
"volume": 45,
"topCompetitors": ["mixpanel", "amplitude"],
"details": {
"brandHits": 10,
"competitorHits": { "mixpanel": 15, "amplitude": 12, "heap": 8 },
"positions": [3, 2, 4, 3],
"sentiments": [0.7, 0.75, 0.68, 0.74]
}
},
{
"prompt": "which analytics tool has the best e-commerce integrations",
"sovPct": 35,
"coverage": 90,
"avgPos": 1.5,
"sentiment": 0.84,
"volume": 40,
"topCompetitors": ["amplitude", "heap"],
"details": {
"brandHits": 14,
"competitorHits": { "amplitude": 10, "heap": 9, "mixpanel": 7 },
"positions": [1, 2, 1, 2],
"sentiments": [0.85, 0.82, 0.88, 0.81]
}
}
]
}
This is where the real insights live. You can see exactly which prompts your competitors dominate and which ones you're winning. In the example above, Mixpanel outranks you on the general "best analytics" query, but you lead on the integrations-focused query. That tells you where your content strategy is working and where it needs attention.
Building a Competitor Tracking Workflow
Here's a step-by-step workflow that submits an analysis via the API, polls for results, extracts competitor data, and generates actionable reports. Save this as competitor_tracker.py:
Step 1: Submit an Analysis and Poll for Results
import requests
import json
import os
import time
from collections import defaultdict
API_KEY = os.environ["SELLM_API_KEY"]
BASE_URL = "https://sellm.io/api/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
def submit_analysis(prompt, providers=None, locations=None, replicates=3):
"""Submit an async analysis request."""
body = {
"prompt": prompt,
"providers": providers or ["chatgpt", "claude", "perplexity"],
"locations": ["US"],
"replicates": replicates,
}
if locations:
body["locations"] = locations
resp = requests.post(f"{BASE_URL}/async-analysis", headers=HEADERS, json=body)
resp.raise_for_status()
return resp.json()["data"]
def poll_analysis(analysis_id, timeout=300, interval=5):
"""Poll until the analysis succeeds or fails."""
deadline = time.time() + timeout
while time.time() < deadline:
resp = requests.get(
f"{BASE_URL}/async-analysis/{analysis_id}", headers=HEADERS
)
resp.raise_for_status()
data = resp.json()["data"]
if data["status"] == "succeeded":
return data
if data["status"] == "failed":
raise RuntimeError(f"Analysis {analysis_id} failed")
time.sleep(interval)
raise TimeoutError(f"Analysis {analysis_id} timed out after {timeout}s")
Step 2: Analyze Competitor Positions
def analyze_competitors(prompt_breakdown):
"""Build a competitor analysis from prompt-level data."""
competitor_totals = defaultdict(int)
for p in prompt_breakdown:
hits = p.get("details", {}).get("competitorHits", {})
for name, count in hits.items():
competitor_totals[name] += count
# Sort by total mentions descending
results = [
{"name": name, "totalMentions": count}
for name, count in sorted(
competitor_totals.items(), key=lambda x: x[1], reverse=True
)
]
return results
def find_competitor_strengths(prompt_breakdown, your_brand_key="your_brand"):
"""Find which prompts each competitor dominates."""
competitor_wins = defaultdict(list)
for p in prompt_breakdown:
hits = p.get("details", {}).get("competitorHits", {})
brand_hits = p.get("details", {}).get("brandHits", 0)
for name, count in hits.items():
if count > brand_hits:
competitor_wins[name].append({
"prompt": p["prompt"],
"theirMentions": count,
"yourMentions": brand_hits,
})
return dict(competitor_wins)
Step 3: Generate a Competitive Report
def print_report(data, your_brand="Acme Analytics"):
"""Print a formatted competitive intelligence report."""
summary = data["summary"]
prompt_breakdown = data.get("promptBreakdown", [])
print("=" * 60)
print("COMPETITIVE INTELLIGENCE REPORT")
print("=" * 60)
# Your brand's position
print(f"\nYour Brand: {your_brand}")
print(f" Share of Voice: {summary['sovPct']}%")
print(f" Coverage: {summary['coveragePct']}%")
print(f" Avg Position: {summary['avgPos']}")
print(f" Sentiment: {summary['sentiment']}")
# Competitor leaderboard
competitors = analyze_competitors(prompt_breakdown)
print(f"\n{'Competitor':<25} {'Total Mentions':<15}")
print("-" * 40)
for c in competitors:
print(f"{c['name']:<25} {c['totalMentions']:<15}")
# Prompts where competitors beat you
strengths = find_competitor_strengths(prompt_breakdown)
if strengths:
print(f"\nCompetitors outperforming you:")
for name, wins in strengths.items():
print(f" {name}: beats you on {len(wins)} prompt(s)")
for w in wins[:3]:
print(f" - \"{w['prompt'][:60]}\"")
print(f" theirs: {w['theirMentions']} vs yours: {w['yourMentions']}")
if __name__ == "__main__":
# Submit analysis for a competitive query
result = submit_analysis("best analytics platform for e-commerce")
analysis_id = result["id"]
print(f"Submitted analysis: {analysis_id}")
# Poll until complete
data = poll_analysis(analysis_id)
print(f"Analysis completed: {data['status']}")
# Generate report
print_report(data)
Run it with:
export SELLM_API_KEY="sellm_your_api_key"
python3 competitor_tracker.py
Example output:
============================================================
COMPETITIVE INTELLIGENCE REPORT
============================================================
Your Brand: Acme Analytics
Share of Voice: 29%
Coverage: 72%
Avg Position: 2.3
Sentiment: 0.76
Competitor Total Mentions
----------------------------------------
mixpanel 42
amplitude 31
heap 18
Competitors outperforming you:
mixpanel: beats you on 1 prompt(s)
- "best analytics platform for e-commerce"
theirs: 15 vs yours: 10
Analyzing Competitor Trends Over Time
A single snapshot tells you where you stand today. But competitive intelligence becomes truly powerful when you track changes over time. Submit the same prompt on a regular schedule and compare the results across multiple analyses:
import csv
from datetime import datetime
def run_and_store(prompt, csv_path="competitor_trends.csv"):
"""Run an analysis and append competitor data to a CSV for trending."""
result = submit_analysis(prompt)
data = poll_analysis(result["id"])
summary = data["summary"]
prompt_breakdown = data.get("promptBreakdown", [])
competitors = analyze_competitors(prompt_breakdown)
# Build row
row = {
"date": datetime.utcnow().strftime("%Y-%m-%d"),
"analysisId": data["id"],
"yourSOV": summary["sovPct"],
}
for c in competitors[:5]:
row[c["name"]] = c["totalMentions"]
# Append to CSV
file_exists = os.path.exists(csv_path)
with open(csv_path, "a", newline="") as f:
writer = csv.DictWriter(f, fieldnames=row.keys())
if not file_exists:
writer.writeheader()
writer.writerow(row)
return row
def print_trend_table(csv_path="competitor_trends.csv"):
"""Display SOV trends from stored CSV data."""
with open(csv_path, "r") as f:
reader = csv.DictReader(f)
rows = list(reader)
if not rows:
print("No trend data yet.")
return
# Get all competitor columns
meta_cols = {"date", "analysisId", "yourSOV"}
competitor_cols = sorted(set(rows[0].keys()) - meta_cols)
header = f"{'Date':<14} {'Your SOV':<10}"
for col in competitor_cols:
header += f"{col[:15]:<17}"
print(header)
print("-" * len(header))
for row in rows:
line = f"{row['date']:<14} {row['yourSOV']:<10}"
for col in competitor_cols:
line += f"{row.get(col, '-'):<17}"
print(line)
Example trend output:
Date Your SOV amplitude heap mixpanel
---------------------------------------------------------------------
2026-01-27 24 28 15 40
2026-02-03 25 27 16 39
2026-02-10 27 26 17 38
2026-02-17 28 27 18 37
2026-02-24 29 31 18 42
In this example, your brand has gained 5 percentage points of SOV over five weeks while Mixpanel has fluctuated. That's the kind of trend you want to catch early - and the kind you'd never notice without systematic tracking.
Per-Provider Competitive Analysis
Different AI engines may favor different brands. The providerBreakdown object in the analysis response shows how your brand performs on each platform:
def compare_by_provider(data):
"""Show how your brand stacks up on each AI platform."""
breakdown = data.get("providerBreakdown", {})
sov_map = {p["provider"]: p["sov"] for p in breakdown.get("sovByProvider", [])}
cov_map = {p["provider"]: p["coverage"] for p in breakdown.get("coverageByProvider", [])}
sent_map = {p["provider"]: p["sentiment"] for p in breakdown.get("sentimentByProvider", [])}
providers = sorted(sov_map.keys())
print(f"\n{'Provider':<14} {'SOV %':<10} {'Coverage %':<12} {'Sentiment':<10}")
print("-" * 46)
for prov in providers:
print(
f"{prov:<14} {sov_map.get(prov, '-'):<10} "
f"{cov_map.get(prov, '-'):<12} {sent_map.get(prov, '-'):<10}"
)
If you discover that Mixpanel dominates ChatGPT while you lead in Claude, that's a signal to investigate what content ChatGPT's training data favors and adjust your strategy accordingly.
Setting Up Competitor Alerts
Automate notifications when the competitive landscape shifts. This Slack integration alerts you when a competitor's mentions surpass yours or when a new competitor enters the scene:
SLACK_WEBHOOK = os.environ.get("SLACK_WEBHOOK_URL")
def send_slack_alert(title, details):
"""Send a formatted alert to Slack."""
if not SLACK_WEBHOOK:
return
payload = {
"blocks": [
{"type": "header", "text": {"type": "plain_text", "text": title}},
{"type": "section", "text": {"type": "mrkdwn", "text": details}},
]
}
requests.post(SLACK_WEBHOOK, json=payload)
def check_competitive_alerts(current_data, previous_data, your_brand="Acme Analytics"):
"""Compare two analysis results and alert on competitive changes."""
current_breakdown = current_data.get("promptBreakdown", [])
previous_breakdown = previous_data.get("promptBreakdown", [])
current_competitors = analyze_competitors(current_breakdown)
previous_competitors = analyze_competitors(previous_breakdown)
current_map = {c["name"]: c["totalMentions"] for c in current_competitors}
previous_map = {c["name"]: c["totalMentions"] for c in previous_competitors}
current_brand_hits = sum(
p.get("details", {}).get("brandHits", 0) for p in current_breakdown
)
alerts = []
# Check for competitors who overtook your brand
for name, mentions in current_map.items():
prev_mentions = previous_map.get(name, 0)
if prev_mentions <= current_brand_hits and mentions > current_brand_hits:
alerts.append(
f"*{name}* overtook you in mentions: "
f"{prev_mentions} -> {mentions} "
f"(yours: {current_brand_hits})"
)
# Check for new competitors
new_names = set(current_map) - set(previous_map)
for name in new_names:
alerts.append(
f"New competitor detected: *{name}* "
f"({current_map[name]} mentions)"
)
if alerts:
send_slack_alert(
"Competitive Intelligence Alert",
"\n".join([f"- {a}" for a in alerts])
)
Pricing
Competitor tracking uses the same Sellm API available on all plans. The competitive intelligence data (topCompetitors, competitorHits) is included in every analysis run at no extra cost:
- Paid plans: Automated scheduled runs with weekly prompt quotas across all providers. Each prompt analysis costs less than 1 cent. Track dozens to hundreds of competitive queries automatically.
Competitor data comes from the same analysis runs you already use for brand monitoring. There's no separate charge for competitive intelligence - if you're running prompts, you're already collecting competitor data.
Next Steps
- Create a Sellm account and configure prompts that include competitor-relevant queries
- Generate an API key in Project Settings
- Run the competitor tracker script above to see where you stand
- Set up a weekly cron job and Slack alerts for ongoing monitoring
- Use the trend data to correlate content changes with competitive position shifts
For the full API reference, including all competitor-related fields and filtering options, visit sellm.io/docs/api.
Know Where You Stand Against Competitors in AI Search
See which brands AI engines recommend alongside yours across ChatGPT, Claude, Perplexity, Gemini, Grok, and Copilot.
Get StartedFrequently Asked Questions
Do I need to configure competitors manually?
No. Sellm automatically detects every brand mentioned in AI responses. The topCompetitors and competitorHits fields are populated from what the AI engines actually say, not from a pre-defined list. You can optionally configure known competitors in project settings for more targeted tracking.
Can I track competitors across specific AI providers?
Yes. Use the providerBreakdown in the analysis response to see your metrics per platform. You can also specify which providers to include when submitting an analysis via the providers array.
How often does competitor data update?
Competitor data updates with every analysis run. On paid plans, scheduled runs happen weekly. You can also trigger manual runs (limited to 1 per 7 days) when you need fresh competitive data outside the regular schedule.
Is competitor tracking included in every plan?
Yes, competitor tracking is included in every API response at no extra cost.