Skip to content

Google Tag Manager — Discovery Recipe (Pipedream Connect gap-fill)

Google Tag Manager — Discovery Recipe (Pipedream Connect gap-fill)

GTM is NOT in Composio’s catalog (verified 2026-05-19). It is served via Pipedream Connect as the sanctioned gap-fill vendor per ADR-061. This file is a recipe, not a snapshot — re-verify connection IDs and tool surface before relying on them.

Auth model

  • OAuth client: BYO Google OAuth client (separate from googlesuper). GCP project ascend-gtm. Client ID prefix 705816965171-qumivcaeqi2ad13opj9....
  • Redirect URI: https://api.pipedream.com/connect/oauth/oa_88iV2v/callback
  • Scopes (sensitive):
    • https://www.googleapis.com/auth/tagmanager.readonly
    • https://www.googleapis.com/auth/tagmanager.edit.containers
    • https://www.googleapis.com/auth/tagmanager.edit.containerversions
    • https://www.googleapis.com/auth/tagmanager.publish
  • Pipedream OAuth client: ascend-gtm-gtm (wired to the GCP client above)
  • Multi-tenant model: external_user_id={client_slug} mirrors Composio’s user_id={slug} pattern.

Secrets (Infisical — project 1c1907fa-ee74-4d52-ba1a-839fc71e855d, env prod)

KeyPurpose
PIPEDREAM_CLIENT_IDWorkspace API OAuth client ID (server-side auth)
PIPEDREAM_CLIENT_SECRETWorkspace API OAuth client secret
PIPEDREAM_WORKSPACE_IDWorkspace ID — o_JvI9PZE
PIPEDREAM_PROJECT_IDRequired for MCP server header x-pd-project-id. Current value: proj_ELsVB0b (verified 2026-05-19).

Connection-verify recipe

Server-side workspace OAuth token (needed before any API or MCP call):

Terminal window
source ~/.zprofile
curl -X POST https://api.pipedream.com/v1/oauth/token \
-H "Content-Type: application/json" \
-d "{\"grant_type\":\"client_credentials\",\"client_id\":\"$PIPEDREAM_CLIENT_ID\",\"client_secret\":\"$PIPEDREAM_CLIENT_SECRET\"}"

Expected: {"access_token":"...","token_type":"Bearer","expires_in":3600}.

Resolved 2026-05-19: workspace OAuth previously returned invalid_client — root cause was conflating the BYO GCP OAuth client (for Google end-user consent, namespaced under Pipedream OAuth client ascend-gtm-gtm) with the workspace API OAuth client (for api.pipedream.com itself). These are distinct artifacts. Workspace API client ascendgtm-connect was created 2026-05-19 and credentials stored via Infisical MCP (no echo/newline issues since MCP path bypasses shell). Token endpoint now returns a valid Bearer token.

End-user connect flow (per tenant)

Terminal window
ACCESS_TOKEN="<from step above>"
PROJECT_ID="<proj_xxx from PIPEDREAM_PROJECT_ID>"
EXTERNAL_USER_ID="ascend" # or kahuna, or any client slug
# 1. Create a Connect Token
curl -X POST https://api.pipedream.com/v1/connect/$PROJECT_ID/tokens \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "X-PD-Environment: production" \
-H "Content-Type: application/json" \
-d "{\"external_user_id\":\"$EXTERNAL_USER_ID\"}"

Returns {token, connect_link_url, expires_at}. Open connect_link_url in a browser → click through Google consent → Pipedream stores the refresh token under external_user_id.

Manual UI alternative: from Pipedream dashboard → Connect → Users → pick the user → “Connect a new account” → Google Tag Manager.

Smoke test (after connect)

Step 1 — List connected accounts to get the apn_* ID for this tenant:

Terminal window
curl -sS -G "https://api.pipedream.com/v1/connect/$PROJECT_ID/accounts" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "x-pd-environment: production" \
--data-urlencode "external_user_id=$EXTERNAL_USER_ID" \
--data-urlencode "app=google_tag_manager"

Returns {"data":[{"id":"apn_xxxxxxx","healthy":true,"authorized_scopes":[…],…}]}. Capture the id.

Step 2 — Proxy a GET to GTM via base64url-encoded target URL in the path:

Terminal window
ACCOUNT_ID="apn_xxxxxxx" # from step 1
URL_B64=$(printf 'https://tagmanager.googleapis.com/tagmanager/v2/accounts' | base64 | tr '+/' '-_' | tr -d '=')
curl -sS -X GET "https://api.pipedream.com/v1/connect/$PROJECT_ID/proxy/$URL_B64?external_user_id=$EXTERNAL_USER_ID&account_id=$ACCOUNT_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "x-pd-environment: production"

Expect {"account":[{"path":"accounts/…","accountId":"…","name":"…","features":{…}}]}. If data:[] from step 1: consent wasn’t completed, or external_user_id doesn’t match what was passed to the connect token.

Verified working 2026-05-20T00:57Z for external_user_id=ascend against connected account apn_JjhBPDA — returned {"account":[{"accountId":"4703167523","name":"Kahuna",…}]}.

Important — Connect tokens vs workspace tokens: the ctok_* token from POST /v1/connect/{project_id}/tokens is one-shot and consumed by the user’s browser at connect.html. For data-plane calls, always use the workspace OAuth Bearer (mint a fresh one — 1h TTL) plus external_user_id+account_id query params to identify the stored grant. Don’t pass ctok_* to the proxy — it returns "The Pipedream Connect token is invalid".

MCP equivalent

https://remote.mcp.pipedream.net/v3 with headers:

Authorization: Bearer <workspace access token>
x-pd-project-id: <proj_xxx>
x-pd-environment: production
x-pd-external-user-id: ascend
x-pd-app-slug: google_tag_manager

Once stable, add to .mcp.json as a new server entry pipedream-gtm. Re-issue access tokens before expiry (≤1h).

GTM v2 endpoints — what to call

Base: https://tagmanager.googleapis.com/tagmanager/v2/

Audit primitiveEndpoint
AccountsGET accounts
ContainersGET accounts/{a}/containers
WorkspacesGET accounts/{a}/containers/{c}/workspaces
TagsGET .../workspaces/{w}/tags
TriggersGET .../workspaces/{w}/triggers
VariablesGET .../workspaces/{w}/variables
Create versionPOST .../workspaces/{w}:create_version
Publish versionPOST .../versions/{v}:publish

Full reference: https://developers.google.com/tag-platform/tag-manager/api/v2/reference

Per-tenant rollout

Repeat the connect flow for each new tenant slug. The connection ID returned by accounts.list (Pipedream proxy) for the external_user_id is the lookup key. Treat connection IDs as ephemeral — they rotate on re-auth.

Last-known values (assume stale, re-verify before use)

  • PIPEDREAM_WORKSPACE_ID = o_JvI9PZE (verified 2026-05-19)
  • PIPEDREAM_PROJECT_ID = proj_ELsVB0b (verified 2026-05-19)
  • Pipedream workspace API OAuth client name: ascendgtm-connect (verified 2026-05-19)
  • GCP OAuth client ID: 705816965171-qumivcaeqi2ad13opj9ns2eounrokdqq.apps.googleusercontent.com (verified 2026-05-19)
  • GCP redirect URI: https://api.pipedream.com/connect/oauth/oa_88iV2v/callback
  • Pipedream Connect app slug (GTM): google_tag_manager (Pipedream oa_G1MiyV)
  • ascend connected account: apn_JjhBPDA (live, healthy, verified 2026-05-20T00:57Z) — scopes granted: tagmanager.readonly, tagmanager.edit.containers, tagmanager.publish + email, profile. tagmanager.edit.containerversions NOT granted in initial consent — re-consent needed before workspaces:create_version can be called.
  • Pipedream proxy allowed_domains (whitelist enforced server-side): www.googleapis.com, tagmanager.googleapis.com.

Rotation triggers

  • Pipedream workspace OAuth client secret → printf 'new' | wrangler ... is unrelated; rotate inside Pipedream dashboard then mcp__infisical__update-secret.
  • GCP OAuth client secret rotation → update Pipedream BYO client config + Infisical at google/gtm/client_secret.
  • Re-evaluation triggers: see ADR-061 “Re-evaluation triggers” section.