Automate Weekly Marketing Reports from GA4 with n8n + AI

AgentRoost · June 2, 2026 · 7 min read · View as Markdown
AgentRoost — n8n for Business

Every marketing team has a version of the same Monday ritual: someone opens GA4, exports last week's numbers, pastes them into a doc, writes two paragraphs of context, formats the table, and sends it to the distribution list. It takes 30–60 minutes and it happens 52 times a year. This post shows you how to build that workflow in n8n so it runs itself — and how an AI node writes the narrative paragraph so the output is actually readable, not just a raw data dump.

What the finished workflow does

  1. Fires every Monday at 08:00 (your time zone).
  2. Fetches last week's GA4 data: sessions, new users, bounce/engagement rate, goal completions, and top channel groupings.
  3. Optionally fetches spend data from Google Ads or Meta Ads (same pattern, different node).
  4. Passes the metrics to an AI/LLM node that writes a 150–200 word plain-English summary with a "What worked", "What to watch", and "Suggested next steps" structure.
  5. Sends the finished report as a formatted HTML email to your stakeholders.

Total node count: 6–8 nodes. Build time: roughly 45 minutes the first time.


Step 1 — Schedule Trigger

Drop a Schedule Trigger node. Set it to Cron mode and use:

0 8 * * 1

That fires at 08:00 every Monday. Set the Timezone field to match your team (e.g. Europe/Istanbul or America/New_York) — n8n respects it exactly, no UTC math needed.


Step 2 — Pull GA4 data with the Google Analytics node

Add a Google Analytics node (search "Google Analytics" in the node panel — it's the first-party one, not a custom HTTP Request).

Authentication: create a Google Analytics OAuth2 credential. You need a Google Cloud project with the Analytics Data API enabled, plus an OAuth 2.0 Client ID scoped to https://www.googleapis.com/auth/analytics.readonly. Paste the client ID and secret into n8n's credential modal, click Connect, and authorize. n8n handles token refresh from that point on.

Node config:

Field Value
Property ID Your GA4 numeric property ID (find it in GA4 → Admin → Property Settings)
Date Range last7Days (or use expressions: {{ $today.minus({days: 7}).toFormat('yyyy-MM-dd') }} for the start)
Dimensions sessionDefaultChannelGroup, country
Metrics sessions, newUsers, bounceRate, conversions, engagedSessions
Limit 20

The node outputs one item per dimension combination. A Summarize or Aggregate node can roll them up by channel group before passing to the AI step.


Step 3 — (Optional) Pull ad spend from Google Ads or Meta

If you run paid campaigns, add a second data fetch in parallel. For Google Ads, use an HTTP Request node hitting the Google Ads API:

POST https://googleads.googleapis.com/v18/customers/{customer_id}/googleAds:search

Body (minimal, returns last 7 days of campaign cost + impressions + clicks):

{
  "query": "SELECT campaign.name, metrics.cost_micros, metrics.impressions, metrics.clicks FROM campaign WHERE segments.date DURING LAST_7_DAYS"
}

Divide cost_micros by 1,000,000 for actual spend. A Set node can reshape the fields into clean labels before the merge step.

Use a Merge node (mode: Merge by Index or Append) to combine GA4 output with the ads data into a single payload.


Step 4 — Build the AI prompt with a Set node

Before calling the LLM, use a Set node to construct a structured prompt string. This keeps your prompt readable and lets you inject live values cleanly:

You are a marketing analyst. Below are last week's website and paid media metrics.

GA4 Summary:
- Sessions: {{ $json.sessions }}
- New Users: {{ $json.newUsers }}
- Bounce Rate: {{ $json.bounceRate }}%
- Conversions: {{ $json.conversions }}
- Top Channel: {{ $json.topChannel }}

Ad Spend: ${{ $json.totalSpend }} | Clicks: {{ $json.totalClicks }} | Impressions: {{ $json.impressions }}

Write a concise 150-200 word marketing performance summary with three sections:
1. What worked this week
2. What to watch (anomalies or drops)
3. Two specific recommended next steps

Tone: direct, data-backed, no filler.

Storing the prompt in a Set node (rather than inline in the AI node) also makes it easy to version and tweak without touching the node logic.


Step 5 — AI/LLM node writes the narrative

Add an AI node (labeled "Basic LLM Chain" or "Chat Model" depending on your n8n version). Point it at the prompt output from the previous Set node.

  • Model: any chat model in the list — GPT-4o, Claude 3.5 Sonnet, and Mistral Large all produce good analytical prose. Switch models without touching the rest of the workflow.
  • System prompt: "You are a concise marketing analyst. Return only the report text, no preamble."
  • Max tokens: 400 is enough for a 200-word summary.

The node outputs {{ $json.text }} — the finished paragraph.


Step 6 — Send the email

Add a Gmail node (or Send Email for SMTP). Build the HTML body by combining a header, a metrics table, and the AI narrative:

<h2>Weekly Marketing Report — {{ $today.minus({days:7}).toFormat('dd MMM') }} to {{ $today.minus({days:1}).toFormat('dd MMM yyyy') }}</h2>

<table>
  <tr><td>Sessions</td><td>{{ $('GA4 Fetch').item.json.sessions }}</td></tr>
  <tr><td>New Users</td><td>{{ $('GA4 Fetch').item.json.newUsers }}</td></tr>
  <tr><td>Conversions</td><td>{{ $('GA4 Fetch').item.json.conversions }}</td></tr>
</table>

<hr/>
<h3>AI Summary</h3>
<p>{{ $('AI Node').item.json.text }}</p>

Set To to a comma-separated list of stakeholder addresses, or pull them from a Google Sheets node if your list changes.


Common pitfalls

  • GA4 sampling on large date ranges. The Data API applies sampling for properties on the free tier with high-cardinality queries. Keep dimensions to 2–3 and use date ranges ≤ 30 days to stay in unsampled territory.
  • Merge node item count mismatch. If GA4 returns 12 rows and the Ads node returns 5 campaigns, "Merge by Index" will truncate. Use Append mode and let the AI node receive all rows, or aggregate both sides first.
  • OAuth token expiry. n8n auto-refreshes the GA4 token, but if the credential is dormant for more than 6 months Google may revoke it. Add an Error Trigger node that sends you a Slack or email alert when the workflow fails — catches this before a Monday report silently skips.

Running this on AgentRoost

This workflow needs to run reliably every Monday whether your laptop is on or not. That means an always-on instance, not a local n8n process you manually restart.

On AgentRoost you get your own n8n instance — your login, your data, your workflows — hosted on a public subdomain (https://<your-id>.agentroost.app). You own it: self-hosting without the DevOps. The Schedule Trigger fires on time because the instance is always running. Webhook URLs work immediately with no reverse-proxy setup.

The part that usually blocks teams: the AI node requires an OpenAI or Anthropic API key, another billing account, and BYOK configuration. On AgentRoost that step doesn't exist. LLM credits are included in the subscription. Drop the AI node, pick your model, write your prompt, and run — no API key, no second billing account.

Getting started takes about two minutes:

  1. Sign up at AgentRoost with email, Google, Microsoft, or Discord.
  2. Pick the n8n framework, name your instance.
  3. Your private n8n editor opens at https://<your-id>.agentroost.app.
  4. Build the workflow above — the AI node already has credits.

Pricing starts at $19.99/mo all-in with a 14-day money-back guarantee. Compare plans to see which tier fits your report volume and model preferences.


A weekly marketing report that writes itself and lands in inboxes before the team's Monday standup is not a complex automation project — it's eight n8n nodes and one afternoon of setup. The only thing that usually makes it feel harder than it is: the AI writing step requires a separate API account everywhere except here.

Frequently asked questions

Do I need to supply my own OpenAI or Anthropic API key for the AI node?

Not on AgentRoost. LLM/AI credits are included in every subscription tier, so the AI node is pre-wired and works the moment you drop it into the canvas. You pick the model (350+ available), set your prompt, and run — no BYOK step.

How does n8n connect to Google Analytics 4?

n8n ships a first-party Google Analytics node. You authenticate it once via OAuth (Google Cloud Console → Credentials → OAuth 2.0 Client ID, then paste into the n8n credential store). After that, every workflow run reuses the token automatically.

Can I change the schedule — daily instead of weekly, or a different time zone?

Yes. The Schedule Trigger node lets you set any cron expression and choose the instance's time zone. Switch to 0 8 * * 1 for Monday 08:00, 0 7 * * * for daily at 07:00, or use the visual picker in the node settings.

Where is workflow data stored when the workflow runs?

Execution data (logs, credentials, workflow state) lives on your own n8n instance — you own it. The LLM call routes to the model provider the same way any self-hosted n8n setup would when calling a third-party API; this is no different from using OpenAI or Anthropic directly.

What happens if I cancel my AgentRoost subscription?

You can cancel any time. There is a 14-day money-back guarantee on new subscriptions. After cancellation your instance is stopped; n8n workflows can be exported as JSON at any point before that so you can take them elsewhere.