Plan overview
GA4 Traffic Report
Pull GA4 acquisition, engagement, and cohort-retention data through an API connection point and turn it into chart-ready, day-by-day structured insights.
Best for
Marketing · Growth · Founders
Runs with
Google Analytics 4 · Acquisition · Retention cohorts
At a glance
04
Outputs
01
Capabilities
03
Teams
Core outputs
Acquisition insights
Engagement insights
Retention cohorts
Chart-ready rows
Capability requirements
What it solves
GA4 reporting means clicking through the UI every week and hand-copying numbers into a deck instead of getting a typed, repeatable dataset.
Replaces weekly manual GA4 exports with a repeatable plan.
Preserves raw numeric values for trustworthy charts.
Returns chart-ready rows you can drop straight into a report.
Workflow
Fetch acquisition, engagement, and cohort-retention reports from GA4.
Aggregate each into per-day chart rows with exact numeric values.
Return structured summaries and trends for acquisition, engagement, retention.
Implementation
Review the underlying FML plan — the sessions, tools, and typed schemas that define this workflow — and see exactly how it is instructed for repeatable execution.
FML Plan
google-analytics.fml
96 lines
system(`You are an expert data analyst. Review the provided Google Analytics 4 data and generate clear, insightful, structured reports for the end user. When extracting rows for chart data, preserve raw numeric values verbatim — never round or invent figures. `) parameter("property", type=string, default="484780505") # A Google Analytics GA4 property identifier (numeric ID only, e.g. 484780505). require apicp google_analytics call("google_analytics_runReport") -> acquisitionData { property = "{{ .params.property }}" body = {dateRanges: [{startDate: "7daysAgo", endDate: "today"}], dimensions: [{name: "date"}, {name: "firstUserDefaultChannelGroup"}], metrics: [{name: "newUsers"}, {name: "sessions"}, {name: "totalUsers"}], orderBys: [{dimension: {dimensionName: "date"}}]} } call("google_analytics_runReport") -> engagementData { property = "{{ .params.property }}" body = {dateRanges: [{startDate: "7daysAgo", endDate: "today"}], dimensions: [{name: "date"}, {name: "sessionDefaultChannelGroup"}], metrics: [{name: "engagedSessions"}, {name: "engagementRate"}, {name: "averageSessionDuration"}, {name: "screenPageViews"}], orderBys: [{dimension: {dimensionName: "date"}}]} } # Retention uses a `code:` block instead of declarative args because GA4 # cohortSpec requires absolute YYYY-MM-DD dates (relative "7daysAgo" # strings are rejected). Diaphora's `{{ .params.X }}` substitution only # works on top-level args, not deeply-nested body fields, so the dates are # computed in JS at runtime here and passed to the apicp tool with a fully # resolved body. call("ga_runReport_retention") -> retentionData { property = "{{ .params.property }}" code( const today = new Date(); const sevenDaysAgo = new Date(); sevenDaysAgo.setDate(today.getDate() - 7); const fmt = (d) => d.toISOString().slice(0, 10); runFunction("google_analytics_runReport", { property: args.property, body: { cohortSpec: { cohorts: [{ name: "last_7_days", dimension: "firstSessionDate", dateRange: { startDate: fmt(sevenDaysAgo), endDate: fmt(today), }, }], cohortsRange: { granularity: "DAILY", endOffset: 6 }, }, dimensions: [{ name: "cohort" }, { name: "cohortNthDay" }], metrics: [ { name: "cohortActiveUsers" }, { name: "cohortTotalUsers" }, ], orderBys: [{ dimension: { dimensionName: "cohortNthDay" } }], }, }); ) } session("analyze_acquisition", target="acquisition") { - Analyze the following Google Analytics User Acquisition data (last 7 days, broken down by date AND channel) and extract structured insights. For `summary` and `keyChannels`: identify the top performing acquisition channels across the entire week (aggregate newUsers across days). For `data` (chart-ready rows): emit ONE row per day, in chronological order. `label` = a short date like "Nov 19" derived from the `date` dimension (GA returns YYYYMMDD strings — convert to "MMM D"). `value` = the SUM of `newUsers` across ALL channels for that day (integer). `detail` = the top channel that day plus its share, e.g. "Direct led with 58 (62%)". Data: {{ .vars.acquisitionData }} schema { summary: string # Executive summary of acquisition performance. keyChannels: string[] # Top performing acquisition channels based on new users and sessions. data: { label: string # Channel name (e.g. "Organic Search", "Direct", "Referral"). value: int # New users for this channel (integer, taken directly from the report). detail?: string # Secondary metrics for this channel (e.g. sessions, total users). }[] } } session("analyze_engagement", target="engagement") { - Analyze the following Google Analytics Engagement data (last 7 days, broken down by date AND channel) and extract structured insights. For `summary` and `topChannels`: identify the top channels driving engaged sessions across the entire week. For `data` (chart-ready rows): emit ONE row per day, in chronological order. `label` = a short date like "Nov 19" (convert YYYYMMDD → "MMM D"). `value` = the SUM of `engagedSessions` across ALL channels for that day (integer). `detail` = an engagement-rate hint for that day, e.g. "engagement rate ~64.2% · avg session 1m 42s". Data: {{ .vars.engagementData }} schema { summary: string # Analysis of engagement metrics. topChannels: string[] # Channels driving the most engaged sessions. data: { label: string # Channel name. value: int # Engaged sessions for this channel (integer, taken directly from the report). detail?: string # Engagement rate, average session duration, and pageviews for this channel. }[] } } session("analyze_retention", target="retention") { - Analyze the following Google Analytics Retention/Cohort data (last 7 days) and extract structured insights AND chart-ready rows. For each cohortNthDay bucket, emit a `data` row with `label` = "Day N" (e.g. "Day 0", "Day 1") and `value` = the raw `cohortActiveUsers` count (integer). Put a short detail like "of 3,201 cohort users · 24.1% retained" in `detail`. Data: {{ .vars.retentionData }} schema { summary: string # Summary of user retention over the 7 day cohort. retentionTrend: string # Trend analysis of retention. data: { value: int # Active users in this cohort day (integer). detail?: string # Cohort size and retention percentage. label: string # Cohort day label (e.g. "Day 0", "Day 1"). }[] } }