# Full website onboarding — GA4, GSC, BigQuery, Vercel and Metricsjar

Use this runbook only when the user explicitly asked for the analytics stack to
be created or repaired. The shorter `connect.md` path assumes those sources
already exist.

Keep a durable ledger in the target repository from the first probe. Record
every identity, project/property/stream id, dataset, IAM grant, DNS record,
deployment, console switch, verification result, blocker, and product gap.
Never put tokens, API secrets, or credential contents in it.

Mirror each material result into the Metricsjar setup session:

```sh
bun ~/.metricsjar/cli.ts onboard event \
  --title "<what changed>" --type "<source>" --status ok \
  --detail "<result>" --evidence "<ids or verification>" --undo "<undo>"
```

Use `onboard needs-user --message "<exact action + deep link>"` at identity,
billing, or paid-data checkpoints, then `onboard resume` after the answer.

## Completion contract

Do not stop at “configured.” Finish when all of these are true:

- the production site sends GA4 and Vercel Analytics;
- a verified Search Console domain property exists and its sitemap succeeds;
- GA4 and Search Console are associated;
- GA4 Daily + Streaming BigQuery export is enabled;
- Search Console bulk BigQuery export is active;
- dev-telemetry (when available) passes its doctor for Firebase, Log Analytics,
  and the linked logs dataset;
- the site is visible in the requested Metricsjar account;
- tracked keywords are loaded;
- Metricsjar Pipe health has no red rows (new exports may be yellow/warming);
- the scheduled refresh passes `doctor --as-cron` and `cron status`.

Google may take up to 48 hours to create first-export tables. A verified export,
correct IAM, and a yellow `warming up` pipe satisfy completion; waiting for
traffic rows does not.

## 1. Pin identities before changing anything

Resolve and record:

- the requested Google account;
- the GCP project and billing state;
- the GA4 account/property;
- the Vercel team/project and production domain;
- the Metricsjar `whoami` account.

Use `CLOUDSDK_CORE_ACCOUNT=<email>` on every Google command. Never change the
global gcloud account. If more than one plausible identity exists, the user
chooses.

Billing attachment is a financial action. Inspect it read-only, name the exact
billing account and project, and get explicit confirmation immediately before
linking them.

## 2. Establish the web surface

Inspect the deployed site and repository for an existing GA tag, Vercel
Analytics, canonical hostname, favicon, `robots.txt`, and sitemap. Verify the
real hydrated page in a browser; server HTML alone misses client-loaded tags.

When the user authorized source instrumentation:

1. Create or reuse one GA4 web stream for the production domain.
2. Add the GA tag once at the application root and carry a production
   environment label when the codebase already distinguishes environments.
3. Enable Vercel Web Analytics and mount the official framework component.
4. Add framework-native robots, sitemap, and favicon assets when absent.
5. Build, test, deploy to production, then inspect the hydrated script elements
   or network requests for both analytics loaders.

Record the GA property id, web stream id, and measurement id. Never store a
Measurement Protocol secret in the repository; ordinary browser pageviews do
not require one.

## 3. Create and verify Search Console

Prefer a domain property so apex, `www`, and protocols are covered together.
Create the DNS TXT record through the site's existing DNS provider, verify
ownership, and record the record id plus verification result. Submit the
canonical sitemap and confirm `Success`; a redirecting apex submission can be
kept if it also turns green.

Search Console may briefly report no `robots.txt` or no crawl data for a brand
new property even when the live files resolve. Treat that as indexing warm-up,
not a reason to rewrite working files.

## 4. Prepare BigQuery

Confirm billing first. Enable BigQuery, Logging, Firebase, and resource-manager
APIs required by the telemetry runbook. For Search Console:

```sh
CLOUDSDK_CORE_ACCOUNT=<email> gcloud projects add-iam-policy-binding <project> \
  --member='serviceAccount:search-console-data-export@system.gserviceaccount.com' \
  --role='roles/bigquery.dataEditor'
CLOUDSDK_CORE_ACCOUNT=<email> gcloud projects add-iam-policy-binding <project> \
  --member='serviceAccount:search-console-data-export@system.gserviceaccount.com' \
  --role='roles/bigquery.jobUser'
CLOUDSDK_CORE_ACCOUNT=<email> bq mk --dataset --location=US <project>:searchconsole
```

Verify both IAM roles. The empty dataset is intentional: it pins the name and
lets Metricsjar register before Google creates export tables.

If the local dev-telemetry runbook exists, run its setup and doctor. For a web
project, the generic Measurement Protocol secret warning is optional unless a
server-side event sender was requested.

## 5. Drive the console links

Use the already signed-in account and verify its email in each product.

1. GA4 Admin → Product links → Search Console links: link the verified domain
   property to the correct web stream.
2. GA4 Admin → Product links → BigQuery links: choose the confirmed project and
   US location, keep the one correct stream selected, enable **Daily** and
   **Streaming (best-effort)**, review, submit, and verify the project row.
3. Search Console → Settings → Bulk data export: project `<project>`, dataset
   `searchconsole`, United States; review, set up, and verify
   `Bulk data export is active`.

Record the enablement date. Neither export backfills time before it was enabled.

## 6. Research and load tracked keywords

Use first-party search data if it exists; otherwise combine:

- the product's category and differentiated language;
- direct product and category competitors;
- competitor ranking keywords from the configured keyword-data provider;
- one batched volume/intent check in the target market.

Curate rather than dump. Keep terms the site deliberately wants to rank for,
including a small number of zero-volume category-creation phrases. Map each to
the closest existing or planned page.

Create UTF-8 CSV:

```csv
keyword,volume,page
google search console dashboard,170,/docs/connect-search-console
agent-first analytics,0,/articles/agent-first-analytics
```

Rules: `keyword` required; `volume` and `page` optional; one unique keyword per
row; no blank keyword; maximum 150. Record provider cost and raw result paths in
the ledger, never credentials.

## 7. Register before exports finish warming

Use the requested account and explicit web stream:

```sh
bun ~/.metricsjar/cli.ts site add \
  --slug <slug> --domain <domain> \
  --bq-project <project> --gsc-dataset searchconsole \
  --ga4-dataset analytics_<property-id> \
  --ga4-web-stream <numeric-stream-id> \
  --gcloud-account <email> \
  --geo <location-code> --language <code> \
  --targets <absolute-path>/targets.csv
```

The current CLI must treat a valid dataset with absent first-export tables as
yellow/warming, not as an authentication error. If it reports auth, separately
prove the pinned account can `bq show` the dataset and update the CLI before
continuing; do not create fake export tables.

Run:

```sh
bun ~/.metricsjar/cli.ts doctor <slug>
bun ~/.metricsjar/cli.ts refresh <slug> --serp --backlinks
bun ~/.metricsjar/cli.ts cron install
bun ~/.metricsjar/cli.ts doctor <slug> --as-cron
bun ~/.metricsjar/cli.ts cron status
bun ~/.metricsjar/cli.ts onboard verify <slug>
```

The paid first refresh can take several minutes because SERP checks are
per-keyword. Use a persistent process. If a process dies, a current CLI
recognizes the dead PID and recovers its lock immediately.

## 8. Verify the actual dashboard

Open the printed dashboard URL in the requested account. Confirm:

- the domain and recent refreshed timestamp;
- every tracked keyword appears with its volume/page mapping;
- backlinks or other enabled optional sources render;
- Pipe health contains green or yellow only;
- yellow export rows explicitly say they are warming, not auth failures.

Capture proof when visual verification is required. End the ledger with what is
green, what is warming, the export enablement date, expected next state, costs,
and every onboarding gap found and fixed.
