Answer Engine Optimization (AEO) is the practice of ranking in ChatGPT, Perplexity, and Claude answers, not just Google. This tutorial walks through building an AEO dashboard that runs daily prompts, captures brand mentions, and visualizes trends over time using Scavio for data and Metabase for charts.
Prerequisites
- Python 3.8+
- A Scavio API key
- A Postgres database (Supabase free tier works)
- Metabase self-hosted or cloud
Walkthrough
Step 1: Set up the database schema
Create a table to log prompt-answer-mention rows.
CREATE TABLE aeo_log (
id SERIAL PRIMARY KEY,
run_date DATE,
engine TEXT,
prompt TEXT,
answer TEXT,
brand_mentions JSONB
);Step 2: Write the daily tracker script
For each engine and prompt, query Scavio and log the result.
ENGINES = ['chatgpt', 'perplexity']
PROMPTS = ['best SERP API 2026', 'top Claude Code alternatives']
def run_tracker():
for engine in ENGINES:
for prompt in PROMPTS:
resp = requests.post('https://api.scavio.dev/api/v1/ask',
headers={'x-api-key': API_KEY},
json={'platform': engine, 'prompt': prompt}).json()
mentions = count_brands(resp.get('answer', ''))
save_row(engine, prompt, resp['answer'], mentions)Step 3: Schedule with cron
Run the tracker daily at 8am UTC.
0 8 * * * /usr/bin/python3 /path/to/aeo_tracker.pyStep 4: Build Metabase charts
Create a trend chart of brand mentions over time, per engine.
-- In Metabase, use:
SELECT run_date, engine, brand_mentions->>'Scavio' AS scavio_count
FROM aeo_log
ORDER BY run_date;Step 5: Set up alerts
Configure Metabase to email the team when a competitor's mention count jumps 20%+.
// Metabase UI: Subscriptions > New alert on trend changePython Example
import os, requests, psycopg2, json
API_KEY = os.environ['SCAVIO_API_KEY']
PG_URL = os.environ['POSTGRES_URL']
BRANDS = ['Scavio', 'SerpAPI', 'Tavily']
def count_brands(text):
return {b: text.lower().count(b.lower()) for b in BRANDS}
def run():
conn = psycopg2.connect(PG_URL)
cur = conn.cursor()
for engine in ['chatgpt', 'perplexity']:
for prompt in ['best SERP API 2026']:
r = requests.post('https://api.scavio.dev/api/v1/ask',
headers={'x-api-key': API_KEY},
json={'platform': engine, 'prompt': prompt}).json()
cur.execute('INSERT INTO aeo_log (run_date, engine, prompt, answer, brand_mentions) VALUES (CURRENT_DATE, %s, %s, %s, %s)',
(engine, prompt, r.get('answer', ''), json.dumps(count_brands(r.get('answer', '')))))
conn.commit()
run()JavaScript Example
import { Client } from 'pg';
const API_KEY = process.env.SCAVIO_API_KEY;
const BRANDS = ['Scavio', 'SerpAPI', 'Tavily'];
const pg = new Client({ connectionString: process.env.POSTGRES_URL });
await pg.connect();
for (const engine of ['chatgpt', 'perplexity']) {
const r = await fetch('https://api.scavio.dev/api/v1/ask', {
method: 'POST',
headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ platform: engine, prompt: 'best SERP API 2026' })
});
const { answer } = await r.json();
const mentions = Object.fromEntries(BRANDS.map(b => [b, (answer.toLowerCase().match(new RegExp(b.toLowerCase(), 'g')) || []).length]));
await pg.query('INSERT INTO aeo_log (run_date, engine, prompt, answer, brand_mentions) VALUES (CURRENT_DATE, $1, $2, $3, $4)', [engine, 'best SERP API 2026', answer, mentions]);
}
await pg.end();Expected Output
Daily rows appear in the aeo_log table, one per engine-prompt combination. Metabase charts display a 30-day trend line of brand mentions, and an alert fires when a competitor's count spikes.