Three Ways to Add a Moving Average to Your SEO Data: Spreadsheet, Python, and the Shortcut Most SEOs Miss

Three complete methods for adding a moving average to your GSC data: a Google Sheets formula, a Python script, and a one-click option that skips the export entirely.

MAR 22, 202611 MIN READ
How to calculate Moving average in SEO

If you have already read why moving averages help you read GSC data more accurately and want to actually get one on your data, this is that article. Three complete methods: a spreadsheet formula, a Python script, and a one-click option inside Google Search Console. Each one works. They differ in setup time, where the output lives, and whether you can automate it.

Pick the method that fits how you already work.

Method 1: Google Sheets

The spreadsheet approach gives you a rolling average column sitting next to your raw data. You can chart it, share it, or feed it into a reporting template. It requires an export and a formula, but once set up it takes less than two minutes to apply to any new dataset.

Step 1: Export Your GSC Data

Go to Google Search Console, open the Performance report, and set a date range. 90 days is a reasonable minimum. 180 days gives the smoothed line more context and makes trends easier to read.

Under the chart, click "Export" and choose Google Sheets. GSC creates a spreadsheet with multiple tabs. Go to the Dates tab. You need two columns: Date in column A, Clicks in column B. If you want a moving average on impressions as well, you can apply the same formula to that column after.

Sort by date ascending if it is not already. The formula depends on rows being in chronological order.

Step 2: Write the Formula

Add a header in C1 — something like "MA 7d" — then put this in C2:

=IF(ROW()-ROW($B$2)+1<7,"",AVERAGE(OFFSET($B$2,ROW()-ROW($B$2)-6,0,7,1)))

What it does, step by step:

OFFSET($B$2, ROW()-ROW($B$2)-6, 0, 7, 1) selects a range that ends at the current row and spans 7 rows upward. For row 8 (the 7th data row), it selects B2:B8. For row 9, it selects B3:B9. The window always covers exactly 7 consecutive rows ending at the current date.

AVERAGE(...) takes the mean of those 7 values.

IF(ROW()-ROW($B$2)+1<7,"",...) returns a blank for the first 6 rows because there are not yet 7 data points to average. Blanks are cleaner than zeros for charting — a line chart will simply not draw the line for those rows, which is correct.

Enter your window size and the cell where your clicks data starts. The formula updates instantly.

Step 3: Fill the Column

Click cell C2, then drag the fill handle down to the last row of your data. The formula adjusts automatically for each row. Rows 2 through 7 will be blank. Row 8 onward will show the 7-day trailing average.

To chart it: select columns A, B, and C, insert a line chart, and choose "Date" as the x-axis. You now have raw clicks in one line and the smoothed 7-day average in another.

One note for advanced Sheets users: OFFSET is not array-compatible in Google Sheets, so wrapping this formula in ARRAYFORMULA will not work. The fill-and-drag approach is the correct method here. If you add more rows of data later, just extend the fill down to cover them.

Changing the Window Size

The formula has one variable: the window length. For a 14-day moving average:

=IF(ROW()-ROW($B$2)+1<14,"",AVERAGE(OFFSET($B$2,ROW()-ROW($B$2)-13,0,14,1)))

The pattern for any window size N:

=IF(ROW()-ROW($B$2)+1<N,"",AVERAGE(OFFSET($B$2,ROW()-ROW($B$2)-(N-1),0,N,1)))

Replace N with 7, 14, 21, or 28. Larger windows smooth more but respond more slowly to recent changes.

Pick a window size to see exactly how the lag tradeoff plays out in days.

Method 2: Python with pandas

If you work across multiple properties, pull GSC data programmatically, or want a calculation that runs automatically as part of a larger workflow, pandas is the right tool. The actual code is short.

The Complete Code

import pandas as pd

# Load your exported GSC data
# Expects a CSV with at least 'Date' and 'Clicks' columns
df = pd.read_csv('gsc_data.csv', parse_dates=['Date'])
df = df.sort_values('Date').reset_index(drop=True)

# Calculate moving averages
df['clicks_ma_7d']  = df['Clicks'].rolling(window=7).mean().round()
df['clicks_ma_14d'] = df['Clicks'].rolling(window=14).mean().round()

# Preview the first 20 rows
print(df[['Date', 'Clicks', 'clicks_ma_7d', 'clicks_ma_14d']].head(20))

# Export back to CSV
df.to_csv('gsc_with_ma.csv', index=False)

rolling(window=7).mean() is pandas' built-in trailing moving average. For each row, it looks back N rows including the current one and returns the mean. The first 6 rows will show NaN because there are not yet 7 data points. That is correct and expected — the same logic as the blank cells in the spreadsheet version.

.round() converts the float average to a whole number. Clicks are integers, so a rolling average of 247.14 is not meaningful to report. Remove it if you want the precise float.

To apply the same calculation to impressions, add one line.

When you export from the Dates tab in GSC (via Export > Google Sheets or Download CSV), the column headers are exactly: Date, Clicks, Impressions, CTR, Position. The code above uses these as-is. If your CSV came from a third-party tool or a different export tab, check the header row and adjust the column names in the script to match.

When Python Earns Its Setup Time

For a single site reviewed occasionally, the spreadsheet approach is faster to run once. Python makes sense when you are processing more than a handful of properties and want one script to handle all of them, when you pull GSC data via the API and want the moving average calculated before it touches any spreadsheet, or when you are building a reporting pipeline and need the MA as a calculated column that feeds into a dashboard or alerting system.

If neither of those applies to you, the spreadsheet method is fine. If either applies, Python pays back the setup time quickly.

Method 3: Advanced GSC Visualizer

The first two methods require an export. The extension skips that entirely. The moving average is calculated and drawn directly on the GSC performance chart, in the same view where you already read your data.

How to Enable the Moving Average

Open Google Search Console with the Advanced GSC Visualizer extension installed. Navigate to the performance chart and locate the extension controls. Click the More button to reveal additional visualization settings, then find the Trendline / Moving Average dropdown.

The available options depend on the current time grouping in your chart. In daily mode: standard trendline, 7-day moving average, or 14-day moving average. In weekly mode: standard trendline, 4-week moving average, or 8-week moving average. In monthly mode: standard trendline or 3-month moving average.

Select the option that fits your analysis. The overlay renders immediately as a red line on the chart. No export, no formula, no chart setup.

What the Overlay Shows You

The calculation is the same trailing simple moving average as Methods 1 and 2. The first N-1 days of the visible date range show no overlay because the window does not have enough prior data. From day N onward the smoothed red line runs continuously on top of the raw data.

The legend at the bottom of the chart confirms the active calculation, showing it as Trendline(clicks) or Trendline(impressions) depending on the metric. If multiple metrics are active, the extension applies the moving average to whichever metric you activated first. To target impressions specifically, deactivate all active metrics, click the impressions button first, then enable anything else you want visible in the background.

To make the trendline stand out more against busy raw data, use the Chart Opacity slider to reduce the visibility of the underlying chart. The smoothed line comes into sharp focus while the raw data stays visible in the background.

You can switch window sizes without refreshing or re-exporting. Changing from 7-day to 14-day updates the line immediately — useful for feeling the difference between a short and long window on your actual data before committing to one for a report.

For the technical details of how the extension calculates the moving average and handles data aggregation edge cases, see the trendlines and moving averages documentation.

Which Method Fits Your Workflow

The right choice comes down to where you work and what you do with the output.

Use Google Sheets if you already report in spreadsheets, if you want the calculation visible and auditable in your own file, or if you need to combine the moving average with other metrics you track in a sheet.

Use Python if you process multiple sites in a data pipeline, if you are already pulling GSC data via the API, or if you need the moving average as an input to an automated workflow.

Use Advanced GSC Visualizer if you primarily work inside Google Search Console, if you want to check the trend without exporting anything, or if you want to adjust the window size and see the effect on your live data in real time.

For most SEOs who check GSC regularly, the extension fits the existing workflow without any setup. The spreadsheet and Python methods are worth knowing when you need to take the data somewhere the extension cannot follow.

Glossary

Key terms used in this article.

Simple Moving Average (SMA)
A simple moving average calculates the mean of the last N data points, where N is the window size you choose. Each day the window shifts forward by one: the oldest day drops off, the newest day is added, and the average is recalculated. The result is a smoothed line that shows the direction of the underlying data without the day-to-day noise. It is called simple to distinguish it from weighted variations like the exponential moving average, which gives more importance to recent data.
Window Size / Period
The number of data points included in each average calculation. A 7-day window averages the 7 most recent days. A 14-day window averages the 14 most recent days. Larger windows produce smoother lines but respond more slowly to recent changes. Smaller windows stay closer to current performance but pick up more short-term fluctuation. The window size is the one tunable parameter in all three methods described in this article.
Aggregation Level
The unit of time your data is bucketed into before the moving average is calculated. In GSC exports, the default aggregation is daily: one row per day. The moving average then averages across N days. If your data is weekly, a 7-period window covers 7 weeks, not 7 days. Aggregation level matters because the same window size means different things depending on whether your data is daily, weekly, or monthly.

Frequently Asked Questions

Click any question to expand the answer.

Does the formula work for impressions and position data too?
Yes. The OFFSET formula and the pandas rolling().mean() both work on any numeric column. For impressions, swap the clicks column reference with the impressions column in your spreadsheet, or change 'Clicks' to 'Impressions' in the Python code. For position data, the smoothing effect is less dramatic because GSC position is already an average across all queries and dates. The moving average still reduces noise, but the visual difference between raw and smoothed will be smaller than it is for clicks or impressions.
What window size should I use for SEO data?
Start with 7-day. It smooths weekend dips and one-off spikes while staying close enough to the present to be actionable. Move to 14-day when 7-day still looks too jagged, or when you are presenting to someone who needs a calmer visual. The tradeoff is that longer windows lag: a change that happens today takes longer to fully register in a 14-day average than a 7-day one. For most GSC analysis, 7 to 14 days is the useful range. For monthly reporting, a 4-week window often makes more sense.
Why are the first rows blank or NaN?
A 7-day trailing moving average requires 7 days of prior data to calculate. Day 1 through day 6 do not have a full 7-day window behind them, so there is nothing to average. The spreadsheet formula returns a blank, and pandas returns NaN. This is correct behavior. If you want zeros instead of blanks in the spreadsheet, replace the empty string in the IF statement with 0, but blanks chart more cleanly since the line simply does not start until the first valid calculation.
Can I use an exponential moving average instead?
Yes. An exponential moving average (EMA) gives more weight to recent data points, so it responds faster to changes than a simple moving average. In pandas, replace rolling(window=7).mean() with ewm(span=7).mean(). In Google Sheets, the EMA formula is more complex and harder to audit. For most SEO trend analysis, a simple moving average is easier to explain to stakeholders, easier to verify, and accurate enough. EMA is worth considering if you want the line to react faster to recent shifts and are comfortable explaining the weighted calculation.