giip
SES Proposal
16 min read

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).

๐Ÿ”— Open GA Analytics Report โ†’

๐Ÿ“‹ 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

  1. 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.
  2. Collection is running so there is data (see "Setting up collection" below).

๐Ÿ”Ž View a report

  1. 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.
  2. To see individual metrics, pick a registered property/site from the dropdown (or enter one manually) in the GA4/GSC panels below.

๐Ÿ“Š Metrics

MetricMeaning
Active UsersDistinct active users
SessionsNumber of sessions
Page ViewsScreen/page views
Bounce RateShare of single-interaction sessions (shown as %)
ConversionsConversion 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

ItemWhat it looks at
Structured FAQWhether questions and answers are present on the page in a machine-readable form
AuthorWhether the person or organization who wrote it is named, with a verifiable address
OrganizationWhether the publishing organization's name and its main address or logo are stated
DateWhether publish and update dates exist in a machine-readable form and do not contradict each other
SourcesWhether the body text links out to supporting sources, and whether those sources come from more than one place
Comparable informationWhether the body has a table you can actually compare with (a header row, and two or more things being compared)
Numbers with evidenceWhether every number in the body comes with a period, a source or a supporting link
Entity relationshipsWhether 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 the judged n/8 next 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) and 0 (absent) are different. 0 is 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

SymptomCauseWhat to do
"No AEO/GEO measurement data"The weekly check has never run for this organization yetCheck that a GSC site or GA4 property is registered, then wait for the next run.
A particular page is not in the listOnly top search-entry pages are measured โ€” other pages are notOnce 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 collectionRead 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 judgedThe 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:

  1. 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.
  2. 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's serviceAccountKeyFile field (actual path: giipdb/.secrets/ga-service-account.json, gitignored). GIIP's ProcessGaCollect (giipfaw timer function) reads this file and calls the Google Data API directly.
  3. 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 giipdb docs/30_Specs/CQE_SPECIFICATION.md apply only to the legacy agent-based collection method.
  4. AI analysis (combined) โ€” giipfaw's ProcessComboReport reads 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

SymptomCauseSolution
"No report yet"The combined-report batch hasn't run yetVerify collection/setup and wait for the next run.
A "setup needed" link appearsEither the GA4 property or the GSC site isn't registeredRegister it via the linked page (GA Property Management / GSC Sites).
Property/site dropdown is emptyNo properties/sites registered for this organizationRegister one in the corresponding management page.
403 / Access deniedYou lack permission for the property's organizationUse an organization you belong to.
The AI misunderstands our service structureAutomatic page classification doesn't fit our organization's exceptionsAdd 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

ItemValue
MethodGET
URLhttps://giipfaw.azurewebsites.net/api/giipGareportSnapshot?csn={CSN}
Headerx-api-key: {SK}
Parametera 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[].data contains that site's latest raw GSC JSON (totals, topQueries, topPageQueries, date, range, collectedAt, source) verbatim.
  • ga4Properties[].data is that property's latest raw GA4 JSON object, containing the following fields (per giipfaw ProcessGaCollect's collection schema):
    • propertyId, range (the collected date), collectedAt, source
    • metrics: activeUsers, sessions, screenPageViews, bounceRate, conversions, averageSessionDuration
    • topPages: top 10 pages by views โ€” each item has pagePath, screenPageViews, bounceRate, averageSessionDuration
    • landingPages: top 10 landing pages by sessions โ€” each item has landingPage, sessions, bounceRate
    • events: top 20 events by count โ€” each item has eventName, eventCount
    • coreWebVitals: populated only when both a site URL and the organization's own PageSpeed API key are configured, otherwise null. When present, each of mobile/desktop has performanceScore, lcpMs, clsScore, inpMs, fcpMs, ttfbMs
    • periods: per comparison window (current_3d, current_7d, current_28d, previous_28d, current_90d) startDate/endDate/metrics (null if that collection failed)
  • combinedReport is the single latest combined report (null if none). content is 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": "..." } }.

ConditionHTTPerror.code
SK missing or invalid401UNAUTHENTICATED
SK cannot access the requested csn403FORBIDDEN_CSN
csn missing, non-numeric, or โ‰ค 0400INVALID_CSN
Server or DB error500INTERNAL_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).

StatusMeaningAction the AI should take
READYAn active property exists and has the latest collected raw dataSummarize that data as fact
NOT_CONFIGUREDNo active property exists for this csnDon't guess โ€” report it as "not configured" as-is
NO_DATAAn active property exists but has no latest collected dataDon't guess โ€” report it as "no data" as-is

Fixed AI call procedure

  1. Query the snapshot exactly once.
  2. Check each status in sources first.
  3. Summarize only READY data as fact; report NOT_CONFIGURED/NO_DATA as-is without guessing.
  4. Treat the combined report's content as suggestions and the numbers in the GSC/GA4 data as factual data, keeping the two distinct.
  5. 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

ItemValue
MethodGET
URLhttps://giipfaw.azurewebsites.net/api/giipGareportHistory?csn={CSN}&from={YYYY-MM-DD}&to={YYYY-MM-DD}&page={N}&pageSize={N}
Headerx-api-key: {SK}
ParameterRequiredMeaning
csnRequiredOrganization number (positive integer)
fromOptionalQuery start date (YYYY-MM-DD). Defaults to 30 days before to
toOptionalQuery end date (YYYY-MM-DD, inclusive). Defaults to today (UTC)
pageOptional1-based page number. Defaults to 1
pageSizeOptionalRecords per page. Defaults to 30, max 100 (capped at 100 if exceeded)

page/pageSize apply 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 own totalCount/hasMore (or combinedReportPagination) 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. Each content is 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[].data are that date's raw GSC/GA4 collection JSON, using the same schema as the snapshot API's data field (GA4 has metrics, topPages, landingPages, events, coreWebVitals, periods, etc.; GSC has totals, 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."
  • collectedAt is the collection time (UTC) of that daily record. Judge per-date collection from this value and the date/range inside data.
  • 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).

ConditionHTTPerror.code
SK missing or invalid401UNAUTHENTICATED
SK cannot access the requested csn403FORBIDDEN_CSN
csn missing, non-numeric, or โ‰ค 0400INVALID_CSN
from/to malformed or from > to400INVALID_DATE_RANGE
page is not an integer400INVALID_PAGE
pageSize is not an integer400INVALID_PAGE_SIZE
Server or DB error500INTERNAL_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)

  1. Set the evaluation range: to check "whether collection ran through yesterday", query with to=yesterday's date and from=far enough in the past (e.g. 7 days ago).
  2. Check dates per source: in each item of ga4Properties[]/gscSites[], check whether collectedAt (or data's date/range) in dailyHistory[] includes yesterday's date.
  3. 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).
  4. 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).
  5. Separate fact from suggestion: combinedReportHistory[].content (the combined report) is a suggestion, while the numbers in dailyHistory[].data are 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