To automate SEO reporting for free, connect Search Console and Google Analytics 4 to a one-page Data Studio report and use its Schedule delivery option to email it as a PDF every month. If you also want a permanent record of the numbers, add a short Apps Script to a Google Sheet that pulls last month’s totals on the 4th of each month.
That covers the copy-and-paste work, which is most of the time a report takes. What it can’t do is explain why the numbers moved, so the last step stays manual: a three-line note on top. This guide shows both free setups, when a paid tool is worth it, and the limits that break automated reports. Every limit and menu name below was checked against Google’s documentation in November 2026.
What to automate and what to keep
Automate anything that is the same every month: pulling numbers, building charts, comparing periods, and sending the email. Keep anything that needs judgment: the summary, the reason a page dropped, and what you need from the client.
If you don’t have a report structure yet, start with our monthly SEO reporting template. It lists seven sections and which numbers belong in each. The setups below fill that template without you opening a single dashboard.
Three ways to automate it, compared
| Data Studio scheduled email | Google Sheet with Apps Script | Paid reporting tool | |
|---|---|---|---|
| Cost | Free | Free | From about $20 per client a month |
| Code needed | None | About 40 lines, copy and paste | None |
| Delivery | PDF and link by email | A new row in a sheet, optional email | Email, client portal, white label |
| Keeps data past 16 months | No | Yes | Depends on the tool |
| Best for | One site or a few clients | Keeping a history, custom numbers | Ten or more clients |
The 16-month column matters more than it looks. Google says Search Console keeps data for the last 16 months, so a Data Studio report can’t show a year-on-year comparison for a month older than that. A sheet that saves one row a month keeps it forever.
The paid price is AgencyAnalytics’ current Core plan: $20 per client per month, billed annually, with a 14-day free trial. Other tools price differently, so check before you commit.
Method 1: a Data Studio report that emails itself
Data Studio is the free dashboard tool Google used to call Looker Studio. Its scheduling feature sends a report on a timer, which is all most small businesses need.
- Connect Search Console. In Data Studio, create a data source, pick the Search Console connector, choose your site and pick a table. Google’s connector guide explains that a data source can use either Site Impression or URL Impression, not both, so add two data sources if you want sitewide totals and a page list.
- Connect GA4. Add a second data source with the Google Analytics connector. You need “Read & Analyze” permission on the property.
- Build one page. Scorecards for organic key events, clicks and impressions, a non-branded clicks scorecard with a filter that excludes queries containing your brand name, and a table of the top pages. Fewer charts make a better PDF.
- Set the dates. Set the default date range to the previous calendar month, not a rolling 28 days, so each email covers one clean month. Then set a Comparison date range of Previous period or Previous year on each scorecard, as Google’s date range guide shows.
- Schedule it. Click Share, then Schedule delivery. Add recipients, pick the pages, set a start date and time, and choose how often it repeats.
Step 4 matters most. With a rolling date range, the email that lands on the 4th covers part of last month and part of this one, and the comparison shifts every time. The numbers will look wrong to anyone who checks them against Search Console.
What the scheduled email contains
According to Google’s scheduling documentation, each email has the report as a PDF attachment, a preview of the first page and a link to the live report. You can send it to up to 50 addresses or group aliases, and you are always included.
The limits of the free version
- One schedule per report. Without the paid Pro tier you get one schedule per report. Pro allows up to 200, plus a custom subject and message, “Send now”, and delivery to Google Chat and Slack.
- Email quotas. Personal accounts can send 200 emails a day and 800 a month. Google Workspace accounts get 500 a day and 3,000 a month. An agency with 30 clients on one personal account is nowhere near that, but a weekly schedule to big group aliases can be.
- Time zone. Delivery follows your computer’s operating system time zone, and you can’t change it in Data Studio. If you work from California and your client is in New York, the 7 am email lands at 10 am their time.
- No note. Without Pro you can’t write a custom message, so the email arrives as a bare PDF. Send your summary as a separate reply to the same thread.
Schedule the email for the 4th of the month or later. Google says Search Console data is normally available in 2 to 3 days, so a report sent on the 1st will be missing the last days of the month.
Method 2: a Google Sheet that logs your numbers every month
A sheet suits you if you want a history that outlives Search Console’s 16 months, or numbers Data Studio can’t easily show side by side. The script below runs once a month, pulls last month’s Search Console totals and organic GA4 sessions and key events, and adds one row to a sheet.
- Create the sheet. Make a Google Sheet with a tab called
Monthly, then open Extensions, then Apps Script. - Add the GA4 service. In the editor, next to Services, click Add a service and pick Analytics Data. It wraps the Google Analytics Data API.
- Switch to a standard Cloud project and enable the APIs. Apps Script can only call the Search Console API if the API is turned on in the script’s Cloud project, and Google’s Cloud project guide says you can’t change APIs in the default project. In Project Settings, change the project to a standard one, then enable the Google Search Console API and the Google Analytics Data API in the Cloud console. You will also be asked to set up an OAuth consent screen there.
- Set the scopes. In Project Settings, tick the box to show
appsscript.json, then add the scopes below. Google’s scopes guide explains theoauthScopesfield. - Paste the script, run
createTriggeronce, and approve access.
The scopes block for appsscript.json:
"oauthScopes": [
"https://www.googleapis.com/auth/webmasters.readonly",
"https://www.googleapis.com/auth/analytics.readonly",
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/script.scriptapp"
]
The script. Change the two values at the top:
const SITE = 'sc-domain:example.com'; // or 'https://www.example.com/'
const GA4_PROPERTY = '123456789'; // your GA4 property ID
function monthlyReport() {
const tz = Session.getScriptTimeZone();
const now = new Date();
const first = new Date(now.getFullYear(), now.getMonth() - 1, 1);
const last = new Date(now.getFullYear(), now.getMonth(), 0);
const start = Utilities.formatDate(first, tz, 'yyyy-MM-dd');
const end = Utilities.formatDate(last, tz, 'yyyy-MM-dd');
// Search Console: no dimensions returns one row of totals.
const url = 'https://www.googleapis.com/webmasters/v3/sites/' +
encodeURIComponent(SITE) + '/searchAnalytics/query';
const res = UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
payload: JSON.stringify({ startDate: start, endDate: end, type: 'web' }),
});
const gsc = (JSON.parse(res.getContentText()).rows || [{}])[0];
// GA4: sessions and key events by channel, keep Organic Search.
const report = AnalyticsData.Properties.runReport({
dimensions: [{ name: 'sessionDefaultChannelGroup' }],
metrics: [{ name: 'sessions' }, { name: 'keyEvents' }],
dateRanges: [{ startDate: start, endDate: end }],
}, 'properties/' + GA4_PROPERTY);
const organic = (report.rows || []).find(
(r) => r.dimensionValues[0].value === 'Organic Search');
SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Monthly').appendRow([
Utilities.formatDate(first, tz, 'yyyy-MM'),
gsc.clicks || 0,
gsc.impressions || 0,
organic ? Number(organic.metricValues[0].value) : 0,
organic ? Number(organic.metricValues[1].value) : 0,
]);
}
function createTrigger() {
ScriptApp.newTrigger('monthlyReport').timeBased().onMonthDay(4).atHour(6).create();
}
Every name in that script comes from Google’s reference pages: the searchAnalytics.query endpoint and its type field, the GA4 API schema for sessionDefaultChannelGroup, sessions and keyEvents, and the clock trigger builder for onMonthDay and atHour. Leaving out dimensions in the Search Console request returns a single row of totals for the whole month.
Run monthlyReport once by hand to check it adds a row, then run createTrigger. Google notes that a trigger set for 6 am may fire any time between 6 and 7 am, which doesn’t matter for a monthly job. You can also make the trigger without code: click Triggers on the left, then Add Trigger.
Once the sheet has a few rows, point a Data Studio chart at it. You get a long-run trend line that keeps going after Search Console has dropped the old months.
Where the script can break
- Wrong property format. A Domain property needs
sc-domain:in front. A URL-prefix property needs the full URL with the trailing slash, exactly as Search Console shows it. - Quotas. Apps Script allows 20 triggers per user per script and 6 minutes per run. One monthly call per site is far inside both, but a single script looping over 200 client sites could run out of time.
- GA4 limits. A standard property gets 200,000 core tokens a day. One small report a month uses almost none, but Data Studio dashboards on the same property draw from the same pool.
- Silent zeros. If someone removes the GA4 tag from the site, the script still adds a row, full of zeros. That is why you read the numbers before you send anything.
When a paid tool is worth it
Free setups get slow when you manage many clients. Each Data Studio report has to be copied and reconnected per client, and the free email has no custom message. Paid tools add client portals, white-label branding, rank tracking and Google Business Profile data in one place.
A rough test: if building and checking reports takes you more than a day a month, a tool at $20 per client is cheaper than your time. Below about ten clients, the free route usually wins. For local clients you can also pull calls and direction requests yourself with the Google Business Profile API, though access takes an application and a profile that’s at least 60 days old.
The part you shouldn’t automate
An automated report answers “what happened”. The client wants to know “is it working, and what are you doing about it”. Those answers need someone who knows that the drop in October was the site migration, or that the jump came from a radio ad and not from SEO.
Spend five minutes a month on that note. Check the numbers look sane first: a month of zeros means broken tracking, not a bad month. If Search Console and GA4 disagree by 10 or 20%, that is normal, and our guide to Search Console vs Google Analytics explains why so you can tell the client once and move on.
FAQ
Can SEO reporting be fully automated?
The data collection, charts and delivery can be. The explanation can’t, because a tool doesn’t know about the site redesign, the new competitor or the client’s radio campaign. Automate the numbers and write the summary yourself.
Is Data Studio free for automated reports?
Yes. Scheduled email delivery works on the free version, with one schedule per report and a maximum of one delivery a day. The paid Pro tier adds more schedules, custom messages and Slack delivery, according to Google’s docs.
How do I send automated SEO reports to clients?
Build the report in Data Studio, open Share, then Schedule delivery, and add the client’s email address. They get a PDF and a link each month. Give them view access to the report if you want the link to work without a sign-in request.
What is the best automated SEO reporting tool?
For one site or a handful of clients, Data Studio with the free Search Console and GA4 connectors is enough. Paid tools earn their cost when you manage many clients and need white-label reports or client portals.
The short version
Build one Data Studio page with a fixed last-month date range, schedule it for the 4th, and add a Sheets script if you want to keep your numbers past 16 months. Then spend the time you saved on the three sentences that tell the client what happened and what comes next. That note is the part they read.
