Skip to content

EarthCraig/GTAG-Manager

Repository files navigation

GTAG-Manager

A Claude Code-driven CLI for Google Tag Manager. Declare your tags, triggers, and variables in YAML; plan and apply them like Terraform; publish a new container version on confirmation.

A local Python CLI that drives Google Tag Manager from a YAML spec, designed to be operated by Claude Code.

All OAuth tokens stay on your local machine; no telemetry, no third-party servers.


Prereqs

  • Python 3.10 or newer.
  • A Google account with edit access to at least one GTM container.
  • A Google Cloud project where you can create an OAuth 2.0 Client ID (free tier is fine).
  • git and a working pip.

Step-by-step OAuth setup

GTM's API requires OAuth 2.0. You create the client once, paste two values into a local .env file, and never touch the cloud console again.

1. Create a Google Cloud project

Open https://console.cloud.google.com/. Click the project picker in the top bar, then New Project. Name it gtag-manager (or any name you like) and click Create. Wait for the notification, then switch into the new project from the picker.

[screenshot: google cloud project picker with "new project" button highlighted]

2. Enable the Tag Manager API

With the new project selected, open the Tag Manager API library page directly:

https://console.cloud.google.com/apis/library/tagmanager.googleapis.com

Click Enable. The page reloads to show the API as enabled (a Manage button replaces the Enable button). If you skip this step, every gtm-agent command that touches the network will fail with an accessNotConfigured / SERVICE_DISABLED error linking back to this same page.

Alternative path: from the project home, open APIs & Services > Library, search for Tag Manager API, click the result, and click Enable.

[screenshot: tag manager api library page with "enable" button]

3. Create an OAuth client ID (Desktop app type)

Open APIs & Services > Credentials. If prompted, configure the OAuth consent screen first: choose External, fill in app name (GTAG-Manager), your email, and save. Add yourself as a test user under Audience (only test users can complete the flow until the app is verified, which is unnecessary for a local tool).

Back on Credentials, click Create Credentials > OAuth client ID. Set Application type to Desktop app (this is the type that supports the loopback flow used by gtm-agent auth). Name it GTAG-Manager local, click Create.

[screenshot: create oauth client id form with "desktop app" selected]

4. Download client secrets

After creation, a dialog shows your Client ID and Client secret. Copy both values (you can also click Download JSON to save client_secret_*.json, but you only need the two strings). Keep this dialog open while you set up .env in the next section.

[screenshot: oauth client created dialog with client id and secret visible]


Install

git clone https://github.com/EarthCraig/GTAG-Manager.git
cd GTAG-Manager
pip install -e .
cp .env.example .env

Open .env and paste the two values from the OAuth dialog:

GOOGLE_OAUTH_CLIENT_ID=1234567890-abc...apps.googleusercontent.com
GOOGLE_OAUTH_CLIENT_SECRET=GOCSPX-...

.env is gitignored. Do not commit it.


First run

gtm-agent auth

A browser window opens for Google sign-in and consent. Approve the requested scopes (tagmanager.readonly, tagmanager.edit.containers, tagmanager.publish). The CLI confirms success and writes a refresh token to ~/.gtm-agent/token.json (or %LOCALAPPDATA%\gtm-agent\token.json on Windows).

gtm-agent whoami

Sanity check. Prints your email and the OAuth scopes the cached token holds. This command does not call the GTM API, so it does not consume daily quota.

gtm-agent list

Prints every GTM account, container, and workspace your token can see. Note the account_id, container_id, and workspace_id of the workspace you want to edit.


Plan and apply walkthrough

examples/ga4-pageview.yaml is a minimal spec: one GA4 config tag firing on All Pages. Open it, replace GTM-XXXXXXX with your container ID and G-XXXXXXX with your real GA4 measurement ID.

gtm-agent plan examples/ga4-pageview.yaml

You see a plan table:

Plan for accounts/123/containers/GTM-ABC/workspaces/4

  kind     resource          name
  ------   ---------------   ------------------------------
  create   built_in_var      pageUrl
  create   built_in_var      pagePath
  create   built_in_var      pageHostname
  create   built_in_var      referrer
  create   variable          Const - GA4 Measurement ID
  create   trigger           All Pages
  create   tag               GA4 - Config

Summary: 7 create, 0 update, 0 no-op

Apply it:

gtm-agent apply examples/ga4-pageview.yaml
Applied 7 resources to workspace accounts/123/containers/GTM-ABC/workspaces/4

  created: 4 built-in variables, 1 variable, 1 trigger, 1 tag
  updated: 0
  no-op:   0

Workspace is ready. Run `gtm-agent apply ... --publish --yes-publish` to publish a new version.

Re-running apply is a no-op:

Plan for accounts/123/containers/GTM-ABC/workspaces/4
Summary: 0 create, 0 update, 7 no-op

To publish:

gtm-agent apply examples/ga4-pageview.yaml --publish --yes-publish \
    --version-name "GA4 pageview v1" \
    --version-notes "Initial GA4 setup via GTAG-Manager"

Troubleshooting

  • Reset OAuth. gtm-agent auth --revoke deletes the local token and revokes it server-side. Re-run gtm-agent auth to re-consent.
  • Inspect the log. Every API call is logged to ./gtm-agent.log (JSON lines). tail -f gtm-agent.log while a command runs shows request/response trails. Secrets are redacted.
  • 409 conflicts. "Resource already exists" means a tag/trigger/variable with that name is already in the workspace. Pass --allow-update to apply to PATCH the existing resource instead of failing.
  • WSL or SSH (no browser). gtm-agent auth --no-browser prints the auth URL, you open it on a machine that has a browser, then paste the resulting code back into the terminal.
  • dailyLimitExceeded. Google's free GTM API quota is 10,000 calls per project per day, reset at midnight Pacific. The CLI does not retry this error. Wait until tomorrow or create a second OAuth client in a different project.

Publish gate

--publish alone is rejected with an error. To actually publish a version you must pass both --publish and --yes-publish.

This is intentional. An agent that can edit your container should not be one shell-history arrow-up away from shipping changes to production. The two-flag gate forces an explicit, deliberate confirmation every time.


Activate CI (one-time)

The CI matrix (lint + tests on Ubuntu/macOS/Windows x Python 3.10-3.12) is provided as a template at .github/ci.yml.template because the GitHub OAuth token used to bootstrap this repo lacked the workflow scope. To enable it, grant the scope and move the file into .github/workflows/:

gh auth refresh -s workflow
mkdir -p .github/workflows
git mv .github/ci.yml.template .github/workflows/ci.yml
git commit -m "Activate CI matrix"
git push

GitHub will pick it up on the next push and run the matrix on every PR.


Limitations / out of scope for v1

  • No server-side GTM containers (web containers only).
  • No deletes. The agent only creates and updates resources. To remove a tag/trigger/variable, use the GTM UI.
  • No permission management. The CLI cannot grant or revoke user access on accounts or containers.
  • No MCP wrapper. GTAG-Manager is a CLI driven by Claude Code via shell calls, not a Model Context Protocol server.
  • No export command. There is no "dump my workspace to YAML" path; specs are authored by hand or generated from a brief.

About

A Claude Code-driven CLI for Google Tag Manager. Declare tags/triggers/variables in YAML, plan and apply like Terraform.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages