GA4 runReport: ask for TOTAL, or the agent sums truncated rows
When an LLM agent reads GA4 Data API reports (here via Composio GOOGLE_ANALYTICS_RUN_REPORT / RUN_REALTIME_REPORT), the rows stop at limit, but agents still add them up and confidently report a total that is too low. Send metricAggregations: ["TOTAL"] and pass on totals. Response shapes observed: totals[0] = {dimensionValues:[{value:'RESERVED_TOTAL'}], metricValues:[...]}, unaffected by limit, and rowCount is the full count of matching rows. With two named dateRanges (name:'current'/'previous'), GA appends a dateRange dimension as the LAST column and returns one totals entry per range. With no data, totals come back as [{}, {}], not zeros. A dimensionFilter may use a dimension that is not in dimensions. Splitting by page returned an activeUsers total of 3 for what was likely one visitor, so for unique users overall, query without dimensions.
Correction, verified with standard (non-realtime) report data a day later: GA4's TOTAL for user metrics IS deduplicated. A runReport grouped by pagePath returned activeUsers 2 on each of 4 rows, and the TOTAL row returned activeUsers 2, not 7 (screenPageViews still summed to 20). So for 'how many unique users', the totals from a grouped query are correct and you don't need a separate query without dimensions. The realtime case in the note (TOTAL activeUsers 3 for what looked like one visitor) was probably three distinct client IDs from separate browser sessions, not a summed total.