Provision Cloud Run Services

This step stands up the two Cloud Run services that run the GTM server image: a preview service for testing and a tagging service that receives live events. Both services run Google's official gtm-cloud-image:stable container image — GSS does not build or deploy custom code.

Once both services are running, the runtime checks in Step 3 prove they are reachable, healthy, and configured correctly before Tagging Endpoint unlocks. The tagging service still has only a *.run.app URL at the end of this step; attaching a custom domain happens in Tagging Endpoint.

Happy path

  1. Step 1 — paste the CONTAINER_CONFIG string from GTM into the form, click Save deployment config.
  2. Step 2 — click Create Cloud Run services and let GSS deploy them, OR pick existing services in the two pickers and click Save Cloud Run services.
  3. Step 3 — click Check; all 9 runtime checks turn green.
  4. Continue to Tagging Endpoint.
Glossary
Cloud Run
Google's managed serverless runtime for containers. Each service is a deployed container with its own URL, scaling rules, and IAM policy.
Preview service
The Cloud Run service that GTM Preview / Tag Assistant connects to. Has RUN_AS_PREVIEW_SERVER=true and is capped at 1 instance.
Tagging service
The Cloud Run service that handles live event traffic. Always has at least 1 warm instance to avoid cold-start latency on incoming requests.
CONTAINER_CONFIG
The base64-encoded GTM server container configuration string. GTM gives it to you on Admin → Container Settings → Set up your tagging server → Manually provision tagging server. Both Cloud Run services need it as an environment variable to know which container they host.
Container image
The Docker image both services run: gcr.io/cloud-tagging-10302018/gtm-cloud-image:stable. Maintained by Google. GSS does not modify or replace it.
Region
The Google Cloud region where the services run. Default suggestion is us-central1; you can pick any Cloud Run region. Both services run in the same region.

Not covered on this page: enabling the Cloud Run Admin API (GCP Project), the GTM server container itself (GTM Containers), or attaching a custom domain (Tagging Endpoint).

Before you start

  • Complete GCP Project — the Cloud Run Admin API must be enabled and the project bound.
  • Complete GTM Containers — the server container must be bound so GSS can validate the CONTAINER_CONFIG string matches it. The page surfaces a link directly to that step if it's missing.
  • Have the CONTAINER_CONFIG base64 string from the server container's Admin → Container Settings → Set up your tagging server → Manually provision tagging server screen.

Decision record

Once both Cloud Run services are bound, the page surfaces a Cloud Run services decision record above the steps with the preview / tagging service IDs and URLs, the deployment-config save state, when requirements were last checked, and the current requirement rollup.

Field Where it comes from What "done" looks like
Server container Inherited from GTM Containers. Surfaced as context above Step 1. Container name + GTM-XXXXXXX shown.
Deployment config Step 1 below. The base64 string from GTM. "Saved" with a masked value (click show to reveal).
Preview service Step 2 — bind existing or create new. Service name + *.run.app URL shown.
Tagging service Step 2 — bind existing or create new. Service name + *.run.app URL shown.
Requirements Rollup of Step 3. Verified after Step 3's Check button has run all 9 runtime checks green.

1 Capture CONTAINER_CONFIG From Your GTM Server Container

GTM gives you a base64-encoded configuration string that tells the server container which GTM container it is. Both Cloud Run services need this string as their CONTAINER_CONFIG environment variable; without it, the container does not know which configuration to load. GSS will inject the value into the services it creates and check that user-bound services already have it.

In GTM, open your server container → Admin → Container Settings → Set up your tagging server → Manually provision tagging server. Copy the long string labelled Container Config. Paste it into the input under Step 1 and click Save deployment config. The page also surfaces the bound server container's name and ID, with a link to Container Settings, so it's easy to jump back into GTM.

GSS validates that the string is valid base64, that the decoded value contains id=GTM-XXXXXXX, and that the GTM ID matches the bound server container. After saving, the value is shown masked next to a show toggle so you can verify what's stored without exposing it on every page load. The string is stored on the project (as profile_config.container_config) and is only sent to Cloud Run as an environment variable when GSS creates or updates services.

The button label flips to Update deployment config after the first save, so you can replace the value if you re-key the GTM server container.

Clear deployment config

After saving, a destructive zone at the bottom of Step 1 shows a Clear deployment config button gated behind an acknowledgement checkbox. Clearing the value locks Step 2's Cloud Run save actions and Step 3's runtime checks until you save a new value. The Cloud Run services in GCP keep running with whatever CONTAINER_CONFIG they already have — clearing only wipes the saved string in GSS.

2 Which Cloud Run Services Should Host the Preview and Tagging Containers?

Step 2 stays locked until the GCP project is bound and Step 1's deployment config is saved. The page reminds you which project the services will land in (inherited from GCP Project) above the picker. You need two services: one running in preview mode, one running tagging traffic, both in the same project.

Option A — Pick existing services

The two pickers (Preview service / Tagging service) list every Cloud Run service in the bound GCP project. Pick one row for the preview slot and a different row for the tagging slot, then click Save Cloud Run services. Save stays disabled until both pickers have a value, both differ from what's already saved, and the two picks are different services — the page surfaces an inline warning if you pick the same service in both slots ("Preview and tagging must be different services").

GSS records each binding with created_by: user metadata. Step 3's runtime checks confirm that the services have the right environment variables and IAM policies regardless of who originally created them — mis-configured user services will fail those checks with specific guidance on what's wrong.

Option B — Create Cloud Run services from scratch

Click the Create Cloud Run services link (it reads Create new Cloud Run services if you already have services in the picker). A modal opens with checkboxes for each service, a name input per service, a region selector (default suggestion us-central1, reordered by your local timezone), and a read-only display of the image GSS will deploy.

  • Image: gcr.io/cloud-tagging-10302018/gtm-cloud-image:stable — Google's official maintained image.
  • Preview service: CONTAINER_CONFIG + RUN_AS_PREVIEW_SERVER=true, max instances = 1, allow unauthenticated invocations (anyone on the internet can reach /healthy).
  • Tagging service: CONTAINER_CONFIG + PREVIEW_SERVER_URL pointing at the preview service's URL, min instances = 1 (always-warm), allow unauthenticated.

Click Create. A confirmation prompt warns that creating Cloud Run services locks the primary GA4 property and GTM web container selections for this setup — to change those later you'd archive the setup and start a new one. The deployment is synchronous: the request blocks until both services are running (typically 30–60 seconds). Both bindings get created_by: gss metadata.

If you already have one of the two services bound (for example, you previously created the preview but not the tagging), the corresponding checkbox is unchecked and its name field disabled — you can re-run the Create flow for just the missing side. If the preview deploys but the tagging service fails, you'll see a partial-success message and can retry just the tagging side.

Clear service bindings

Once services are bound, a Clear service bindings link appears in Step 2. Confirming the modal unbinds the services from this project but does not delete anything in GCP. You'll need to re-bind or recreate before Tagging Endpoint will work again.

cloudrun_* bindings survive the Tier 2 cascade

Unlike GA4 stream bindings, the cloudrun_preview and cloudrun_tagging bindings are excluded from the Tier 2 reset cascade that fires when you change the browser GA4 property or web container in Audit Discovery. Re-deploying every time someone tweaks an upstream binding would be expensive and pointless. The Step 3 check rows do get cleared by the cascade, so you'll need to click Check again, but the bindings themselves persist.

3 Are Both Services Reachable, Healthy, and Configured?

Step 3 stays locked until both services are bound in Step 2 and the deployment config is saved in Step 1. Click Check to run 9 runtime checks. GSS makes 4 Cloud Run API calls (2 service reads, 2 IAM policy reads) plus 1 HTTP probe to the preview service's /healthy endpoint, and reuses the responses across the rows.

Preview service (3.1–3.4)

3.1Preview service is running

The bound preview Cloud Run service must exist and respond to a Cloud Run API get call.

Where to check: Cloud Run console. The preview service should be listed and in "Serving" state.

Fix: If the service was deleted, re-bind in Step 2 (or recreate via Create Cloud Run services).

Deep dive

What it checks. Cloud Run v2 services.get(name) returns the service object.

How GSS performs the check. One Cloud Run API call. Response is reused by 3.2, 3.3, and 3.7 (container_config_present).

What counts as pass. The service exists.

Why it might fail. Service deleted in Cloud Run console. Service moved to a different region (binding has stale region). API permission lost.

How to recover. Re-bind the correct service in Step 2 or click Create Cloud Run services to redeploy.

3.2Preview service is in preview mode

The preview service must have the RUN_AS_PREVIEW_SERVER environment variable set to true. Without it, the GTM container runs in tagging mode instead of preview mode, and GTM Preview won't connect to it.

Where to check: Cloud Run console → preview service → Variables & Secrets tab.

Fix: Edit the service to add or correct the env var; or redeploy via Create Cloud Run services (which always sets it correctly).

Deep dive

What it checks. Reads the preview service's container env vars and looks for RUN_AS_PREVIEW_SERVER == "true".

How GSS performs the check. No additional API call — uses the service object from 3.1.

What counts as pass. Env var present and value equals "true" exactly.

Why it might fail. User-bound service that wasn't configured for preview. Env var was edited or removed manually.

How to recover. Add the env var manually in the Cloud Run console, or use Create Cloud Run services to deploy a fresh preview.

3.3Preview max-instances is 1

The preview service should have max_instance_count = 1. Preview mode is single-session: a connected GTM Preview tab needs its requests to land on the same instance to maintain the session, and capping at 1 enforces that.

Where to check: Cloud Run console → preview service → Edit & deploy new revision → Container, Variables, Networking → Container scaling.

Fix: Set max instances to 1.

Deep dive

What it checks. The preview service's max_instance_count is between 1 and 1 (exactly 1).

How GSS performs the check. Reads the value from the service object.

What counts as pass. 0 < max_instances <= 1.

Why it might fail. Max instances set to 0 (service is paused). Set higher than 1 — GTM Preview sessions can lose state across instances.

How to recover. Edit the service in Cloud Run console and set max instances to 1.

3.4Preview health endpoint returns 200

The preview service's *.run.app URL must respond to GET /healthy with HTTP 200. This confirms the container actually started and is serving requests.

Where to check: open <preview-uri>/healthy in a browser (the URL is shown in the decision record).

Fix: If it returns 5xx, the container failed to start — check Cloud Run logs for the preview service. Most commonly the CONTAINER_CONFIG env var is missing or invalid.

Deep dive

What it checks. HTTP GET to the preview service's uri + /healthy returns status 200.

How GSS performs the check. One httpx.get call from the GSS server (not from your browser). Default user-agent, follows redirects, 10s timeout.

What counts as pass. Status code is exactly 200. Any other status (including 403 from authentication, 5xx from container errors) fails.

Why it might fail. Container failed to boot (bad CONTAINER_CONFIG, OOM). Service is private (unauthenticated invocations not allowed — caught by 3.9 too). Cloud Run is in cold-start mode and the request timed out (rare with min instances ≥ 1, but the preview is set to max=1 not min=1).

How to recover. Check Cloud Run logs for the preview service. If the container is crash-looping, fix CONTAINER_CONFIG (Step 1) and redeploy. If the service is private, fix IAM (covered by 3.9).

Tagging service (3.5–3.6)

3.5Tagging service is running

The bound tagging Cloud Run service must exist and respond to a Cloud Run API get call.

Where to check: Cloud Run console; the tagging service should be listed and Serving.

Fix: Re-bind in Step 2 or recreate via Create Cloud Run services.

Deep dive

What it checks. Cloud Run v2 services.get(tagging_name) returns the service.

How GSS performs the check. Second Cloud Run API call. Response is reused by 3.6, 3.7, 3.8.

What counts as pass. Service exists.

Why it might fail. Same as 3.1: deleted, region mismatch, permission lost.

How to recover. Re-bind in Step 2 or recreate.

3.6Tagging min-instances is at least 1

The tagging service must keep at least one instance always running. Without min instances, every cold start adds 200–800ms of latency to the first request — bad for a tag that fires on user pageloads.

Where to check: Cloud Run console → tagging service → Edit & deploy new revision → Container scaling.

Fix: Set Min instances to 1.

Deep dive

What it checks. The tagging service's min_instance_count >= 1.

How GSS performs the check. Reads the value from the service object.

What counts as pass. Min instances is at least 1.

Why it might fail. Min instances was left at the default 0 to save cost — at the price of cold-start latency on every quiet period.

How to recover. Edit min instances to 1 in Cloud Run console. If you really want 0 to minimize cost, this check will keep failing — the tagging service is meant for production traffic, not occasional use.

Cross-service environment + access (3.7–3.9)

3.7Both services have CONTAINER_CONFIG

Both Cloud Run services must have the CONTAINER_CONFIG environment variable set. This is the GTM container configuration string from Step 1.

Where to check: Cloud Run console → service → Variables & Secrets tab. Look for CONTAINER_CONFIG.

Fix: Add the env var manually with the value from Step 1, or redeploy via Create Cloud Run services.

Deep dive

What it checks. Both service objects have CONTAINER_CONFIG in their env vars.

How GSS performs the check. Reads env vars from both service objects (no additional API calls).

What counts as pass. Env var present on both. The check verifies presence, not value — it doesn't compare against the saved Step 1 value.

Why it might fail. User-bound services without the env var. Env var was renamed or removed manually.

How to recover. Add the env var to the failing service. The error message will name which service is missing it.

3.8Tagging service has PREVIEW_SERVER_URL

The tagging service must have PREVIEW_SERVER_URL in its env vars (presence check; value not validated). This tells the tagging service where to forward GTM Preview / Tag Assistant connection probes so debug overlays work end-to-end.

Where to check: Cloud Run console → tagging service → Variables & Secrets.

Fix: Add the env var with the preview service's URL. Create Cloud Run services sets this automatically.

Deep dive

What it checks. Tagging service has the PREVIEW_SERVER_URL key in its env vars.

How GSS performs the check. Reads env vars from the tagging service object.

What counts as pass. Key is present. Value is not validated — even an empty string passes (not great but the check is permissive).

Why it might fail. User-bound tagging service without the env var.

How to recover. Add the env var. Value should be the preview service's URI (visible in the decision record after preview is bound).

3.9Both services allow unauthenticated access

Both services must allow unauthenticated invocations. Browsers sending events have no Google auth token; Cloud Run will reject their requests if IAM is locked down to specific service accounts.

Where to check: Cloud Run console → service → Permissions / Security. Look for allUsers with the Cloud Run Invoker role.

Fix: In Cloud Run console, edit Permissions and add allUsers with the Cloud Run Invoker role; or redeploy via Create Cloud Run services (which sets it automatically).

Deep dive

What it checks. Both services have allUsers in roles/run.invoker.

How GSS performs the check. Two Cloud Run v2 getIamPolicy calls (one per service).

What counts as pass. Both services have the binding.

Why it might fail. Org policy disallows public services. User-bound services that were originally private. Manual IAM edits.

How to recover. Add allUsers as Cloud Run Invoker. If org policy blocks public access, you'll need to either get an exception or use a different deployment pattern (load balancer with allowlists, etc.) — that's out of scope for this guide.

Common errors & failure modes

Symptom Likely cause Where to fix
CONTAINER_CONFIG
Save returns 400 "CONTAINER_CONFIG is not a valid container config string" String isn't valid base64 or doesn't contain id=GTM-XXXXXX. Often a copy-paste error (truncated or whitespace). Re-copy from GTM Admin → Container Settings → Manually provision tagging server. Make sure you copied the full value with no leading/trailing whitespace.
Save returns 400 "GTM ID mismatch" Pasted CONTAINER_CONFIG is for a different GTM container than the one bound in GTM Containers. Either copy the config from the correct server container in GTM, or change the bound server container.
Service deployment
Create button is disabled in the modal Deployment config hasn't been saved yet. The modal surfaces a "Save the deployment config in step 1 before creating services" warning. Close the modal, save the config in Step 1, reopen Create Cloud Run services.
Create succeeds for preview but tagging fails (warning shown) Tagging service deploy hit an error (quota, name collision, image pull failure, etc.). Preview service is bound correctly. The warning text identifies the cause. Reopen Create Cloud Run services with a different tagging name, or fix the underlying issue (e.g., quota request) and retry.
Save Cloud Run services button stays disabled Either both pickers don't have a value, both values match what's already saved, or you picked the same service for both slots ("Preview and tagging must be different services" warning). Pick two different services in the two pickers.
Validation failures specific to user-bound services
3.2, 3.7, 3.8 all fail on user-bound services You picked existing services that weren't configured by GSS — env vars are not set up the way the GTM container image expects. Easiest path: click Clear service bindings, then use Create Cloud Run services to deploy fresh ones. OR manually edit each user-bound service in Cloud Run to add the missing env vars.
3.9 fails — services aren't public Org policy blocking allUsers; or services were locked down post-creation. Add allUsers with Cloud Run Invoker in the service's Permissions tab. If org policy blocks it, you need an exception or a different deployment pattern (load balancer + identity-aware proxy, etc.).
Cascade after upstream changes
After Audit Discovery change, this stage shows all checks needing re-check Tier 2 cascade clears stage check rows (but not the cloudrun bindings themselves). Just click Check again. The bindings are still good.
Validate returns 401 "Validation failed — please try again" Google credentials expired. Reconnect Google in the app, then re-run Check.

Next step

Once all 9 runtime checks pass, the next step is Tagging Endpoint — attaching a custom subdomain to the tagging service so first-party event traffic flows through your domain instead of *.run.app.