Rankings shift constantly. Some pages climb, others drop, and most fluctuate in ways that are hard to detect by manually checking Search Console. Ranking Changes analysis compares two time periods of your GSC data, a baseline and a comparison period, and identifies every page that gained or lost positions, and shows the change in clicks and impressions. Upload two CSV exports and see what moved.
Worked Example (Simulated): Which Pages Moved Between Two Periods?
Question: In this made-up example, what changed between two time spans for pages seen in both?
Inputs: Simulated data, seed 31415. Each span has one row per page URL (page address) with an average position and clicks. Average position is the mean place in search results. Positions in the first span are random whole numbers from 3 to 30. For five pages in both spans, the second-span position is the first-span position plus a random shift of -5 to +5. Clicks in each span are random whole numbers from 10 to 100, drawn without any link to position. Each span also has one page the other lacks.
Method: The script joins rows with the same URL. A lower position number means a rise in rank. It counts pages that rose, fell, or held, and adds up the clicks on the shared pages in each span. Pages seen in only one span are left out.
import numpy as np
seed = 31415
rng = np.random.default_rng(seed)
baseline_urls = ["/guide-a", "/guide-b", "/guide-c", "/guide-d", "/guide-e",
"/guide-old"]
comparison_urls = ["/guide-a", "/guide-b", "/guide-c", "/guide-d", "/guide-e",
"/guide-new"]
baseline_positions = rng.integers(3, 31, size=len(baseline_urls))
comparison_positions = np.maximum(
1, baseline_positions[:5] + rng.integers(-5, 6, size=5))
comparison_positions = np.append(comparison_positions, rng.integers(3, 31))
baseline_clicks = rng.integers(10, 101, size=len(baseline_urls))
comparison_clicks = rng.integers(10, 101, size=len(comparison_urls))
base = {url: (int(pos), int(clicks)) for url, pos, clicks
in zip(baseline_urls, baseline_positions, baseline_clicks)}
comp = {url: (int(pos), int(clicks)) for url, pos, clicks
in zip(comparison_urls, comparison_positions, comparison_clicks)}
shared = sorted(base.keys() & comp.keys())
base_only = sorted(base.keys() - comp.keys())
comp_only = sorted(comp.keys() - base.keys())
print(f"Simulated data, seed {seed}")
print("Periods: baseline and comparison; each has one row per page URL.")
print("Matched page rows: URL | baseline position | comparison position | "
"baseline clicks | comparison clicks")
improved = declined = stable = 0
base_click_total = comp_click_total = 0
for url in shared:
bp, bc = base[url]
cp, cc = comp[url]
# A lower average position number means a higher search result position.
if cp < bp:
improved += 1
elif cp > bp:
declined += 1
else:
stable += 1
base_click_total += bc
comp_click_total += cc
print(f"{url} | {bp} | {cp} | {bc} | {cc}")
print(f"Shared pages: {len(shared)}")
print(f"Improved position: {improved}; declined position: {declined}; "
f"unchanged position: {stable}")
print(f"Observed clicks on shared pages: baseline {base_click_total}; "
f"comparison {comp_click_total}; "
f"difference {comp_click_total - base_click_total}")
print("Baseline-only pages excluded from matched-page deltas: "
f"{', '.join(base_only)}")
print("Comparison-only pages excluded from matched-page deltas: "
f"{', '.join(comp_only)}")
Printed output:
Simulated data, seed 31415
Periods: baseline and comparison; each has one row per page URL.
Matched page rows: URL | baseline position | comparison position | baseline clicks | comparison clicks
/guide-a | 16 | 21 | 96 | 25
/guide-b | 16 | 20 | 74 | 29
/guide-c | 4 | 1 | 56 | 35
/guide-d | 6 | 3 | 32 | 10
/guide-e | 27 | 30 | 71 | 100
Shared pages: 5
Improved position: 2; declined position: 3; unchanged position: 0
Observed clicks on shared pages: baseline 329; comparison 199; difference -130
Baseline-only pages excluded from matched-page deltas: /guide-old
Comparison-only pages excluded from matched-page deltas: /guide-new
Result: Two of the five shared pages rose and three fell. Clicks on the shared pages went from 329 to 199, a drop of 130. This is chance: clicks here are random and have no link to the position change by construction. For example, /guide-c moved from position 4 to position 1 and its clicks fell from 56 to 35, and /guide-d moved from position 6 to position 3 and its clicks fell from 32 to 10.
Limit: The data are made up, so this example cannot show how rank moves link to clicks, and it does not show what caused any change. Five pages and two spans are far too few to say anything about a real site.
What Is Ranking Change Analysis?
Every website's search rankings are in constant motion. Google updates its algorithm, competitors publish new content, your own site changes, all of this can cause pages to move up or down in search results. The problem is that Search Console shows you current performance, not a clear picture of what changed. You can compare date ranges in the GSC interface, but you get a single summary table that does not separate significant shifts from daily noise, does not quantify the traffic impact, and does not prioritize which changes need your attention.
Ranking Change Analysis takes two snapshots of your GSC data, a baseline period and a comparison period, and produces a comprehensive differential analysis. For URLs seen in both time spans, the analysis finds changes in average position, clicks, impressions (times shown), and CTR (click rate). URLs seen in only one span are left out of this matched page check. A size filter can hide small shifts so larger ones stand out. A size filter is not a statistical test. Pages are classified as winners (gained positions) or losers (lost positions) and ranked by traffic impact, not just position change magnitude, because a 3-position gain on a page with 10,000 impressions matters far more than a 10-position gain on a page with 50 impressions.
The analysis goes beyond page-level reporting. It aggregates the overall movement direction: is your site gaining or losing ground overall? It shows the distribution of changes: are most pages stable with a few big movers, or is everything shifting? And it shows the change in clicks between time spans. This does not show how many clicks rank changes caused.
When to Use Ranking Change Analysis
Monthly SEO reporting is the primary cadence. Export your GSC data for last month (comparison) and the month before (baseline), run the analysis, and include the winners/losers sections in your report. This gives stakeholders a clear view of SEO momentum, are we gaining or losing ground?
Algorithm update review is another use case. Comparing a period before a suspected update with a period after it shows how pages moved over that time. It does not show that the update caused the change. To compare types of content or page patterns, the data needs those labels.
Post-migration monitoring is equally important. After a URL migration, domain change, or major site restructure, ranking disruptions are expected. The analysis compares URLs seen in both time spans. A URL seen in one span is not paired with a different URL. So this check alone cannot show that a new URL took rank from an old one.
Competitive intelligence rounds out the use cases. If a competitor publishes a major piece of content or runs a PR campaign, your rankings for related queries might drop. With page data, the analysis shows page changes. To find changes by search term, it needs search term data and a check by search term.
What Data Do You Need?
This is a multi-dataset module requiring two CSV files:
Baseline dataset: GSC page-level data from your earlier time period. Required columns: page (URL), clicks, impressions, ctr (as a decimal), and position (average ranking position). The column mapping uses baseline_page_url, baseline_clicks, baseline_impressions, baseline_ctr, and baseline_position.
Comparison dataset: Same structure from your later time period, mapped to comparison_page_url, comparison_clicks, comparison_impressions, comparison_ctr, and comparison_position.
Export page-level data from Search Console once for the baseline period and once for the comparison period. Use periods of equal length so that impression and click volumes are directly comparable.
How to Read the Report
The report builds from overview to detail:
Position Distribution. Side-by-side histograms showing how your pages distributed across position ranges in the baseline vs. comparison period. This is the big-picture view: did more pages move into the top positions? Did you lose pages from page one? The shape of the distribution tells you whether your site is consolidating at the top, spreading across the middle, or sinking.
Change Breakdown. A summary table showing how many pages improved, declined, or stayed stable, broken down by position range. In the example above, two shared pages rose and three fell. This is a change seen between the two time spans. It does not show what caused it. The breakdown by position range shows whether moves happen near the top of page one or in lower positions that generate few clicks.
Top Movers. The pages with the largest absolute position changes, sorted by the magnitude of the shift. These are your biggest gains and biggest losses. Each row shows the baseline position, comparison position, position delta, and the corresponding changes in clicks and impressions. In the example above, /guide-c moved from position 4 to position 1. This is a rise in its mean search rank. It does not show why it moved. A page that dropped a long way is worth a closer look.
Impact Analysis. Shows the change in clicks and impressions between time spans. For each page, it shows the click delta (how many more or fewer clicks) and the impression delta. Added across pages, this gives the net change in clicks. This does not show how many clicks rank changes caused.
Winners Detail. An expanded view of pages that gained positions, with full metrics for both periods. This section helps you understand why pages improved: was it a content update, a new backlink, a competitor dropping out? The data alone does not answer causation, but the details give you hypotheses to investigate.
Losers Detail. The same expanded view for pages that lost positions. These are your investigation priorities. Check whether these pages had technical issues (crawl errors, slow load times), lost backlinks, or were outcompeted by newer content on the same topics.
TL;DR. AI-generated summary with net movement direction, biggest wins and losses, total click impact, and priority actions.
When to Use Something Else
If you want to find pages with CTR optimization potential at their current position rather than tracking position changes, use the GSC Quick Wins module. It focuses on pages that rank well but underperform on CTR, a different dimension of SEO opportunity.
If you are running controlled SEO experiments (intentionally changing titles and measuring the effect), use the Title A/B Test module. Ranking Change Analysis detects natural fluctuations across your entire site, while Title A/B Test evaluates the impact of specific, intentional changes.
If you want to combine search data with engagement data to understand which pages are performing well end-to-end (not just in search), use the Cross-Platform Content Performance module. A page might gain rankings but have terrible engagement, the cross-platform view catches that.
Your turn
Bring your own data and the question you actually need answered.
MCP AnalyticsData science by email Send us your data and your question, and we will reply. ds@mcpanalytics.ai