What does a keyword rank tracking dashboard show in Metabase?
A keyword rank tracking dashboard turns daily position checks into an operational view: position trends by keyword group, the week's biggest gains and losses, newly ranking keywords, striking-distance opportunities, and rank volatility. It runs on daily snapshots synced from SE Ranking, Semrush position tracking, or raw DataForSEO SERP data — the day-to-day working layer of SEO analytics.
seo_keyword_positions.Which cards belong on a keyword rank tracking dashboard?
- Average position by keyword group over time (line)
- Biggest gains week-over-week, in positions (table)
- Biggest losses week-over-week, in positions (table)
- Newly ranking keywords, trailing 28 days (table)
- Striking distance — positions 11–20 by search volume (table)
- Rank volatility — position standard deviation, trailing 30 days (table)
- SERP features on tracked keywords — who owns the snippet (table)
- Tracking coverage — keywords tracked by engine and location (bar)
What data does the dashboard need?
seo_keyword_positionswith search_engine and location columns — keyword, project, search_engine, location, stat_date, position, previous_position, search_volume, url — from SE Ranking or Semrush position tracking.- Or raw
serp_snapshotsfrom DataForSEO — one row per keyword per result position per crawl — reduced to your domain's best rank per keyword in a view. - A keyword grouping table (topic, intent, funnel stage) so trend cards aggregate something more useful than the all-keyword average.
How do you build it?
- Sync daily positions to the warehouse via the SE Ranking or Semrush API, or schedule DataForSEO SERP tasks and land the results — there is no managed connector for any of the three.
- Model best-rank-per-keyword per day, plus a weekly rollup with
LAG()deltas for the movers tables. - Add the keyword grouping table and compute per-group averages and 30-day position standard deviation for volatility.
- Assemble the cards with engine, location, and group filters, and a drill-through from mover rows to the keyword's full position history.
Example card SQL
WITH weekly AS (
SELECT
keyword,
date_trunc('week', stat_date) AS week,
MIN(position) AS best_position
FROM seo_keyword_positions
WHERE search_engine = 'google'
AND location = 'United States'
GROUP BY 1, 2
),
deltas AS (
SELECT
keyword,
week,
best_position,
LAG(best_position)
OVER (PARTITION BY keyword ORDER BY week) AS prev_position
FROM weekly
)
SELECT
keyword,
prev_position,
best_position,
prev_position - best_position AS positions_gained
FROM deltas
WHERE week = date_trunc('week', CURRENT_DATE)
AND prev_position IS NOT NULL
ORDER BY positions_gained DESC
LIMIT 20;WITH ranked_days AS (
SELECT
keyword,
stat_date,
MIN(position) AS best_position
FROM seo_keyword_positions
WHERE search_engine = 'google'
AND position <= 20
GROUP BY 1, 2
)
SELECT
keyword,
MIN(stat_date) AS first_ranked_on,
MIN(best_position) AS best_position_since
FROM ranked_days
GROUP BY 1
HAVING MIN(stat_date) >= CURRENT_DATE - 28
ORDER BY first_ranked_on DESC;