What is average position in SEO, and how do you measure it in Metabase?
Average position is the weighted mean rank of your pages in search
results — weighted by search volume when it comes from a rank tracker, by impressions
when it comes from Google Search Console. The two conventions measure different things, and the metric only means
anything when the weighting and the keyword set are held fixed.
TL;DR — Weight it or don't report it: an unweighted average over
a changing keyword set is noise. GSC's number is impression-weighted across queries where you appeared; rank trackers report best position per tracked keyword per crawl. Keep
the two series on separate cards, and read the average next to
position-bucket counts.
What does an average position chart look like in Metabase?
Chart the volume-weighted position per day as a line, and remember this axis
reads upside down: position 1 is the best rank, so a falling line means
rankings improving. The steady drift from ~13 toward 10 is the trend to
trust, while a one-day jump like Jul 7's is usually SERP volatility around
an algorithm update — wait for it to settle before reacting.
Average position as a Metabase card, built from rank-tracker data. Figures
are illustrative.
What average position measures
A single rank number for a single keyword is legible; a portfolio of
thousands of rankings is not. Average position compresses the portfolio into
one trend line — at the cost of hiding which end of the distribution moved.
Weighting is what keeps the compression honest: multiply each position by
its search volume (or impressions) so the average reflects where searchers
actually are, not how many filler keywords you track.
The number is also convention-dependent. Google Search Console averages the
topmost position over every impression, across all queries, devices, and
locations — so gaining visibility on new long-tail queries makes it worse. A
rank tracker reports the best position per keyword per crawl over a fixed
set you chose. Comparing one to the other, or blending them, produces a
chart that contradicts itself.
What data does it need?
A seo_keyword_positions table with keyword,
target_domain, stat_date, position,
and search_volume, synced from your rank tracker on each
snapshot.
A gsc_performance_daily table with stat_date,
query, impressions, clicks, and
position for the impression-weighted view.
A stable, versioned keyword set — the average is only comparable across
time if the set underneath it didn't change.
SQL patterns
Volume-weighted average position from rank-tracker snapshotsPostgreSQL
SELECT
stat_date,
ROUND(
SUM(position * search_volume)::numeric
/ NULLIF(SUM(search_volume), 0),
2
) AS volume_weighted_position,
ROUND(AVG(position)::numeric, 2) AS unweighted_position,
COUNT(*) AS keywords_tracked
FROM seo_keyword_positions
WHERE target_domain = 'yourdomain.com'
AND stat_date >= CURRENT_DATE - INTERVAL '6 months'
GROUP BY 1
ORDER BY 1;
Impression-weighted position by week from Search ConsolePostgreSQL
SELECT
date_trunc('week', stat_date) AS week,
ROUND(
SUM(position * impressions) / NULLIF(SUM(impressions), 0), 1
) AS impression_weighted_position,
SUM(impressions) AS impressions,
SUM(clicks) AS clicks
FROM gsc_performance_daily
WHERE stat_date >= CURRENT_DATE - INTERVAL '12 months'
GROUP BY 1
ORDER BY 1;
Pitfalls
Letting keyword-set drift move the average.→
Add fifty striking-distance keywords to the tracker and the average jumps
worse; prune dead keywords and it jumps better — with zero change in actual
rankings. Version the tracked set, annotate every change on the chart, and
trend only within a set version.
Averaging across devices and locations.→
Position 3 on desktop in the US and position 12 on mobile in Germany do not
average to a meaningful 7.5. Rankings differ by device and locale; segment
the average by search_engine and location, or fix one segment and
track it consistently.
Chasing decimals instead of position buckets.→
Moving from 8.4 to 8.1 is statistically invisible and clickwise irrelevant;
moving keywords from page two into the top 10 is not. CTR falls off a cliff
by bucket, not by decimal — report top 3 / top 10 / 11–20 counts alongside
the average, and treat the decimal as a tiebreaker.
Comparing Search Console numbers to rank-tracker numbers.→
GSC's impression-weighted average across appearing queries and a tracker's
best-position-per-keyword are different definitions over different keyword
sets. They will disagree, and the disagreement means nothing. Chart them
separately and never reconcile one against the other.
How does Google Search Console calculate average position?
For each impression, Google records the topmost position your property occupied on that result page, then averages across every impression — so Search Console's number is impression-weighted across all the queries, devices, and locations where you appeared. High-impression queries dominate it, and appearing for a new long-tail query at position 40 makes the average worse even though nothing lost rank.
Why doesn't my rank tracker match Search Console?
Because they use different conventions. A rank tracker reports the best position for each tracked keyword per crawl, from a fixed location and device, over a keyword set you chose. Search Console averages over impressions across every query you appeared for. Neither is wrong; they answer different questions. Chart them on separate cards and never blend the two series — a dashboard that mixes them will contradict itself weekly.
Should average position be weighted?
Yes. An unweighted average treats a 10-searches-a-month keyword the same as your highest-volume head term, so it swings with whatever you added to the tracked set last week. Weight by search volume (rank-tracker data) or impressions (Search Console data) so the metric reflects where the visibility actually is. The SQL patterns on this page compute both, and the gap between the weighted and unweighted numbers is itself informative.
Can average position improve while traffic falls?
Easily — that's the core trap. Lose your rankings for a thousand long-tail queries at position 30 and the average "improves" because the weak positions dropped out of the calculation, while clicks and impressions fall. Always read average position next to the impression count and a keywords-in-top-10 count, which doesn't suffer from a shifting denominator.
How do you track average position in Metabase?
Sync rank-tracker snapshots (from Ahrefs, SE Ranking, or similar) and Search Console rows into a SQL database, then chart the volume-weighted tracker position and the impression-weighted GSC position as separate series. Add position-bucket counts alongside, and pin the result to a keyword rank tracking dashboard.