GA Analytics Report Guide
View your organization's combined GA4 + Search Console AI analysis report (the main content), plus the latest metrics and history for a selected property/site (supporting detail).
๐ Overview
This page has two layers:
- Combined report (main) โ an AI analysis that looks at GA4 and Search Console data together. Click a past date in the history list on the right to view that day's report, and click "File this as an issue" to send any suggestion you like straight into a giip issue. Below it, turn on the "Auto-file an issue when a report is created" toggle and every newly created combined report is filed as a giip issue automatically (turning it on also files the latest report currently shown, if it has not been filed yet). While the toggle is off, the manual filing button stays available as before.
- Individual GA4 / GSC panels (supporting) โ below the combined report, separate panels show per-property KPI cards, recent daily history tables, and GSC top queries. These panels no longer generate their own AI analysis (the combined report above is the sole final analysis) โ they're for checking the raw numbers directly.
โ Prerequisites
- The GA4 property and (optionally) the Search Console site must be registered for your organization โ see GA Property Management and GSC Sites. If either source is missing, the combined report shows a "setup needed" link for it.
- Collection is running so there is data (see "Setting up collection" below).
๐ View a report
- The combined report loads automatically when you open the page. Click a date in the history list on the right to switch to that day's report, or click "Back to latest" to return to the current one.
- To see individual metrics, pick a registered property/site from the dropdown (or enter one manually) in the GA4/GSC panels below.
๐ Metrics
| Metric | Meaning |
|---|---|
| Active Users | Distinct active users |
| Sessions | Number of sessions |
| Page Views | Screen/page views |
| Bounce Rate | Share of single-interaction sessions (shown as %) |
| Conversions | Conversion events |
| Avg. Session (s) | Average session duration, seconds |
| Clicks / Impressions (GSC) | Search Console search-result clicks/impressions |
| CTR / Avg. Position (GSC) | Click-through rate (%) / average search position |
๐ค How the AI tells pages apart
The AI behind the combined report looks at each URL path and automatically classifies it as either a marketing/public page (a landing page, blog post, etc. visitors see without logging in) or a login-gated product/admin screen (e.g. a dashboard, an admin-only page). The latter is automatically excluded from being flagged as a conversion-funnel page.
If the automatic classification doesn't match your setup (e.g. you deliberately run some public pages without a login wall), or you want the AI to better reflect your service's own direction and target customers, you can add organization-specific (csn-scoped) guidance in Admin > Gareport AI Custom Prompt. It's appended after the global rules, not a replacement for them.
๐ AEO/GEO readiness
A panel that checks whether your pages are structured so search engines, answer engines and generative AI can cite them, across eight items, and produces a score per page. It appears below the combined report.
The eight items checked
| Item | What it looks at |
|---|---|
| Structured FAQ | Whether questions and answers are present on the page in a machine-readable form |
| Author | Whether the person or organization who wrote it is named, with a verifiable address |
| Organization | Whether the publishing organization's name and its main address or logo are stated |
| Date | Whether publish and update dates exist in a machine-readable form and do not contradict each other |
| Sources | Whether the body text links out to supporting sources, and whether those sources come from more than one place |
| Comparable information | Whether the body has a table you can actually compare with (a header row, and two or more things being compared) |
| Numbers with evidence | Whether every number in the body comes with a period, a source or a supporting link |
| Entity relationships | Whether what the page is about is linked to the identifiers it corresponds to elsewhere |
Each item is judged as met (2 points) / partially met (1 point) / absent (0 points), and any item that could not be judged is left out of the score.
How to read the score
- Always read it together with
judged n/8. The score alone is not enough: it says "what percentage of the points available on the items we judged did this page earn", and how many items that was appears only in thejudged n/8next to it. - It is not a score for your whole site. We measure your top search-entry pages (up to 20 per run) and nothing else. That is also why we never average page scores into a "site score".
โ(excluded from scoring) and0(absent) are different.0is the statement "we read the page and that element was not there".โmeans "we did not judge it". Counting a page we could not read as 0 would be reporting a defect that does not exist, so we do not do it.- The denominator can differ per item. A page with no numbers in its body is excluded from "numbers with evidence" entirely. So even with 10 pages measured, "numbers with evidence" may only have 6 judged pages. That is exactly why the per-item table has no percentage column.
- Grades (A/B/C, good/bad), industry averages and percentiles are not provided. The only comparison we make is against the same page's own earlier measurements.
Measurement runs once a week
The check runs once, on Sunday. Changes you make to content are not reflected immediately โ the score changes from the next run onward. The measured-on date above the panel tells you when the values were taken, and if that date is more than 14 days old the panel adds a note that content changes made since then are not reflected.
AEO comes out as report narrative, not as a score
Direct answers to questions, unambiguous facts, service definitions, term definitions and worked examples โ these five do not produce a score. Instead the AI judges them inside the combined report and writes them up, tagged [EXPERT_HYPOTHESIS], as "under which heading on which page you should add what".
The reason there is no score is that this is not a measurement that returns the same answer when repeated. The eight items are counted straight off the page structure, so repeated runs give the same value. "Does this paragraph answer the question directly", on the other hand, is an interpretation; if the answer shifts between runs, a score trend stops meaning anything. So the eight are scored and the five are narrated. Where the report quotes a measured value verbatim, it is tagged [MEASURED].
When no score is shown
| Symptom | Cause | What to do |
|---|---|---|
| "No AEO/GEO measurement data" | The weekly check has never run for this organization yet | Check that a GSC site or GA4 property is registered, then wait for the next run. |
| A particular page is not in the list | Only top search-entry pages are measured โ other pages are not | Once that page accumulates search entries it will be picked up by a later run. |
| Score cell says "not measured โ no score" | The page could not be read โ no such address (4xx), fetch failure, or robots.txt disallows collection | Read the reason in the "fetch" column and check the address, the connection and robots.txt. |
| Score cell says "too few items judged โ no score" | The page was read, but fewer than 6 of the 8 items could be judged | The structured data is empty, or the body area could not be identified. Pages rendered only by JavaScript have no structured data we can read. |
An item cell shows โ | That item has nothing to measure on that page (for example, zero numbers in the body) | This is not a defect. It is left out of the score's denominator. |
โ๏ธ Setting up collection (admin)
Metrics are collected by GIIP agents/servers and analyzed together by AI on a regular schedule. One-time setup:
- Register the GA4 property (GA Property Management) and the GSC site (GSC Sites) โ both sources need to be registered for the combined report to be complete.
- Service account key โ create a Google service account with GA4 read access and share the property with it. Place the key JSON at the path specified in giipdb
mgmt/ga-collector.config.json.sample'sserviceAccountKeyFilefield (actual path:giipdb/.secrets/ga-service-account.json, gitignored). GIIP'sProcessGaCollect(giipfaw timer function) reads this file and calls the Google Data API directly. - Collection job โ
ProcessGaCollect(a giipfaw timer function) automatically collects registered active properties by reading from DB (tGaConfig). No separate PC/agent deployment is needed. The CQE guide and giipdbdocs/30_Specs/CQE_SPECIFICATION.mdapply only to the legacy agent-based collection method. - AI analysis (combined) โ giipfaw's
ProcessComboReportreads GA4 and GSC data together and produces the combined report. If the sample size is too small (e.g. too few visitors), the report notes that limitation.
Once collection runs, this page fills in automatically.
Troubleshooting
| Symptom | Cause | Solution |
|---|---|---|
| "No report yet" | The combined-report batch hasn't run yet | Verify collection/setup and wait for the next run. |
| A "setup needed" link appears | Either the GA4 property or the GSC site isn't registered | Register it via the linked page (GA Property Management / GSC Sites). |
| Property/site dropdown is empty | No properties/sites registered for this organization | Register one in the corresponding management page. |
| 403 / Access denied | You lack permission for the property's organization | Use an organization you belong to. |
| The AI misunderstands our service structure | Automatic page classification doesn't fit our organization's exceptions | Add guidance in the Gareport AI Custom Prompt page. |
๐ Latest-data query API for AI
A read-only API that lets an external AI read the latest GA4/GSC snapshot and combined report GIIP has already collected โ all in one call โ using only the organization identifier (csn) and that organization's secret key (SK), without interpreting the screen or signing in to a Google account. It does not include any re-collection, re-analysis, or configuration-change capability.
โ ๏ธ Scope limit: This API provides only the single latest snapshot โ it does not include the on-screen history list (past dated reports) or the full daily history table. Only the most recently collected/generated data is queryable. If you need historical per-date reports or daily history, use the "History (by-date, multi-record) API for AI" (giipGareportHistory) section below.
Request
| Item | Value |
|---|---|
| Method | GET |
| URL | https://giipfaw.azurewebsites.net/api/giipGareportSnapshot?csn={CSN} |
| Header | x-api-key: {SK} |
| Parameter | a single positive integer csn |
Success response (HTTP 200)
{
"csn": 47,
"retrievedAt": "2026-09-01T00:00:00Z",
"sources": {
"gsc": { "status": "READY", "siteCount": 1 },
"ga4": { "status": "READY", "propertyCount": 1 },
"combinedReport": { "status": "READY" }
},
"gscSites": [ { "siteUrl": "...", "label": "...", "collectedAt": "...", "data": { } } ],
"ga4Properties": [ { "propertyId": "...", "label": "...", "collectedAt": "...", "data": { } } ],
"combinedReport": { "reportId": 0, "generatedAt": "...", "dataSources": "ga+gsc", "missingConfig": null, "language": "en", "content": "## 1. Current Situation\nActive users are up 12% over the previous 28 days...\n\n## 2. Today's Core Bottleneck\nLanding page A has a 78% bounce rate, blocking conversion from incoming traffic...\n\n## 3. Evidence\n[MEASURED] ...\n\n## 4. Actions To Execute Now\nTarget: /pricing ...\n\n## 5. Judgments On Hold\n..." }
}
gscSites[].datacontains that site's latest raw GSC JSON (totals,topQueries,topPageQueries,date,range,collectedAt,source) verbatim.ga4Properties[].datais that property's latest raw GA4 JSON object, containing the following fields (per giipfawProcessGaCollect's collection schema):propertyId,range(the collected date),collectedAt,sourcemetrics:activeUsers,sessions,screenPageViews,bounceRate,conversions,averageSessionDurationtopPages: top 10 pages by views โ each item haspagePath,screenPageViews,bounceRate,averageSessionDurationlandingPages: top 10 landing pages by sessions โ each item haslandingPage,sessions,bounceRateevents: top 20 events by count โ each item haseventName,eventCountcoreWebVitals: populated only when both a site URL and the organization's own PageSpeed API key are configured, otherwisenull. When present, each ofmobile/desktophasperformanceScore,lcpMs,clsScore,inpMs,fcpMs,ttfbMsperiods: per comparison window (current_3d,current_7d,current_28d,previous_28d,current_90d)startDate/endDate/metrics(nullif that collection failed)
combinedReportis the single latest combined report (nullif none).contentis a markdown string made of the same 5 sections shown above (Current Situation / Today's Core Bottleneck / Evidence / Actions To Execute Now / Judgments On Hold) โ the example above is only illustrative; actual values vary by organization and period.gscKeyJson,gaKeyJson, the Google service account key, SK, AK, and DB connection details are never included in any response.
Error response
The error body is always in the form { "error": { "code": "...", "message": "..." } }.
| Condition | HTTP | error.code |
|---|---|---|
| SK missing or invalid | 401 | UNAUTHENTICATED |
| SK cannot access the requested csn | 403 | FORBIDDEN_CSN |
csn missing, non-numeric, or โค 0 | 400 | INVALID_CSN |
| Server or DB error | 500 | INTERNAL_ERROR |
Call example (with environment variables, no real secrets)
export GIIP_API_BASE_URL="https://giipfaw.azurewebsites.net"
export GIIP_CSN="47"
export GIIP_SK="set_at_runtime_only"
curl --fail-with-body \
-H "x-api-key: ${GIIP_SK}" \
"${GIIP_API_BASE_URL}/api/giipGareportSnapshot?csn=${GIIP_CSN}"
โ ๏ธ Security: Never put the SK in a URL, an issue, a repository, a prompt body, or logs. Pass it only from a runtime environment variable or a secret store.
Status values and the action the AI should take
GSC data is usually delayed by two to three days (Google finalization lag).
| Status | Meaning | Action the AI should take |
|---|---|---|
READY | An active property exists and has the latest collected raw data | Summarize that data as fact |
NOT_CONFIGURED | No active property exists for this csn | Don't guess โ report it as "not configured" as-is |
NO_DATA | An active property exists but has no latest collected data | Don't guess โ report it as "no data" as-is |
Fixed AI call procedure
- Query the snapshot exactly once.
- Check each status in
sourcesfirst. - Summarize only
READYdata as fact; reportNOT_CONFIGURED/NO_DATAas-is without guessing. - Treat the combined report's
contentas suggestions and the numbers in the GSC/GA4dataas factual data, keeping the two distinct. - If you need past reports or daily history, use the History (by-date, multi-record) API (giipGareportHistory) below instead of this snapshot API โ the snapshot covers "the current latest state" and the history API covers "per-date changes within a range."
๐ History (by-date, multi-record) API for AI
Unlike the snapshot API above, which returns only "the single latest record", this read-only history API returns multiple combined reports and GA4/GSC daily raw data (paginated) within a date range (from/to). Use this API to determine, on a per-date basis, "whether collection ran correctly up to yesterday." Like the snapshot API, it has no re-collection, re-analysis, or configuration-change capability.
Request
| Item | Value |
|---|---|
| Method | GET |
| URL | https://giipfaw.azurewebsites.net/api/giipGareportHistory?csn={CSN}&from={YYYY-MM-DD}&to={YYYY-MM-DD}&page={N}&pageSize={N} |
| Header | x-api-key: {SK} |
| Parameter | Required | Meaning |
|---|---|---|
csn | Required | Organization number (positive integer) |
from | Optional | Query start date (YYYY-MM-DD). Defaults to 30 days before to |
to | Optional | Query end date (YYYY-MM-DD, inclusive). Defaults to today (UTC) |
page | Optional | 1-based page number. Defaults to 1 |
pageSize | Optional | Records per page. Defaults to 30, max 100 (capped at 100 if exceeded) |
page/pageSizeapply independently to the combined-report history and to each GA4 property's / GSC site's daily history (a per-source window). Each source returns its owntotalCount/hasMore(orcombinedReportPagination) metadata separately.
Success response (HTTP 200)
{
"csn": 47,
"retrievedAt": "2026-10-30T00:00:00Z",
"from": "2026-09-30",
"to": "2026-10-30",
"page": 1,
"pageSize": 30,
"combinedReportPagination": { "page": 1, "pageSize": 30, "totalCount": 12, "hasMore": false },
"combinedReportHistory": [
{ "reportId": 0, "generatedAt": "2026-10-30T00:00:00Z", "dataSources": "ga+gsc", "missingConfig": null, "language": "en", "content": "## 1. Current Situation ...\n## 2. Today's Core Bottleneck ...\n## 3. Evidence ...\n## 4. Actions To Execute Now ...\n## 5. Judgments On Hold ..." }
],
"gscSites": [
{ "siteUrl": "...", "label": "...", "totalCount": 30, "page": 1, "pageSize": 30, "dailyHistory": [ { "collectedAt": "2026-10-29T00:00:00Z", "data": { } } ] }
],
"ga4Properties": [
{ "propertyId": "...", "label": "...", "totalCount": 30, "page": 1, "pageSize": 30, "dailyHistory": [ { "collectedAt": "2026-10-29T00:00:00Z", "data": { } } ] }
]
}
combinedReportHistory[]holds the combined reports within the range as multiple records in newest-first order. Eachcontentis the same 5-section markdown string as the snapshot API (Current Situation / Today's Core Bottleneck / Evidence / Actions To Execute Now / Judgments On Hold) โ the example above is only illustrative; actual values vary by organization and period.gscSites[].dailyHistory[].data/ga4Properties[].dailyHistory[].dataare that date's raw GSC/GA4 collection JSON, using the same schema as the snapshot API'sdatafield (GA4 hasmetrics,topPages,landingPages,events,coreWebVitals,periods, etc.; GSC hastotals,topQueries,topPageQueries,date,range, etc.). The only difference is that it is "multiple records per date within a range" rather than "a single latest record."collectedAtis the collection time (UTC) of that daily record. Judge per-date collection from this value and thedate/rangeinsidedata.gscKeyJson,gaKeyJson, the Google service account key, SK, AK, and DB connection details are never included in any response.
Error response
The error body is always in the form { "error": { "code": "...", "message": "..." } } (same as the snapshot API).
| Condition | HTTP | error.code |
|---|---|---|
| SK missing or invalid | 401 | UNAUTHENTICATED |
| SK cannot access the requested csn | 403 | FORBIDDEN_CSN |
csn missing, non-numeric, or โค 0 | 400 | INVALID_CSN |
from/to malformed or from > to | 400 | INVALID_DATE_RANGE |
page is not an integer | 400 | INVALID_PAGE |
pageSize is not an integer | 400 | INVALID_PAGE_SIZE |
| Server or DB error | 500 | INTERNAL_ERROR |
Call example (with environment variables, no real secrets)
export GIIP_API_BASE_URL="https://giipfaw.azurewebsites.net"
export GIIP_CSN="47"
export GIIP_SK="set_at_runtime_only"
# Last 7 days of history (to check per-date whether collection ran through yesterday)
curl --fail-with-body \
-H "x-api-key: ${GIIP_SK}" \
"${GIIP_API_BASE_URL}/api/giipGareportHistory?csn=${GIIP_CSN}&from=2026-10-23&to=2026-10-29&page=1&pageSize=30"
โ ๏ธ Security: Never put the SK in a URL, an issue, a repository, a prompt body, or logs. Pass it only from a runtime environment variable or a secret store.
Fixed AI call procedure (determining missing collection)
- Set the evaluation range: to check "whether collection ran through yesterday", query with
to=yesterday's date andfrom=far enough in the past (e.g. 7 days ago). - Check dates per source: in each item of
ga4Properties[]/gscSites[], check whethercollectedAt(ordata'sdate/range) indailyHistory[]includes yesterday's date. - Determine missing collection: if an active property/site is registered (there is an item in that array) but there is no daily history record for yesterday at all, report it as "missing collection." However, since GSC is normally delayed 2โ3 days (Google finalization lag), factor that lag into the GSC missing-collection judgment (GA4 has almost no lag).
- Sweep all csn: repeat steps 1โ3 for each csn the account can access. An admin SK can access every csn; a regular SK can access only its own csn (requests for other csn return 403).
- Separate fact from suggestion:
combinedReportHistory[].content(the combined report) is a suggestion, while the numbers indailyHistory[].dataare factual data โ always base the missing-collection judgment on the presence/absence of dates in the latter (factual data).
Version: 1.7
Last Updated: 2026-10-30
Changelog: giip 4313 โ added the "History (by-date, multi-record) API for AI" (giipGareportHistory) section (including the procedure for determining missing collection by date range), and updated the snapshot API section's "history cannot be queried" wording to reference the history API. / giip #4023 โ added the "AEO/GEO readiness" section (the eight items checked, reading the score together with judged n/8, the difference between โ (excluded) and 0 (absent), the weekly run, why AEO comes out as report narrative rather than a score, and what to do when no score is shown). / giip 2709 โ added the "auto-file an issue when a report is created" toggle to the combined report (the manual button remains while the toggle is off). / giip #2068 โ documented that the API returns only the single latest snapshot, added the real ga4Properties[].data field schema, and expanded the combinedReport.content example.
Source File: giipv3/public/help/gareport.en.md