Publish
This page promotes your staged GTM workspaces to live container versions. For each workspace (server first, then web), GSS calls the GTM API to create a new container version, then publishes that version. Once published, the new version is live in the GTM container — every site visitor's GTM snippet loads it on their next page load (subject to Google's edge caching).
Publish is the most consequential single action in the entire flow because it changes what real users experience. Before this point, all GSS work has been in staging workspaces that nobody outside your team sees. After this point, the world sees your server-side pipeline. The page is gated by Publish — Review staged setup being stamped — the live-traffic verification happens after publish in the next step.
Happy path
- Step 1 — click Audit GTM containers to read both staged workspaces.
- Step 2 — skip cleanup, or stage deletion of any retired GSS items.
- Step 3 — click Publish GTM Changes; GSS publishes server, then web. (Or expand Publish Manually if you'd rather click through GTM yourself.)
- Step 4 — click Check; GSS reads the live containers and verifies the staged plan is live.
- Continue to Publish — Confirm live traffic.
Glossary▶
- Workspace
- A GSS-managed staging area inside a GTM container. Holds the role-mirrored variables / triggers / tags GSS authored. Persists across publishes — the same workspace row is reused on re-publish.
- Container version
- A snapshot of a GTM container's published state. Each Publish creates a new version named
"GetServerSide mirror-pipeline setup". - Audit (Step 1)
- Read-only inspection of the two staged workspaces — lists pending changes, surfaces auto-deletable retired items, and flags items needing manual cleanup.
- Retired GSS items
- GTM artifacts GSS authored in an earlier configuration but no longer needs (e.g. a deprecated forwarder tag). Step 2 lets you stage their deletion in the workspace before Step 3 publishes.
publish_audit_record- An immutable log row written on every successful publish. Records both new container versions, the prior versions (rollback targets), and a configuration hash. Used by the Emergency Rollback flow.
- Provenance state
- Per-container drift signal:
ok(live version matches GSS's last publish),drift(live version differs — someone published outside GSS),unknown(no GSS publish recorded yet).
Not covered on this page: the preceding readiness gate (Publish — Review staged setup), the live-traffic verification that follows (Publish — Confirm live traffic), or post-publish rollback (Emergency Rollback flow on the Go-Live stage).
Before you start
- Publish — Review staged setup is stamped (writes
profile_config.publish_confirmed_at). Clearing that stamp re-locks this page. - The staged GSS workspaces in both containers are in
configuredstate — i.e. Connect — Web Container and Connect — Server Container ran and queued the GSS-authored items. - Edit + publish permission on both GTM containers. Read access alone isn't enough; the orchestration writes a new container version on each side.
- Nobody else is publishing the same containers concurrently. GTM's API doesn't have strong concurrency guarantees for publish, and overlapping publishes will surface a stolen-attempt error.
Publish containers (decision record)
The decision-record card at the top of the page summarises the current publish state. It updates on each Check or Publish attempt.
| Row | Source | What "done" looks like |
|---|---|---|
| Publish state | Composite: attestation stamp present AND all live-checks fresh-passing. | "Published via GSS & verified" (or "Published manually & verified" for manual attestation) once the composite gate is satisfied. |
| Changes published | Timestamp from the most recent publish_audit_record row. |
Local timestamp of the last successful publish; "—" until Step 3 has run. |
| Live container checks | Step 4 — Check. | "N of N verified" once all three checks pass. |
1 Audit GTM containers
Click Audit GTM containers. GSS reads both staged workspaces (the same workspace IDs Configure has been writing into) and produces a snapshot covering: number of pending changes per container, the count of needs-attention items, and any retired GSS artifacts still present.
The audit panel that renders below the button surfaces two sub-sections: Pending changes per container (one line per kind — web vs. server — with a count of changes that will go live on publish) and either "No blocking issues found." or a tally of items needing attention. Any retired items appear in Step 2 below; manual-cleanup-only items appear there informationally.
The audit is read-only — it never mutates the workspace. It surfaces what's about to go live, and what Step 2 might want to clean up beforehand. If you change anything in GTM after auditing (manually editing the workspace, re-running Configure), re-audit before publishing — the snapshot is what Step 2 and Step 3 read. The button shows a "Last updated: <X ago>" timestamp next to it once a fresh audit exists; if the snapshot has gone stale, the page replaces the snapshot with "Audit failed or is stale. Click Audit GTM containers to refresh before publishing."
2 Retired GSS items
GSS lists any auto-deletable retired items found during Step 1 — tags, triggers, or variables GSS authored in a previous configuration but no longer needs. Examples: a forwarder tag from a deprecated loader profile, an init trigger replaced by a newer pattern.
Two options:
- Stage deletion — GSS removes the items from the workspace. Live traffic isn't affected yet; the deletion goes live when Step 3 publishes.
- Skip cleanup — leave the items in place. Use this if you want to publish exactly the items GSS authored without any cleanup, or if you're not sure whether a flagged item is safe to remove.
Manual-cleanup items (items GSS won't auto-delete because their removal could break adjacent setup) are surfaced informationally; they don't block publishing and aren't touched by Stage deletion.
3 Publish GTM changes
Click Publish GTM Changes. The in-app modal lays out what's about to happen; click Confirm to start the orchestration:
- Snapshot prior versions — for each container, read the currently-live
containerVersionId. This is the rollback target if you later need it. - Server workspace publish — call
create_versionagainst the server staging workspace (snapshot the workspace into a new GTM container version), thenpublish_versionon that new version. Server publishes first because the web container's tags reference the server endpoint; if you published web first, traffic could briefly hit a server container that didn't yet have the GSS-staged config. - Web workspace publish — same two-step pattern on the web staging workspace.
- Write
publish_audit_record— one immutable row containing both new version IDs, both prior version IDs, the config hash, and a schema version. Written when at least one container publishes, so partial-publish state is still recorded. - Update workspace status — both staging workspaces transition to
published; theirpublished_version_idfield is set.
Each create_version + publish_version pair takes a few seconds; publishing both containers typically completes in 5–15 seconds total.
Or: publish manually
Expand the Publish Manually disclosure next to the Publish GTM Changes button (separated by a small "or"). The body gives you direct links to both workspaces in GTM's UI; click Submit → Publish in each, then come back and click I published manually. GSS treats your attestation as equivalent to having clicked Publish GTM Changes; the publish_audit_record is written without the GSS-driven version IDs, but downstream gates (Step 4, live-test) work the same way.
Once the manual attestation is recorded, the disclosure body shows "Manual publish is recorded. Re-run Check if the live container changed." plus a Remove manual attestation » button that clears the stamp and re-opens Publish GTM Changes. Opening the disclosure while a stamp is absent disables Publish GTM Changes so a stray click doesn't kick off the GSS orchestration mid-decision.
Last publish summary panel
When the most recent publish attempt happened within the last 24 hours, a "Last publish" panel appears inside Step 3 with one of three titles: "Last publish: recorded" (success), "Last publish: partially published" (one container succeeded, the other did not), or "Last publish: reconcile needed" (GTM published but the project state changed mid-flight). Partial / reconcile titles include a "How to continue" block with the exact remediation steps; success titles confirm that GSS recorded the publish and the next move is Step 4 Check.
What happens if Publish fails halfway
Two distinct failure shapes:
- Server fails first: web is never attempted.
publish_audit_recordis NOT written (no container published). Workspace status: server =failed, web = unchanged. You can retry — the workspace is reusable. - Server succeeds, web fails:
publish_audit_recordIS written withweb_published_version_id = NULL(still valid because at least one container published). The web workspace is infailedstate. Your live state is now mixed: server has the new GSS config, web has the old config. Visitors might see briefly inconsistent behavior. Click Publish GTM Changes again — only the web side will be retried; the server is already on the new version.
4 Have my container changes been published?
After Step 3, click Check. GSS reads the live versions of both containers and runs three checks against the actual published state. This is your last automated confirmation that what you intended to publish is actually what's live; if something published incorrectly, this catches it.
4.1The GSS staging workspaces have no unpublished GTM changes
Confirms both staging workspaces are "clean" — everything GSS staged has been published out of them and the change list is empty.
Deep dive ▶
What it checks. GSS reads each tracked staging workspace's GTM workspaceChange list. Pass requires zero unpublished changes in both the web and server staging workspaces.
Why it might fail. Publish never ran (the modal was cancelled). A previous publish was partial; you cancelled before the second side. Someone added a change to the workspace after Step 3 (rare).
How to recover. Re-run Step 3 — the orchestration is idempotent and will publish whatever's still queued.
4.2Web container has the forwarder tag live
Reads the live (published) web container version and verifies the two required items GSS publishes there: the forwarder tag and the all-pages trigger that fires it.
Deep dive ▶
What it checks. One GTM API call to fetch the live web container. Verifies the two required publishable items (the forwarder tag and its all-pages trigger). Five additional GSS-managed items (URL / MID variables, init trigger, your primary Google tag) are not required to publish but are surfaced in the items table below for diagnostic context.
What counts as pass. Both required items are present and healthy in the live version.
Provenance banner. A separate amber banner surfaces when the live containerVersionId differs from the version GSS most recently published — informational only, doesn't fail this check.
Why it might fail. Publish appeared successful but the workspace landed only partial items (rare GTM API hiccup). Someone manually edited the live container after publish. The items table identifies which role(s) are missing.
How to recover. Re-Publish. If the failure persists, manually inspect the live container in GTM Admin and compare to the role-mirror reference in Connect — Web Container.
4.3Server container has the forwarder tag configured
Same idea as 4.2 but against the live server container. Verifies the required roles GSS publishes there.
Deep dive ▶
What it checks. Reads the live server container and verifies the required roles: GA4 client (parses incoming hits), all-pages trigger (fires the forwarder), and the sgtmgaaw forwarder tag (sends events to the server GA4 property). On the first-party loader profile, the Web Container client is also required.
Note on selected events. The events you selected in Build are validation / coverage scope — which events GSS expects to observe end-to-end — they don't materialize additional per-event GTM artifacts. The items table below shows the loader profile plus the full per-role state.
What counts as pass. Every required server role is healthy.
Why it might fail. Same shapes as 4.2. If 4.2 fails and 4.3 passes, you saw partial-publish (server succeeded, web failed) — re-Publish only attempts the failed side.
Provenance banner (informational)
If GSS detects that your live container's containerVersionId doesn't match the version GSS last published, the page shows an amber banner. This means someone published the container outside of GSS (a teammate via the GTM UI, or an automated tool). The banner is non-blocking — it doesn't affect Publish gating — but it tells you live state may have drifted from what GSS thinks is current. The Check above runs against actual live state, so it'll catch any real misconfiguration regardless of provenance.
Common errors & failure modes
| Symptom | Likely cause | Where to fix |
|---|---|---|
| Gates | ||
| Publish GTM Changes is greyed out | Step 1 (Audit) hasn't run yet, or Publish — Review staged setup isn't stamped. | Run Step 1; if still locked, return to Review staged setup and confirm. |
| Publish returns 422 "build_not_ready" with a Review setup link | An upstream stage went stale or attention between Review-stamp time and now. Strict freshness applies at publish time. | Follow the inline link to Review staged setup; re-validate the stale stages; re-confirm; come back. |
| Publish returns 422 "No publishable test-pipeline workspaces found" | No workspace rows are in created / configured / published state. Probably Connect was never completed. |
Walk back through Connect — both Web Container and Server Container — to ensure the staging workspaces are configured. |
| Publish failures | ||
| Publish returns 502 with "Web workspace publish failed: ..." | Server published successfully but web's create_version or publish_version hit an error. Live state is now mixed. |
Click Publish GTM Changes again — only the web side retries. The error message identifies the specific GTM API failure (quota, permission, validation). |
| Publish returns 502 with "Server workspace publish failed" | Server's publish failed before web was attempted. No publish_audit_record written. Live state is unchanged. |
Click Publish GTM Changes again. If persistent, check GTM API quota in the Cloud Console and your account's Edit access on the server container. |
| Publish returns 4xx "Failed to create version from workspace" | GTM rejected the workspace contents — usually because a tag references a non-existent variable or trigger. | Re-run Connect-stage validation to surface the specific issue; reconfigure that role; re-Publish. |
| Publish returns 409 "stolen_attempt" | Another publish ran concurrently (teammate clicking at the same moment), or the staged workspaces changed between gate-check and orchestration. | Refresh the page; re-audit; re-confirm; re-Publish. |
| Publish returns scope-missing with a Reconnect Google link | Your account is missing the GTM edit / version / publish scopes. Common for accounts that consented before those scopes were added to GSS. | Click Reconnect Google in the error callout; accept all scopes; retry. |
| Check failures | ||
| 4.1 fails — workspace not empty | Something still queued in a workspace (cancelled mid-publish, manual edit in GTM after publish). | Re-Publish — the orchestration republishes whatever's still queued. |
| 4.2 or 4.3 fails after Publish appeared successful | Live container state differs from what was staged — rare unless someone manually edited the live container between Publish and Check. | Re-Publish from the staging workspace. If the issue persists, compare live container in GTM Admin to the role-mirror reference; reconfigure if needed. |
| Provenance banner shows "drift" but Check passes | Someone published the container outside of GSS. Their changes happen to also be GSS-compatible. | Nothing required — the banner is informational. To remove the drift signal, re-Publish through GSS so the recorded version ID matches live again. |
Next step
Once all four steps are green, continue to Publish — Confirm live traffic. That step polls GA4 Realtime + Cloud Run on your live site to prove the just-published pipeline is actually moving traffic, then asks you to attest.
After Go Live
Once the project completes the Go Live cutover, this page stays reachable as the publish receipt. The H1 stays "Publish"; the page intro switches to "This publish stage is read-only because the project is live. The publish receipt and live container checks remain visible here for review."
The four-step orchestration buttons (Audit, Stage deletion, Publish GTM Changes, Check) are hidden. Step 3 renders a receipt table sourced from the latest publish_audit_record row:
- Published — the
published_attimestamp from the audit record. - Web container version —
web_published_version_id. - Server container version —
server_published_version_id. - Publish source — how the publish was triggered (UI button vs. internal).
The publish-orchestration JavaScript that drives steps 3 and 4 is gated off entirely. Direct POSTs to /p/{slug}/publish/run/* return 409 live_project.
The receipt is the page. If a project completed cutover under an earlier flow without writing a publish_audit_record, the receipt falls back to "No publish receipt was found. Use the setup snapshot for the frozen cutover record." The cutover snapshot itself lives at /setup-snapshot.