
How to Automate Weekly Reports from Google Analytics
Manually logging into GA4 every Monday to screenshot the same handful of numbers is exactly the kind of task worth automating, and GA4 gives you several ways to do it — ranging from a couple of clicks to a small custom script — depending on how much control you need over the format and destination.
Option 1: GA4's Built-In Scheduled Email Reports
The simplest option, requiring no setup outside GA4 itself:
- Open any report (standard or a custom report you've built).
- Click the Share this report icon in the top-right corner.
- Choose Email.
- Set the frequency (daily, weekly, or monthly), recipients, and file format (PDF).
- Save.
This is fast, but limited — it sends a snapshot of exactly what's on screen, with no ability to combine multiple data sources or add commentary automatically.
Option 2: Looker Studio Scheduled Delivery
For more control over layout and the ability to combine GA4 with other data sources:
- Build a report in Looker Studio connected to your GA4 property (see our guide on connecting GA4 to Looker Studio).
- Click Share → Schedule email delivery.
- Set a recurring cadence, recipients, and whether to deliver a PDF snapshot or a link to the live, always-current report.
This is the best option for most teams — it requires no coding, supports a polished, focused layout, and can combine GA4 with Google Ads, Search Console, or other connected sources in one report.
Option 3: A Custom Script Using the GA4 Data API
For full control over format, destination (Slack, email, an internal dashboard), and custom calculations GA4's UI doesn't natively support, use the GA4 Data API directly:
npm install @google-analytics/data
const { BetaAnalyticsDataClient } = require("@google-analytics/data");
const analyticsDataClient = new BetaAnalyticsDataClient();
async function getWeeklySummary(propertyId) {
const [response] = await analyticsDataClient.runReport({
property: `properties/${propertyId}`,
dateRanges: [{ startDate: "7daysAgo", endDate: "yesterday" }],
dimensions: [{ name: "sessionDefaultChannelGroup" }],
metrics: [
{ name: "sessions" },
{ name: "engagementRate" },
{ name: "conversions" },
{ name: "totalRevenue" },
],
orderBys: [{ metric: { metricName: "sessions" }, desc: true }],
});
return response.rows.map((row) => ({
channel: row.dimensionValues[0].value,
sessions: row.metricValues[0].value,
engagementRate: row.metricValues[1].value,
conversions: row.metricValues[2].value,
revenue: row.metricValues[3].value,
}));
}
module.exports = { getWeeklySummary };
Sending the Report to Slack
Combine the API call above with a simple formatted message posted to a Slack webhook, run on a schedule (a cron job, a scheduled cloud function, or a CI pipeline's scheduled trigger):
const { getWeeklySummary } = require("./ga4-report");
async function postWeeklyReportToSlack(propertyId, webhookUrl) {
const data = await getWeeklySummary(propertyId);
const rows = data
.map(
(row) =>
`• *${row.channel}*: ${row.sessions} sessions, ${row.conversions} conversions, $${row.revenue}`,
)
.join("\n");
await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `*Weekly GA4 Summary*\n${rows}`,
}),
});
}
postWeeklyReportToSlack("123456789", process.env.SLACK_WEBHOOK_URL);
Scheduling this with a weekly cron trigger (Monday morning, for example) delivers a concise summary directly into a team Slack channel — often more likely to actually get read than an emailed PDF sitting in an inbox.
Setting Up Service Account Access for the API
To run the GA4 Data API programmatically (outside of your own logged-in browser session), you need a service account with API access:
- In Google Cloud Console, create a project (or use an existing one) and enable the Google Analytics Data API.
- Create a Service Account, and generate a JSON key for it.
- In GA4, go to Admin → Property Access Management, and add the service account's email address as a user with at least Viewer access.
- Reference the downloaded JSON key file in your script's authentication configuration (typically via the
GOOGLE_APPLICATION_CREDENTIALSenvironment variable).
Choosing the Right Approach for Your Team
- A small team without engineering resources — GA4's built-in email reports or a Looker Studio scheduled report are the practical choice, requiring no code.
- A team wanting a combined, polished view across multiple data sources — Looker Studio is generally the best balance of effort and flexibility.
- A team needing custom logic, unusual destinations (Slack, an internal tool), or calculations GA4's UI doesn't support — the API-based custom script approach, while requiring some engineering setup, offers full control.
Keeping Automated Reports From Going Stale
Whichever method you choose, automated reports still need occasional human review:
- Confirm the report still reflects current business priorities every quarter or so, rather than running indefinitely unchanged.
- Spot-check the numbers periodically against GA4's own interface, especially after any tracking changes, to confirm the automation hasn't silently broken.
- Prune recipient lists — an automated report still going to someone who's changed roles or left the team is a common, easily overlooked form of clutter.
Adding Commentary to an Automated Report
A purely automated report, however well-formatted, still lacks the interpretation a human reviewer adds — "conversions dipped, likely due to the site migration mid-week" is more useful than the raw number alone. For teams relying heavily on automation, it's worth adding a lightweight manual step: a short written note appended before the automated report goes out, even if it's just two or three sentences from whoever owns the metric that week. This keeps the automation from feeling like an impersonal, unexplained data dump, while still saving the bulk of the manual effort automation is meant to eliminate.
Handling Report Failures Gracefully
Any automated pipeline — a scheduled script, a Looker Studio delivery, an API integration — can fail silently if a credential expires, an API quota is hit, or a property setting changes unexpectedly. Build in a simple failure notification (an error alert to a monitoring channel, or a fallback check a person performs periodically) so a broken automated report doesn't simply stop arriving without anyone noticing for weeks, which defeats much of the purpose of automating it in the first place.
FAQ about Automating Weekly Reports from Google Analytics

What's the easiest way to automate a GA4 report with no coding at all?
GA4's built-in scheduled email delivery, available directly from any report's share menu, requires no code and takes just a couple of minutes to set up.
Do I need to pay for the GA4 Data API to build a custom automated report?
No — the GA4 Data API is free to use within Google's standard usage quotas, though you'll need some development capability to build and host the script that calls it.
Can I combine data from GA4 and Google Ads in one automated report?
Yes, most easily through Looker Studio, which natively supports connecting multiple data sources and scheduling combined reports for delivery.
How do I authenticate a script to access GA4 data without logging in manually each time?
Use a Google Cloud service account, granted Viewer (or higher) access to your GA4 property, authenticating via a downloaded JSON credentials file rather than an interactive login.
Is it possible to send an automated GA4 report to Slack instead of email?
Yes — using the GA4 Data API to pull the data and a Slack incoming webhook to post a formatted message, triggered on a schedule via a cron job or scheduled cloud function.
How often should an automated report actually be reviewed by a person?
Even a fully automated report benefits from a periodic human review (quarterly is reasonable) to confirm it still reflects current priorities and that the underlying tracking hasn't silently broken.
Conclusion
Automating recurring Google Analytics reports frees your team from repetitive manual checking, whether through GA4's own built-in email delivery, a Looker Studio dashboard, or a custom API script for full control. Pick the option matching your team's technical capacity, and revisit it periodically so it keeps reflecting what actually matters for your website.


