← back to Ga Allsites
chore: lint (14 autofix) + light refactor of session GA4 scripts (session close)
277b9434b3689ff646da265d46eb94596f5bf5a0 · 2026-08-17 17:14:27 -0700 · Steve Abrams
Files touched
M create_dw_ga4.pyM create_shell_ga4.pyM delete_orphan_ga4.pyA poll_delete_ga4.pyM resolve_orphan_ga4.pyM tracking-coverage-matrix.py
Diff
commit 277b9434b3689ff646da265d46eb94596f5bf5a0
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 17 17:14:27 2026 -0700
chore: lint (14 autofix) + light refactor of session GA4 scripts (session close)
---
create_dw_ga4.py | 3 ++-
create_shell_ga4.py | 10 +++++++---
delete_orphan_ga4.py | 2 ++
poll_delete_ga4.py | 39 +++++++++++++++++++++++++++++++++++++++
resolve_orphan_ga4.py | 2 ++
tracking-coverage-matrix.py | 22 +++++++++++++++++-----
6 files changed, 69 insertions(+), 9 deletions(-)
diff --git a/create_dw_ga4.py b/create_dw_ga4.py
old mode 100644
new mode 100755
index ded2f05..8aa9caf
--- a/create_dw_ga4.py
+++ b/create_dw_ga4.py
@@ -6,7 +6,8 @@ Usage: python3 ~/Projects/ga-allsites/create_dw_ga4.py
"""
import json
import pathlib
-from google.analytics.admin import AnalyticsAdminServiceClient, Property, DataStream
+
+from google.analytics.admin import AnalyticsAdminServiceClient, DataStream, Property
KEY = pathlib.Path.home() / ".config" / "ga-analytics-agent" / "service-account.json"
PENDING = pathlib.Path.home() / ".claude" / "skills" / "analytics" / "rollout" / "pending_ga.json"
diff --git a/create_shell_ga4.py b/create_shell_ga4.py
old mode 100644
new mode 100755
index 3359edf..ed3b325
--- a/create_shell_ga4.py
+++ b/create_shell_ga4.py
@@ -4,8 +4,11 @@ DesignerWallcoverings GA4 account (15714274, SA has Editor). Steve-run.
Writes G-ids to gtm/shell-ga4.json; then Claude injects the gtag per site.
Usage: python3 ~/Projects/ga-allsites/create_shell_ga4.py
"""
-import json, pathlib
-from google.analytics.admin import AnalyticsAdminServiceClient, Property, DataStream
+import json
+import pathlib
+
+from google.analytics.admin import AnalyticsAdminServiceClient, DataStream, Property
+
KEY = pathlib.Path.home()/".config"/"ga-analytics-agent"/"service-account.json"
ACCT = "accounts/15714274"
SHELLS = {
@@ -19,7 +22,8 @@ SHELLS = {
"cypresawards.com":"Cypres Awards","nodailyworries.com":"No Daily Worries","petitionyour.com":"Petition Your",
"studentdebtcrisis.org":"Student Debt Crisis"}
client = AnalyticsAdminServiceClient.from_service_account_file(str(KEY))
-outf = pathlib.Path(__file__).parent/"gtm"/"shell-ga4.json"
+outf = pathlib.Path(__file__).parent / "gtm" / "shell-ga4.json"
+outf.parent.mkdir(parents=True, exist_ok=True)
out = json.loads(outf.read_text()) if outf.exists() else {}
for dom, name in SHELLS.items():
if out.get(dom):
diff --git a/delete_orphan_ga4.py b/delete_orphan_ga4.py
old mode 100644
new mode 100755
index d667ffc..b1c289e
--- a/delete_orphan_ga4.py
+++ b/delete_orphan_ga4.py
@@ -1,7 +1,9 @@
#!/usr/bin/env python3
"""Delete the 3 GA4 properties Steve approved (soft-delete, recoverable ~35 days)."""
import pathlib
+
from google.analytics.admin import AnalyticsAdminServiceClient
+
KEY = pathlib.Path.home()/".config"/"ga-analytics-agent"/"service-account.json"
TARGETS = [
("G-9K93LH6GH1", "properties/548357651", "Momentum DW (momentum.designerwallcoverings.com)"),
diff --git a/poll_delete_ga4.py b/poll_delete_ga4.py
new file mode 100755
index 0000000..c1dba99
--- /dev/null
+++ b/poll_delete_ga4.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+"""Poll until SA gets Editor on 371997142, then soft-delete both. Every 90s, up to 30 tries (~45 min)."""
+import pathlib
+import time
+
+from google.analytics.admin import AnalyticsAdminServiceClient
+
+KEY = pathlib.Path.home() / ".config" / "ga-analytics-agent" / "service-account.json"
+TARGETS = [
+ ("properties/535741032", "goodquestion.ai"),
+ ("properties/535735055", "nosarabeachfrontrentals.com"),
+]
+MAX_TRIES = 30
+POLL_INTERVAL_S = 90
+
+c = AnalyticsAdminServiceClient.from_service_account_file(str(KEY))
+done = set()
+for attempt in range(1, MAX_TRIES + 1):
+ for prop, label in TARGETS:
+ if prop in done:
+ continue
+ try:
+ c.delete_property(name=prop)
+ done.add(prop)
+ print(f"[try {attempt}] ✅ DELETED {prop} ({label})", flush=True)
+ except Exception as e:
+ msg = str(e)
+ if "not found" in msg.lower():
+ done.add(prop)
+ print(f"[try {attempt}] ✅ already gone {prop}", flush=True)
+ else:
+ print(f"[try {attempt}] ⏳ {prop}: {msg[:45]}", flush=True)
+ if len(done) == len(TARGETS):
+ print(f"\n✅ ALL DONE {len(done)}/2 (soft-delete, recoverable ~35d)", flush=True)
+ break
+ if attempt < MAX_TRIES:
+ time.sleep(POLL_INTERVAL_S)
+else:
+ print(f"\n⚠️ gave up after ~45min, {len(done)}/2 deleted. Editor role likely still not set.", flush=True)
diff --git a/resolve_orphan_ga4.py b/resolve_orphan_ga4.py
old mode 100644
new mode 100755
index 65077ca..fbe922e
--- a/resolve_orphan_ga4.py
+++ b/resolve_orphan_ga4.py
@@ -1,7 +1,9 @@
#!/usr/bin/env python3
"""Resolve the 3 orphan measurement IDs -> GA4 property (+ verify domain), DRY RUN (no delete)."""
import pathlib
+
from google.analytics.admin import AnalyticsAdminServiceClient
+
KEY = pathlib.Path.home()/".config"/"ga-analytics-agent"/"service-account.json"
ORPHANS = {
"G-9K93LH6GH1": "momentumdw.com",
diff --git a/tracking-coverage-matrix.py b/tracking-coverage-matrix.py
old mode 100644
new mode 100755
index 571cdb4..41ed112
--- a/tracking-coverage-matrix.py
+++ b/tracking-coverage-matrix.py
@@ -4,12 +4,23 @@ Gathers owned domains (Cloudflare + GoDaddy + GA4 slugs), curls each in parallel
detects GTM / GA4 / Meta Pixel / Pinterest in the HTML, cross-refs GSC grants from
the ga-allsites cache, and prints a matrix + punch-lists for the LIVE sites.
"""
-import json, os, pathlib, re, ssl, urllib.request
+import json
+import os
+import pathlib
+import re
+import ssl
+import urllib.request
from concurrent.futures import ThreadPoolExecutor
HERE = pathlib.Path(__file__).parent
SEC = pathlib.Path.home() / "Projects" / "secrets-manager" / ".env"
+# Probe tuning — tweak here if needed
+PROBE_WORKERS = 24 # parallel HTTP workers
+PROBE_TIMEOUT_S = 8 # per-site connect+read timeout
+MAX_BODY_BYTES = 300_000 # cap HTML read to avoid huge pages
+LIVE_BODY_MIN = 1_200 # minimum byte count to consider a page "real"
+
def env(*keys):
for k in keys:
if os.environ.get(k): return os.environ[k]
@@ -58,13 +69,13 @@ def probe(d):
"gsc": d in gsc}
try:
req = urllib.request.Request(f"https://{d}/", headers={"User-Agent": "Mozilla/5.0"})
- with urllib.request.urlopen(req, timeout=8, context=ctx) as r:
+ with urllib.request.urlopen(req, timeout=PROBE_TIMEOUT_S, context=ctx) as r:
row["http"] = r.status
final = r.geturl()
- body = r.read(300000).decode("utf-8", "ignore")
+ body = r.read(MAX_BODY_BYTES).decode("utf-8", "ignore")
# live = 200 + real body + not a cross-host redirect
host = re.sub(r"^https?://(www\.)?", "", final).split("/")[0]
- row["live"] = row["http"] == 200 and len(body) > 1200 and d.replace("www.", "") in host
+ row["live"] = row["http"] == 200 and len(body) > LIVE_BODY_MIN and d.replace("www.", "") in host
row["gtm"] = bool(re.search(r"GTM-[A-Z0-9]{6,8}", body))
row["ga4"] = bool(re.search(r"G-[A-Z0-9]{10}\b", body)) or "gtag(" in body
row["meta"] = "fbq(" in body or "connect.facebook.net" in body
@@ -75,7 +86,7 @@ def probe(d):
doms = sorted(domains)
print(f"Probing {len(doms)} owned domains (parallel, $0 local)...\n")
-with ThreadPoolExecutor(max_workers=24) as ex:
+with ThreadPoolExecutor(max_workers=PROBE_WORKERS) as ex:
rows = list(ex.map(probe, doms))
live = [r for r in rows if r["live"]]
@@ -95,5 +106,6 @@ print(f"\n## {len(zero)} LIVE sites with ZERO tracking (top priority):")
print(" " + ", ".join(zero))
# persist
out = HERE / "gtm" / "coverage-matrix.json"
+out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(json.dumps(rows, indent=2))
print(f"\n(raw → {out})")
← 1ad6463 GA4 cleanup: deleted Momentum DW property; goodquestion.ai +
·
back to Ga Allsites
·
chore: lint autofixes (imports, re.IGNORECASE, unused import 3cdc431 →