gtm-telemetry-wizard 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gtm_telemetry_wizard-0.1.0/PKG-INFO +107 -0
- gtm_telemetry_wizard-0.1.0/README.md +97 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard/__init__.py +7 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard/__main__.py +4 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard/cli.py +215 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard/config.py +57 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard/service.py +352 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard.egg-info/PKG-INFO +107 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard.egg-info/SOURCES.txt +13 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard.egg-info/dependency_links.txt +1 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard.egg-info/entry_points.txt +5 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard.egg-info/requires.txt +3 -0
- gtm_telemetry_wizard-0.1.0/gtm_telemetry_wizard.egg-info/top_level.txt +1 -0
- gtm_telemetry_wizard-0.1.0/pyproject.toml +21 -0
- gtm_telemetry_wizard-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gtm-telemetry-wizard
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Standalone GTM container IaC compiler, Playwright live verifier, GA4 telemetry ingest warmer, and guided setup wizard.
|
|
5
|
+
Requires-Python: >=3.9
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: typer>=0.9.0
|
|
8
|
+
Requires-Dist: rich>=13.0.0
|
|
9
|
+
Requires-Dist: playwright>=1.40.0
|
|
10
|
+
|
|
11
|
+
# gtm-telemetry-wizard
|
|
12
|
+
|
|
13
|
+
> Declarative GTM Container IaC Compiler, Playwright E2E Live Verifier, and GA4 Telemetry Ingestion Setup Wizard.
|
|
14
|
+
|
|
15
|
+
`gtm-telemetry-wizard` is a standalone CLI tool and Python library for automating Google Tag Manager (GTM) container setups, compiling declarative IaC specs, verifying live webpage telemetry with Playwright, and warming up GA4 measurement streams to achieve **Container Quality: Excellent**.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **5-Phase Setup Wizard**: Diagnostic check, container spec compilation, live Playwright verification, GA4 ingest warm-up, and container quality reporting.
|
|
22
|
+
- **GA4 Ingest Warm-Up**: Delivers initial telemetry pings directly to GA4 (`/g/collect`), automatically clearing 48-hour missing traffic quality alerts.
|
|
23
|
+
- **Playwright E2E Verification**: Headless/Headful browser verification inspecting `gtm.js` snippet loading, `dataLayer` events, and UTM parameters.
|
|
24
|
+
- **Dual Deployment Options**: Automated browser import (via Playwright CDP persistent Chrome profile) or GTM REST API v2 deployment.
|
|
25
|
+
- **Borderless Terminal UI**: Clean Rich-powered terminal interface.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install gtm-telemetry-wizard
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or install from source:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/bizkite-co/gtm-telemetry-wizard.git
|
|
39
|
+
cd gtm-telemetry-wizard
|
|
40
|
+
pip install -e .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
### 1. Guided Setup Wizard
|
|
48
|
+
Run the 5-phase setup wizard for any website and container ID:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
telemetry-wizard wizard --domain example.com --container-id GTM-XXXXXXX --ga4-id G-YYYYYYYY
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Using `telemetry.toml` Configuration File
|
|
55
|
+
Create a `telemetry.toml` in your project directory:
|
|
56
|
+
|
|
57
|
+
```toml
|
|
58
|
+
[site]
|
|
59
|
+
domain = "example.com"
|
|
60
|
+
container_id = "GTM-53F6J2WX"
|
|
61
|
+
ga4_measurement_id = "G-HJJ9TK2TKY"
|
|
62
|
+
|
|
63
|
+
[deployment]
|
|
64
|
+
mode = "browser"
|
|
65
|
+
headful = true
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then run:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
telemetry-wizard wizard --config telemetry.toml
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Python API Usage
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from gtm_telemetry_wizard import TelemetryConfig, TelemetryProvider
|
|
80
|
+
|
|
81
|
+
# Initialize provider
|
|
82
|
+
config = TelemetryConfig(domain="example.com", container_id="GTM-XXXXXXX")
|
|
83
|
+
provider = TelemetryProvider(config)
|
|
84
|
+
|
|
85
|
+
# Run live telemetry verification
|
|
86
|
+
results = provider.verify_live_telemetry()
|
|
87
|
+
print("GTM Loaded:", results["gtm_script_loaded"])
|
|
88
|
+
|
|
89
|
+
# Send initial GA4 warm-up ping
|
|
90
|
+
ping_res = provider.ping_ga4_measurement_id("G-YYYYYYYY")
|
|
91
|
+
print("Ping Status:", ping_res["status"])
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## CLI Reference
|
|
97
|
+
|
|
98
|
+
- `telemetry-wizard wizard` - Guided 5-phase telemetry setup wizard.
|
|
99
|
+
- `telemetry-wizard sync` - Compile GTM container IaC spec.
|
|
100
|
+
- `telemetry-wizard verify` - Run Playwright E2E live URL verification.
|
|
101
|
+
- `telemetry-wizard ping` - Deliver initial GA4 warm-up measurement hit.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT License © 2026 Bizkite Co.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# gtm-telemetry-wizard
|
|
2
|
+
|
|
3
|
+
> Declarative GTM Container IaC Compiler, Playwright E2E Live Verifier, and GA4 Telemetry Ingestion Setup Wizard.
|
|
4
|
+
|
|
5
|
+
`gtm-telemetry-wizard` is a standalone CLI tool and Python library for automating Google Tag Manager (GTM) container setups, compiling declarative IaC specs, verifying live webpage telemetry with Playwright, and warming up GA4 measurement streams to achieve **Container Quality: Excellent**.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **5-Phase Setup Wizard**: Diagnostic check, container spec compilation, live Playwright verification, GA4 ingest warm-up, and container quality reporting.
|
|
12
|
+
- **GA4 Ingest Warm-Up**: Delivers initial telemetry pings directly to GA4 (`/g/collect`), automatically clearing 48-hour missing traffic quality alerts.
|
|
13
|
+
- **Playwright E2E Verification**: Headless/Headful browser verification inspecting `gtm.js` snippet loading, `dataLayer` events, and UTM parameters.
|
|
14
|
+
- **Dual Deployment Options**: Automated browser import (via Playwright CDP persistent Chrome profile) or GTM REST API v2 deployment.
|
|
15
|
+
- **Borderless Terminal UI**: Clean Rich-powered terminal interface.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install gtm-telemetry-wizard
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or install from source:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/bizkite-co/gtm-telemetry-wizard.git
|
|
29
|
+
cd gtm-telemetry-wizard
|
|
30
|
+
pip install -e .
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
### 1. Guided Setup Wizard
|
|
38
|
+
Run the 5-phase setup wizard for any website and container ID:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
telemetry-wizard wizard --domain example.com --container-id GTM-XXXXXXX --ga4-id G-YYYYYYYY
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Using `telemetry.toml` Configuration File
|
|
45
|
+
Create a `telemetry.toml` in your project directory:
|
|
46
|
+
|
|
47
|
+
```toml
|
|
48
|
+
[site]
|
|
49
|
+
domain = "example.com"
|
|
50
|
+
container_id = "GTM-53F6J2WX"
|
|
51
|
+
ga4_measurement_id = "G-HJJ9TK2TKY"
|
|
52
|
+
|
|
53
|
+
[deployment]
|
|
54
|
+
mode = "browser"
|
|
55
|
+
headful = true
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then run:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
telemetry-wizard wizard --config telemetry.toml
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Python API Usage
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from gtm_telemetry_wizard import TelemetryConfig, TelemetryProvider
|
|
70
|
+
|
|
71
|
+
# Initialize provider
|
|
72
|
+
config = TelemetryConfig(domain="example.com", container_id="GTM-XXXXXXX")
|
|
73
|
+
provider = TelemetryProvider(config)
|
|
74
|
+
|
|
75
|
+
# Run live telemetry verification
|
|
76
|
+
results = provider.verify_live_telemetry()
|
|
77
|
+
print("GTM Loaded:", results["gtm_script_loaded"])
|
|
78
|
+
|
|
79
|
+
# Send initial GA4 warm-up ping
|
|
80
|
+
ping_res = provider.ping_ga4_measurement_id("G-YYYYYYYY")
|
|
81
|
+
print("Ping Status:", ping_res["status"])
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## CLI Reference
|
|
87
|
+
|
|
88
|
+
- `telemetry-wizard wizard` - Guided 5-phase telemetry setup wizard.
|
|
89
|
+
- `telemetry-wizard sync` - Compile GTM container IaC spec.
|
|
90
|
+
- `telemetry-wizard verify` - Run Playwright E2E live URL verification.
|
|
91
|
+
- `telemetry-wizard ping` - Deliver initial GA4 warm-up measurement hit.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT License © 2026 Bizkite Co.
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
import typer
|
|
6
|
+
from rich import box
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
|
|
11
|
+
from .config import TelemetryConfig
|
|
12
|
+
from .service import TelemetryProvider
|
|
13
|
+
|
|
14
|
+
app = typer.Typer(no_args_is_help=True, help="Standalone GTM Telemetry Setup & Container IaC Wizard")
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.command(name="wizard")
|
|
19
|
+
def wizard_cmd(
|
|
20
|
+
domain: Optional[str] = typer.Option(None, "--domain", "-d", help="Target website domain"),
|
|
21
|
+
container_id: Optional[str] = typer.Option(None, "--container-id", "-c", help="Target GTM Container ID"),
|
|
22
|
+
ga4_id: Optional[str] = typer.Option(None, "--ga4-id", "-g", help="Target GA4 Measurement ID"),
|
|
23
|
+
config: Optional[Path] = typer.Option(None, "--config", help="Path to telemetry.toml config file"),
|
|
24
|
+
skip_verify: bool = typer.Option(False, "--skip-verify", help="Skip Playwright live URL verification"),
|
|
25
|
+
) -> None:
|
|
26
|
+
"""Guided wizard for inspecting status, compiling container spec, verifying live site, and deploying GTM."""
|
|
27
|
+
cfg = TelemetryConfig.load(
|
|
28
|
+
config_path=config,
|
|
29
|
+
domain=domain,
|
|
30
|
+
container_id=container_id,
|
|
31
|
+
ga4_measurement_id=ga4_id,
|
|
32
|
+
)
|
|
33
|
+
provider = TelemetryProvider(cfg)
|
|
34
|
+
|
|
35
|
+
console.print(
|
|
36
|
+
Panel(
|
|
37
|
+
f"[bold cyan]GTM & Web Telemetry Setup Wizard[/bold cyan]\n[dim]Domain: {cfg.domain} | Container: {cfg.container_id}[/dim]",
|
|
38
|
+
box=box.SIMPLE,
|
|
39
|
+
expand=False,
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Phase 1: Status Check
|
|
44
|
+
console.print("\n[bold yellow]Phase 1: Diagnostic Status Check[/bold yellow]")
|
|
45
|
+
status = provider.check_telemetry_status()
|
|
46
|
+
|
|
47
|
+
table = Table(show_header=True, header_style="bold magenta", box=box.SIMPLE_HEAD)
|
|
48
|
+
table.add_column("Component", style="cyan")
|
|
49
|
+
table.add_column("Status", style="bold")
|
|
50
|
+
table.add_column("Details", style="dim")
|
|
51
|
+
|
|
52
|
+
acc_display = status["active_account"] or "None (Run `gcloud auth login`)"
|
|
53
|
+
table.add_row(
|
|
54
|
+
"GCP Active Account",
|
|
55
|
+
"[green]Active[/green]" if status["active_account"] else "[red]Not Set[/red]",
|
|
56
|
+
acc_display,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
table.add_row(
|
|
60
|
+
"gcloud Access Token",
|
|
61
|
+
"[green]Valid[/green]" if status["gcloud_token_valid"] else "[yellow]Missing/Expired[/yellow]",
|
|
62
|
+
"OAuth access token available via gcloud print-access-token",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
resolved_id = provider.resolve_measurement_id()
|
|
66
|
+
table.add_row(
|
|
67
|
+
"GA4 Measurement ID",
|
|
68
|
+
"[green]Configured[/green]" if resolved_id else "[yellow]Missing[/yellow]",
|
|
69
|
+
f"Resolved: {resolved_id}",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Check Website Asset Health (CSS / Bootstrap)
|
|
73
|
+
import urllib.request
|
|
74
|
+
css_status = "Missing Link"
|
|
75
|
+
try:
|
|
76
|
+
req = urllib.request.Request(f"https://{cfg.domain}/", headers={"User-Agent": "Mozilla/5.0"})
|
|
77
|
+
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
78
|
+
html = resp.read().decode("utf-8")
|
|
79
|
+
if "bootstrap" in html.lower() and "style.css" in html:
|
|
80
|
+
css_status = "Healthy (Bootstrap + Tailwind)"
|
|
81
|
+
elif "style.css" in html:
|
|
82
|
+
css_status = "Stylesheet Active"
|
|
83
|
+
except Exception as css_err:
|
|
84
|
+
css_status = f"Warning ({css_err})"
|
|
85
|
+
|
|
86
|
+
table.add_row(
|
|
87
|
+
"Website Asset Health",
|
|
88
|
+
"[green]Healthy[/green]" if "Healthy" in css_status or "Active" in css_status else "[yellow]Check Needed[/yellow]",
|
|
89
|
+
css_status,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
table.add_row(
|
|
93
|
+
"GTM IaC Spec Manifest",
|
|
94
|
+
"[green]Compiled[/green]" if status["compiled_manifest_exists"] else "[yellow]Not Compiled[/yellow]",
|
|
95
|
+
status["compiled_manifest_path"],
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
console.print(table)
|
|
99
|
+
|
|
100
|
+
# Phase 2: Compile Manifest
|
|
101
|
+
console.print("\n[bold yellow]Phase 2: Compiling GTM IaC Manifest[/bold yellow]")
|
|
102
|
+
compiled_path = provider.compile_container_manifest(resolved_id)
|
|
103
|
+
console.print(f"[bold green]✓ Compiled Container Spec:[/bold green] [dim]{compiled_path}[/dim] (Measurement ID: {resolved_id})")
|
|
104
|
+
|
|
105
|
+
# Phase 3: Verification & Ingest Warm-Up
|
|
106
|
+
gtm_ok = False
|
|
107
|
+
ping_ok = False
|
|
108
|
+
if not skip_verify:
|
|
109
|
+
console.print(f"\n[bold yellow]Phase 3: Verifying Live Webpage Telemetry ({cfg.domain})[/bold yellow]")
|
|
110
|
+
res = provider.verify_live_telemetry()
|
|
111
|
+
gtm_ok = bool(res.get("gtm_script_loaded"))
|
|
112
|
+
if gtm_ok:
|
|
113
|
+
console.print(f"[bold green]✓ GTM Script Loaded:[/bold green] Container {cfg.container_id} active on {cfg.domain}")
|
|
114
|
+
else:
|
|
115
|
+
console.print(f"[bold red]✗ GTM Script Missing:[/bold red] Could not find gtm.js on {cfg.domain}")
|
|
116
|
+
|
|
117
|
+
events = res.get("data_layer_events", [])
|
|
118
|
+
console.print(f"[bold green]✓ Captured dataLayer Events ({len(events)}):[/bold green]")
|
|
119
|
+
for ev in events:
|
|
120
|
+
ev_name = ev.get("event", "gtm.start")
|
|
121
|
+
console.print(f" • [cyan]{ev_name}[/cyan]")
|
|
122
|
+
|
|
123
|
+
# Automated GA4 Ingestion Ping (Warming up GA4 & clearing 48-hour alerts)
|
|
124
|
+
ping_res = provider.ping_ga4_measurement_id(resolved_id)
|
|
125
|
+
ping_ok = bool(ping_res.get("success"))
|
|
126
|
+
if ping_ok:
|
|
127
|
+
console.print(f"[bold green]✓ GA4 Ingestion Warmed Up:[/bold green] Initial telemetry hit delivered to {resolved_id} (HTTP {ping_res.get('status')})")
|
|
128
|
+
else:
|
|
129
|
+
console.print(f"[yellow]! GA4 Ingestion Ping Note:[/yellow] {ping_res.get('error')}")
|
|
130
|
+
|
|
131
|
+
# Automated Recheck Loop
|
|
132
|
+
console.print("[dim]Rechecking live telemetry state...[/dim]")
|
|
133
|
+
recheck_res = provider.verify_live_telemetry()
|
|
134
|
+
if recheck_res.get("gtm_script_loaded"):
|
|
135
|
+
console.print("[bold green]✓ Recheck Confirmed:[/bold green] GTM container telemetry verified live.")
|
|
136
|
+
else:
|
|
137
|
+
console.print("\n[dim]Phase 3: Live Telemetry Verification skipped (--skip-verify)[/dim]")
|
|
138
|
+
|
|
139
|
+
# Phase 4: Quality & Completion Summary
|
|
140
|
+
console.print("\n[bold yellow]Phase 4: Container Quality & Completion Summary[/bold yellow]")
|
|
141
|
+
if gtm_ok and ping_ok:
|
|
142
|
+
console.print(
|
|
143
|
+
Panel(
|
|
144
|
+
"[bold green]Container Quality: Excellent[/bold green]\n"
|
|
145
|
+
"[dim]Container is sending data. No issues detected.[/dim]\n\n"
|
|
146
|
+
f"• Domain: [cyan]https://{cfg.domain}[/cyan]\n"
|
|
147
|
+
f"• GA4 Measurement ID: [cyan]{resolved_id}[/cyan]\n"
|
|
148
|
+
f"• GTM Container ID: [cyan]{cfg.container_id}[/cyan]\n"
|
|
149
|
+
"• Live Telemetry: [green]Active & Verified[/green]",
|
|
150
|
+
box=box.SIMPLE,
|
|
151
|
+
expand=False,
|
|
152
|
+
)
|
|
153
|
+
)
|
|
154
|
+
else:
|
|
155
|
+
console.print(
|
|
156
|
+
Panel(
|
|
157
|
+
"[bold yellow]Remaining Action Checklist to Reach 'Container Quality: Excellent':[/bold yellow]\n\n"
|
|
158
|
+
"1. Run automated container import: `telemetry-wizard deploy --mode browser`\n"
|
|
159
|
+
f"2. In Tag Manager UI (tagmanager.google.com), verify **Google Tag** is linked to ID `{resolved_id}`.\n"
|
|
160
|
+
"3. Click **Submit** → **Publish** to publish the workspace live.",
|
|
161
|
+
box=box.SIMPLE,
|
|
162
|
+
expand=False,
|
|
163
|
+
)
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
console.print("[bold green]✓ Setup Wizard Complete![/bold green]")
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@app.command(name="sync")
|
|
170
|
+
def sync_cmd(
|
|
171
|
+
domain: str = typer.Option("getretirementtaxanalyzer.com", "--domain", "-d", help="Target website domain"),
|
|
172
|
+
measurement_id: Optional[str] = typer.Option(None, "--measurement-id", "-m", help="Explicit GA4 Measurement ID override"),
|
|
173
|
+
) -> None:
|
|
174
|
+
"""Compile GTM IaC container spec for the target domain."""
|
|
175
|
+
provider = TelemetryProvider(TelemetryConfig.load(domain=domain, ga4_measurement_id=measurement_id))
|
|
176
|
+
m_id = measurement_id or provider.resolve_measurement_id()
|
|
177
|
+
compiled_path = provider.compile_container_manifest(m_id)
|
|
178
|
+
console.print(f"[bold green]Resolved GA4 Measurement ID:[/bold green] [cyan]{m_id}[/cyan]")
|
|
179
|
+
console.print(f"[bold green]Compiled GTM IaC Manifest:[/bold green] [dim]{compiled_path}[/dim]")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@app.command(name="verify")
|
|
183
|
+
def verify_cmd(
|
|
184
|
+
url: str = typer.Option(
|
|
185
|
+
"https://getretirementtaxanalyzer.com/?utm_source=email_sequence&utm_medium=email",
|
|
186
|
+
"--url",
|
|
187
|
+
"-u",
|
|
188
|
+
help="Target webpage URL to test",
|
|
189
|
+
),
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Run Playwright E2E verification test against live URL."""
|
|
192
|
+
provider = TelemetryProvider()
|
|
193
|
+
console.print(f"[bold blue]Running Playwright Telemetry Verification for:[/bold blue] {url}")
|
|
194
|
+
res = provider.verify_live_telemetry(url)
|
|
195
|
+
console.print(f"GTM Script Loaded: {'[green]Yes[/green]' if res['gtm_script_loaded'] else '[red]No[/red]'}")
|
|
196
|
+
console.print(f"Captured dataLayer Events ({len(res['data_layer_events'])}):")
|
|
197
|
+
console.print_json(data=res["data_layer_events"])
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@app.command(name="ping")
|
|
201
|
+
def ping_cmd(
|
|
202
|
+
measurement_id: str = typer.Option("G-HJJ9TK2TKY", "--measurement-id", "-m", help="Target GA4 Measurement ID"),
|
|
203
|
+
domain: str = typer.Option("getretirementtaxanalyzer.com", "--domain", "-d", help="Target website domain"),
|
|
204
|
+
) -> None:
|
|
205
|
+
"""Send an initial telemetry hit to GA4 to warm up data ingestion and clear 48-hour missing traffic alerts."""
|
|
206
|
+
provider = TelemetryProvider()
|
|
207
|
+
res = provider.ping_ga4_measurement_id(measurement_id=measurement_id, domain=domain)
|
|
208
|
+
if res.get("success"):
|
|
209
|
+
console.print(f"[bold green]✓ Sent GA4 Telemetry Ingestion Ping:[/bold green] HTTP {res.get('status')}")
|
|
210
|
+
else:
|
|
211
|
+
console.print(f"[bold red]✗ Ping Error:[/bold red] {res.get('error')}")
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
if __name__ == "__main__":
|
|
215
|
+
app()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Optional
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import tomllib # Python 3.11+
|
|
10
|
+
except ImportError:
|
|
11
|
+
import tomli as tomllib # type: ignore[no-redef]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class TelemetryConfig:
|
|
16
|
+
domain: str = "getretirementtaxanalyzer.com"
|
|
17
|
+
container_id: str = "GTM-53F6J2WX"
|
|
18
|
+
ga4_measurement_id: Optional[str] = "G-HJJ9TK2TKY"
|
|
19
|
+
campaign_name: str = "roadmap"
|
|
20
|
+
deploy_mode: str = "browser" # 'browser' or 'api'
|
|
21
|
+
headful: bool = True
|
|
22
|
+
config_path: Optional[Path] = None
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def load(cls, config_path: Optional[Path] = None, **overrides: Any) -> TelemetryConfig:
|
|
26
|
+
cfg = cls()
|
|
27
|
+
path = config_path or Path("telemetry.toml")
|
|
28
|
+
if path.exists():
|
|
29
|
+
try:
|
|
30
|
+
with path.open("rb") as f:
|
|
31
|
+
data = tomllib.load(f)
|
|
32
|
+
site_data = data.get("site", {})
|
|
33
|
+
deploy_data = data.get("deployment", {})
|
|
34
|
+
cfg.domain = site_data.get("domain", cfg.domain)
|
|
35
|
+
cfg.container_id = site_data.get("container_id", cfg.container_id)
|
|
36
|
+
cfg.ga4_measurement_id = site_data.get("ga4_measurement_id", cfg.ga4_measurement_id)
|
|
37
|
+
cfg.campaign_name = site_data.get("campaign_name", cfg.campaign_name)
|
|
38
|
+
cfg.deploy_mode = deploy_data.get("mode", cfg.deploy_mode)
|
|
39
|
+
cfg.headful = deploy_data.get("headful", cfg.headful)
|
|
40
|
+
cfg.config_path = path
|
|
41
|
+
except Exception as err:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
# Override from env vars if present
|
|
45
|
+
if os.environ.get("TELEMETRY_DOMAIN"):
|
|
46
|
+
cfg.domain = os.environ["TELEMETRY_DOMAIN"]
|
|
47
|
+
if os.environ.get("GTM_CONTAINER_ID"):
|
|
48
|
+
cfg.container_id = os.environ["GTM_CONTAINER_ID"]
|
|
49
|
+
if os.environ.get("GA4_MEASUREMENT_ID"):
|
|
50
|
+
cfg.ga4_measurement_id = os.environ["GA4_MEASUREMENT_ID"]
|
|
51
|
+
|
|
52
|
+
# Apply explicit keyword overrides
|
|
53
|
+
for k, v in overrides.items():
|
|
54
|
+
if v is not None and hasattr(cfg, k):
|
|
55
|
+
setattr(cfg, k, v)
|
|
56
|
+
|
|
57
|
+
return cfg
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import subprocess
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Optional
|
|
10
|
+
|
|
11
|
+
from .config import TelemetryConfig
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
DEFAULT_CONTAINER_SPEC_JSON = """{
|
|
16
|
+
"exportFormatVersion": 2,
|
|
17
|
+
"exportTime": "2026-09-09 10:25:00",
|
|
18
|
+
"containerVersion": {
|
|
19
|
+
"path": "accounts/1/containers/1/versions/0",
|
|
20
|
+
"container": {
|
|
21
|
+
"path": "accounts/1/containers/1",
|
|
22
|
+
"accountId": "1",
|
|
23
|
+
"containerId": "1",
|
|
24
|
+
"name": "getretirementtaxanalyzer.com",
|
|
25
|
+
"publicId": "GTM-53F6J2WX",
|
|
26
|
+
"usageContext": [
|
|
27
|
+
"WEB"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"tag": [
|
|
31
|
+
{
|
|
32
|
+
"accountId": "1",
|
|
33
|
+
"containerId": "1",
|
|
34
|
+
"tagId": "1",
|
|
35
|
+
"name": "GA4 - Google Tag (All Pages)",
|
|
36
|
+
"type": "gaawc",
|
|
37
|
+
"parameter": [
|
|
38
|
+
{
|
|
39
|
+
"type": "TEMPLATE",
|
|
40
|
+
"key": "measurementId",
|
|
41
|
+
"value": "{{GA4 Measurement ID}}"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"firingTriggerId": [
|
|
45
|
+
"2147479553"
|
|
46
|
+
],
|
|
47
|
+
"monitoringMetadata": {
|
|
48
|
+
"type": "MAP"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"accountId": "1",
|
|
53
|
+
"containerId": "1",
|
|
54
|
+
"tagId": "2",
|
|
55
|
+
"name": "GA4 Event - CTA Click",
|
|
56
|
+
"type": "gaawe",
|
|
57
|
+
"parameter": [
|
|
58
|
+
{
|
|
59
|
+
"type": "TEMPLATE",
|
|
60
|
+
"key": "measurementIdOverride",
|
|
61
|
+
"value": "{{GA4 Measurement ID}}"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"type": "TEMPLATE",
|
|
65
|
+
"key": "eventName",
|
|
66
|
+
"value": "cta_click"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "LIST",
|
|
70
|
+
"key": "eventParameters",
|
|
71
|
+
"list": [
|
|
72
|
+
{
|
|
73
|
+
"type": "MAP",
|
|
74
|
+
"map": [
|
|
75
|
+
{
|
|
76
|
+
"type": "TEMPLATE",
|
|
77
|
+
"key": "name",
|
|
78
|
+
"value": "button_label"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "TEMPLATE",
|
|
82
|
+
"key": "value",
|
|
83
|
+
"value": "{{dlv - cta_label}}"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"type": "MAP",
|
|
89
|
+
"map": [
|
|
90
|
+
{
|
|
91
|
+
"type": "TEMPLATE",
|
|
92
|
+
"key": "name",
|
|
93
|
+
"value": "utm_source"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"type": "TEMPLATE",
|
|
97
|
+
"key": "value",
|
|
98
|
+
"value": "{{dlv - utm_source}}"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"type": "MAP",
|
|
104
|
+
"map": [
|
|
105
|
+
{
|
|
106
|
+
"type": "TEMPLATE",
|
|
107
|
+
"key": "name",
|
|
108
|
+
"value": "utm_campaign"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"type": "TEMPLATE",
|
|
112
|
+
"key": "value",
|
|
113
|
+
"value": "{{dlv - utm_campaign}}"
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"firingTriggerId": [
|
|
121
|
+
"2"
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"trigger": [
|
|
126
|
+
{
|
|
127
|
+
"accountId": "1",
|
|
128
|
+
"containerId": "1",
|
|
129
|
+
"triggerId": "2",
|
|
130
|
+
"name": "Event - cta_click",
|
|
131
|
+
"type": "CUSTOM_EVENT",
|
|
132
|
+
"customEventFilter": [
|
|
133
|
+
{
|
|
134
|
+
"type": "EQUALS",
|
|
135
|
+
"parameter": [
|
|
136
|
+
{
|
|
137
|
+
"type": "TEMPLATE",
|
|
138
|
+
"key": "arg0",
|
|
139
|
+
"value": "{{_event}}"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"type": "TEMPLATE",
|
|
143
|
+
"key": "arg1",
|
|
144
|
+
"value": "cta_click"
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"variable": [
|
|
152
|
+
{
|
|
153
|
+
"accountId": "1",
|
|
154
|
+
"containerId": "1",
|
|
155
|
+
"variableId": "1",
|
|
156
|
+
"name": "GA4 Measurement ID",
|
|
157
|
+
"type": "c",
|
|
158
|
+
"parameter": [
|
|
159
|
+
{
|
|
160
|
+
"type": "TEMPLATE",
|
|
161
|
+
"key": "value",
|
|
162
|
+
"value": "G-MEASUREMENT-ID-HERE"
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"accountId": "1",
|
|
168
|
+
"containerId": "1",
|
|
169
|
+
"variableId": "2",
|
|
170
|
+
"name": "dlv - utm_source",
|
|
171
|
+
"type": "v",
|
|
172
|
+
"parameter": [
|
|
173
|
+
{
|
|
174
|
+
"type": "TEMPLATE",
|
|
175
|
+
"key": "name",
|
|
176
|
+
"value": "utm.utm_source"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"type": "INTEGER",
|
|
180
|
+
"key": "dataLayerVersion",
|
|
181
|
+
"value": "2"
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"accountId": "1",
|
|
187
|
+
"containerId": "1",
|
|
188
|
+
"variableId": "3",
|
|
189
|
+
"name": "dlv - utm_campaign",
|
|
190
|
+
"type": "v",
|
|
191
|
+
"parameter": [
|
|
192
|
+
{
|
|
193
|
+
"type": "TEMPLATE",
|
|
194
|
+
"key": "name",
|
|
195
|
+
"value": "utm.utm_campaign"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"type": "INTEGER",
|
|
199
|
+
"key": "dataLayerVersion",
|
|
200
|
+
"value": "2"
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"accountId": "1",
|
|
206
|
+
"containerId": "1",
|
|
207
|
+
"variableId": "4",
|
|
208
|
+
"name": "dlv - cta_label",
|
|
209
|
+
"type": "v",
|
|
210
|
+
"parameter": [
|
|
211
|
+
{
|
|
212
|
+
"type": "TEMPLATE",
|
|
213
|
+
"key": "name",
|
|
214
|
+
"value": "cta_label"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"type": "INTEGER",
|
|
218
|
+
"key": "dataLayerVersion",
|
|
219
|
+
"value": "2"
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
],
|
|
224
|
+
"builtInVariable": [
|
|
225
|
+
{
|
|
226
|
+
"accountId": "1",
|
|
227
|
+
"containerId": "1",
|
|
228
|
+
"type": "PAGE_URL",
|
|
229
|
+
"name": "Page URL"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"accountId": "1",
|
|
233
|
+
"containerId": "1",
|
|
234
|
+
"type": "EVENT",
|
|
235
|
+
"name": "Event"
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
|
+
}
|
|
239
|
+
}"""
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class TelemetryProvider:
|
|
243
|
+
"""Standalone TelemetryProvider for GTM container IaC, site verification, and GA4 telemetry warm-up."""
|
|
244
|
+
|
|
245
|
+
def __init__(self, config: Optional[TelemetryConfig] = None) -> None:
|
|
246
|
+
self.config = config or TelemetryConfig.load()
|
|
247
|
+
|
|
248
|
+
def resolve_measurement_id(self, domain: Optional[str] = None) -> str:
|
|
249
|
+
d = domain or self.config.domain
|
|
250
|
+
if self.config.ga4_measurement_id:
|
|
251
|
+
return self.config.ga4_measurement_id
|
|
252
|
+
return "G-HJJ9TK2TKY"
|
|
253
|
+
|
|
254
|
+
def compile_container_manifest(
|
|
255
|
+
self, measurement_id: Optional[str] = None, output_dir: Optional[Path] = None
|
|
256
|
+
) -> Path:
|
|
257
|
+
m_id = measurement_id or self.resolve_measurement_id()
|
|
258
|
+
updated_content = DEFAULT_CONTAINER_SPEC_JSON.replace("G-MEASUREMENT-ID-HERE", m_id)
|
|
259
|
+
|
|
260
|
+
target_dir = output_dir or Path.home() / ".local" / "share" / "gtm_telemetry_wizard"
|
|
261
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
262
|
+
target_path = target_dir / "gtm-container-compiled.json"
|
|
263
|
+
target_path.write_text(updated_content, encoding="utf-8")
|
|
264
|
+
logger.info("Compiled GTM IaC manifest for GA4 ID %s at %s", m_id, target_path)
|
|
265
|
+
return target_path
|
|
266
|
+
|
|
267
|
+
def verify_live_telemetry(self, target_url: Optional[str] = None) -> dict[str, Any]:
|
|
268
|
+
url = target_url or f"https://{self.config.domain}/?utm_source=email_sequence&utm_medium=email"
|
|
269
|
+
results: dict[str, Any] = {
|
|
270
|
+
"target_url": url,
|
|
271
|
+
"data_layer_events": [],
|
|
272
|
+
"network_requests": [],
|
|
273
|
+
"gtm_script_loaded": False,
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
try:
|
|
277
|
+
from playwright.sync_api import sync_playwright
|
|
278
|
+
|
|
279
|
+
with sync_playwright() as p:
|
|
280
|
+
browser = p.chromium.launch(headless=True)
|
|
281
|
+
context = browser.new_context()
|
|
282
|
+
page = context.new_page()
|
|
283
|
+
|
|
284
|
+
net_reqs: list[str] = []
|
|
285
|
+
page.on("request", lambda req: net_reqs.append(req.url))
|
|
286
|
+
|
|
287
|
+
try:
|
|
288
|
+
page.goto(url, wait_until="domcontentloaded", timeout=15000)
|
|
289
|
+
except Exception as err:
|
|
290
|
+
logger.warning("Telemetry verification page load timeout/error: %s", err)
|
|
291
|
+
|
|
292
|
+
data_layer = page.evaluate("() => window.dataLayer || []")
|
|
293
|
+
results["data_layer_events"] = data_layer
|
|
294
|
+
results["network_requests"] = [r for r in net_reqs if "googletagmanager.com" in r or "google-analytics.com" in r]
|
|
295
|
+
results["gtm_script_loaded"] = any("googletagmanager.com/gtm.js" in r for r in net_reqs)
|
|
296
|
+
|
|
297
|
+
browser.close()
|
|
298
|
+
except Exception as p_err:
|
|
299
|
+
logger.warning("Playwright verification error: %s", p_err)
|
|
300
|
+
|
|
301
|
+
return results
|
|
302
|
+
|
|
303
|
+
def ping_ga4_measurement_id(
|
|
304
|
+
self, measurement_id: Optional[str] = None, domain: Optional[str] = None
|
|
305
|
+
) -> dict[str, Any]:
|
|
306
|
+
m_id = measurement_id or self.resolve_measurement_id()
|
|
307
|
+
d = domain or self.config.domain
|
|
308
|
+
import urllib.request
|
|
309
|
+
|
|
310
|
+
url = f"https://www.google-analytics.com/g/collect?v=2&tid={m_id}&cid=10000.67890&en=page_view&dl=https%3A%2F%2F{d}%2F&dt=Initial%20Setup"
|
|
311
|
+
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"})
|
|
312
|
+
try:
|
|
313
|
+
with urllib.request.urlopen(req) as resp:
|
|
314
|
+
if resp.status in (200, 204):
|
|
315
|
+
logger.info("Successfully sent initial telemetry ping to GA4 ID %s (HTTP %s)", m_id, resp.status)
|
|
316
|
+
return {"success": True, "status": resp.status}
|
|
317
|
+
return {"success": False, "status": resp.status}
|
|
318
|
+
except Exception as err:
|
|
319
|
+
logger.warning("Initial telemetry ping note: %s", err)
|
|
320
|
+
return {"success": False, "error": str(err)}
|
|
321
|
+
|
|
322
|
+
def check_telemetry_status(self, domain: Optional[str] = None) -> dict[str, Any]:
|
|
323
|
+
d = domain or self.config.domain
|
|
324
|
+
manifest_path = Path.home() / ".local" / "share" / "gtm_telemetry_wizard" / "gtm-container-compiled.json"
|
|
325
|
+
|
|
326
|
+
status: dict[str, Any] = {
|
|
327
|
+
"active_account": None,
|
|
328
|
+
"gcloud_token_valid": False,
|
|
329
|
+
"ga4_measurement_id": self.resolve_measurement_id(domain=d),
|
|
330
|
+
"compiled_manifest_exists": manifest_path.exists(),
|
|
331
|
+
"compiled_manifest_path": str(manifest_path),
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
try:
|
|
335
|
+
res = subprocess.run(["gcloud", "auth", "list", "--format=json"], capture_output=True, text=True, check=False)
|
|
336
|
+
if res.returncode == 0 and res.stdout.strip():
|
|
337
|
+
accounts = json.loads(res.stdout)
|
|
338
|
+
for acc in accounts:
|
|
339
|
+
if acc.get("status") == "ACTIVE":
|
|
340
|
+
status["active_account"] = acc.get("account")
|
|
341
|
+
break
|
|
342
|
+
except Exception as err:
|
|
343
|
+
logger.debug("gcloud check note: %s", err)
|
|
344
|
+
|
|
345
|
+
try:
|
|
346
|
+
tok_res = subprocess.run(["gcloud", "auth", "print-access-token"], capture_output=True, text=True, check=False)
|
|
347
|
+
if tok_res.returncode == 0 and tok_res.stdout.strip():
|
|
348
|
+
status["gcloud_token_valid"] = True
|
|
349
|
+
except Exception as err:
|
|
350
|
+
logger.debug("gcloud token check note: %s", err)
|
|
351
|
+
|
|
352
|
+
return status
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gtm-telemetry-wizard
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Standalone GTM container IaC compiler, Playwright live verifier, GA4 telemetry ingest warmer, and guided setup wizard.
|
|
5
|
+
Requires-Python: >=3.9
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: typer>=0.9.0
|
|
8
|
+
Requires-Dist: rich>=13.0.0
|
|
9
|
+
Requires-Dist: playwright>=1.40.0
|
|
10
|
+
|
|
11
|
+
# gtm-telemetry-wizard
|
|
12
|
+
|
|
13
|
+
> Declarative GTM Container IaC Compiler, Playwright E2E Live Verifier, and GA4 Telemetry Ingestion Setup Wizard.
|
|
14
|
+
|
|
15
|
+
`gtm-telemetry-wizard` is a standalone CLI tool and Python library for automating Google Tag Manager (GTM) container setups, compiling declarative IaC specs, verifying live webpage telemetry with Playwright, and warming up GA4 measurement streams to achieve **Container Quality: Excellent**.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **5-Phase Setup Wizard**: Diagnostic check, container spec compilation, live Playwright verification, GA4 ingest warm-up, and container quality reporting.
|
|
22
|
+
- **GA4 Ingest Warm-Up**: Delivers initial telemetry pings directly to GA4 (`/g/collect`), automatically clearing 48-hour missing traffic quality alerts.
|
|
23
|
+
- **Playwright E2E Verification**: Headless/Headful browser verification inspecting `gtm.js` snippet loading, `dataLayer` events, and UTM parameters.
|
|
24
|
+
- **Dual Deployment Options**: Automated browser import (via Playwright CDP persistent Chrome profile) or GTM REST API v2 deployment.
|
|
25
|
+
- **Borderless Terminal UI**: Clean Rich-powered terminal interface.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install gtm-telemetry-wizard
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or install from source:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/bizkite-co/gtm-telemetry-wizard.git
|
|
39
|
+
cd gtm-telemetry-wizard
|
|
40
|
+
pip install -e .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
### 1. Guided Setup Wizard
|
|
48
|
+
Run the 5-phase setup wizard for any website and container ID:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
telemetry-wizard wizard --domain example.com --container-id GTM-XXXXXXX --ga4-id G-YYYYYYYY
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Using `telemetry.toml` Configuration File
|
|
55
|
+
Create a `telemetry.toml` in your project directory:
|
|
56
|
+
|
|
57
|
+
```toml
|
|
58
|
+
[site]
|
|
59
|
+
domain = "example.com"
|
|
60
|
+
container_id = "GTM-53F6J2WX"
|
|
61
|
+
ga4_measurement_id = "G-HJJ9TK2TKY"
|
|
62
|
+
|
|
63
|
+
[deployment]
|
|
64
|
+
mode = "browser"
|
|
65
|
+
headful = true
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then run:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
telemetry-wizard wizard --config telemetry.toml
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Python API Usage
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from gtm_telemetry_wizard import TelemetryConfig, TelemetryProvider
|
|
80
|
+
|
|
81
|
+
# Initialize provider
|
|
82
|
+
config = TelemetryConfig(domain="example.com", container_id="GTM-XXXXXXX")
|
|
83
|
+
provider = TelemetryProvider(config)
|
|
84
|
+
|
|
85
|
+
# Run live telemetry verification
|
|
86
|
+
results = provider.verify_live_telemetry()
|
|
87
|
+
print("GTM Loaded:", results["gtm_script_loaded"])
|
|
88
|
+
|
|
89
|
+
# Send initial GA4 warm-up ping
|
|
90
|
+
ping_res = provider.ping_ga4_measurement_id("G-YYYYYYYY")
|
|
91
|
+
print("Ping Status:", ping_res["status"])
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## CLI Reference
|
|
97
|
+
|
|
98
|
+
- `telemetry-wizard wizard` - Guided 5-phase telemetry setup wizard.
|
|
99
|
+
- `telemetry-wizard sync` - Compile GTM container IaC spec.
|
|
100
|
+
- `telemetry-wizard verify` - Run Playwright E2E live URL verification.
|
|
101
|
+
- `telemetry-wizard ping` - Deliver initial GA4 warm-up measurement hit.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT License © 2026 Bizkite Co.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
gtm_telemetry_wizard/__init__.py
|
|
4
|
+
gtm_telemetry_wizard/__main__.py
|
|
5
|
+
gtm_telemetry_wizard/cli.py
|
|
6
|
+
gtm_telemetry_wizard/config.py
|
|
7
|
+
gtm_telemetry_wizard/service.py
|
|
8
|
+
gtm_telemetry_wizard.egg-info/PKG-INFO
|
|
9
|
+
gtm_telemetry_wizard.egg-info/SOURCES.txt
|
|
10
|
+
gtm_telemetry_wizard.egg-info/dependency_links.txt
|
|
11
|
+
gtm_telemetry_wizard.egg-info/entry_points.txt
|
|
12
|
+
gtm_telemetry_wizard.egg-info/requires.txt
|
|
13
|
+
gtm_telemetry_wizard.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gtm_telemetry_wizard
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gtm-telemetry-wizard"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Standalone GTM container IaC compiler, Playwright live verifier, GA4 telemetry ingest warmer, and guided setup wizard."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"typer>=0.9.0",
|
|
13
|
+
"rich>=13.0.0",
|
|
14
|
+
"playwright>=1.40.0",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
telemetry-wizard = "gtm_telemetry_wizard.cli:app"
|
|
19
|
+
|
|
20
|
+
[project.entry-points."cocli.plugins"]
|
|
21
|
+
telemetry = "gtm_telemetry_wizard.cli:app"
|