Web Analytics Module Setup
The Web Analytics module pulls GA4 and Google Search Console data into a plain-language dashboard inside Flo (Amministrazione → Analytics). It reads Google's APIs through one fleet-wide service account, configured once by the operator.
There are two sides to wiring it up:
- Operator (once per fleet) — provision the Google Cloud service account and put its key into the
GOOGLE_ANALYTICS_SA_JSONsecret on each instance. - Per customer — grant that service account read access to the customer's GA4 property and Search Console, then enter the IDs on the config page and verify.
The service-account JSON lives only in the GOOGLE_ANALYTICS_SA_JSON environment variable. It is a fleet-level secret and is never stored in any tenant database — the per-tenant config row holds only the GA4 property id, the GSC site, the vertical, and the enable flag.
The "not connected on this server yet" notice
If the config page shows an amber notice like "Analytics isn't connected on this server yet. Ask the Flo operator to set it up before linking", it means GOOGLE_ANALYTICS_SA_JSON is not set on that instance. This is expected on a fresh instance — complete the operator steps below first. The backend log line confirms it:
Web analytics: GOOGLE_ANALYTICS_SA_JSON not set — ETL disabled.
Part A — Operator: provision the service account (once)
You need the gcloud CLI authenticated against a Google Cloud project you control.
1. Select (or create) the project
gcloud config set project <PROJECT_ID>
2. Enable the two read APIs
gcloud services enable analyticsdata.googleapis.com searchconsole.googleapis.com
analyticsdata.googleapis.com— GA4 reporting (Data API).searchconsole.googleapis.com— Search Console search-analytics.
3. Create the service account
gcloud iam service-accounts create flo-web-analytics \
--display-name="Flo Web Analytics (read-only)"
This yields the account email flo-web-analytics@<PROJECT_ID>.iam.gserviceaccount.com — this is the address customers grant access to. It is non-sensitive; Flo surfaces it on the config page so the customer can copy it.
4. Download a key
gcloud iam service-accounts keys create flo-web-analytics-key.json \
--iam-account="flo-web-analytics@<PROJECT_ID>.iam.gserviceaccount.com"
Keep flo-web-analytics-key.json safe — treat it like any password. The same key can serve every tenant; you do not need a separate account per customer.
5. Set the secret on the instance
The backend reads the variable as raw JSON (GoogleCredential.FromJson). Because the .env file is line-based, pass the key minified to a single line:
flo --vps production config env set <instance-id> \
GOOGLE_ANALYTICS_SA_JSON "$(jq -c . flo-web-analytics-key.json)" --restart
The value must be the JSON itself, not a filename. --restart is required: the credential is built once at startup, so a running container won't pick up a new key until it restarts.
Repeat for every instance that should have analytics. The scopes are fixed read-only: analytics.readonly + webmasters.readonly.
6. Verify it loaded
flo --vps production config web-analytics status <instance-id>
The backend log should now show the ETL enabling instead of the "not set" line. The config page in the app will show the service-account email instead of the amber notice.
Part B — Per customer: link GA4 + Search Console
These steps are split between Google's consoles and Flo's Amministrazione → Analytics config page.
1. Grant the service account access in Google
- GA4 — go to Amministrazione → Gestione dell'accesso alla proprietà (Property Access Management), add the service-account email with the Viewer (Visualizzatore) role. Read-only is enough.
- Search Console — go to Impostazioni → Utenti e autorizzazioni (Settings → Users and permissions), add the same email with Full access.
This is separate from adding team.ledges@gmail.com as Editor (see GA4 Setup for a Customer). The human Ledges account manages the property; the service account only reads data for the dashboard.
2. Enter the IDs in Flo and verify
On the Amministrazione → Analytics config page:
- Copy the service-account email shown at the top (use the Copy button) if you still need it for step 1.
- Enter the GA4 property id (the numeric id, e.g.
542344364). - Enter the Search Console site exactly as Google shows it (
sc-domain:example.comfor a domain property, or the fullhttps://…/URL for a URL-prefix property). - Save, then click Verify access.
A green result confirms both GA4 and Search Console are reachable. The next ETL tick then backfills history and the dashboard populates.
Troubleshooting verification errors
The Verify access result maps to a stable error code:
| Result | Meaning | Fix |
|---|---|---|
not_configured | GOOGLE_ANALYTICS_SA_JSON not set on this instance | Do Part A. |
permission_denied | Service account not granted access | Add the email as Viewer in GA4 and Full in Search Console (Part B step 1). |
invalid_config | Property / site not found | Check the GA4 property id and the GSC site string match Google exactly. |
quota_exceeded | Too many requests | Wait a minute and verify again. |
unknown | Verification didn't complete | Re-check the IDs and that the service account has access, then retry. |
Checklist
| Step | Side | Result |
|---|---|---|
| Enable GA4 Data API + Search Console API | Operator | Google APIs reachable |
Create flo-web-analytics service account + key | Operator | One reusable read-only account |
Set GOOGLE_ANALYTICS_SA_JSON (minified) + restart | Operator | Instance can call Google |
| Add SA email as Viewer in GA4 | Per customer | GA4 data readable |
| Add SA email as Full in Search Console | Per customer | Search data readable |
| Enter GA4 id + GSC site, Save, Verify access | Per customer | Dashboard backfills and populates |