← back to Ga Allsites
GA4: delete 5 redundant duplicate properties (soft-trash, recoverable ~7d) — reconcile after detector fix
293388c33a20753103f3b1cd3ab62c9a21d5fb7b · 2026-08-18 10:32:29 -0700 · Steve Abrams
Files touched
A scripts/delete_dup_properties.py
Diff
commit 293388c33a20753103f3b1cd3ab62c9a21d5fb7b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Aug 18 10:32:29 2026 -0700
GA4: delete 5 redundant duplicate properties (soft-trash, recoverable ~7d) — reconcile after detector fix
---
scripts/delete_dup_properties.py | 79 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/scripts/delete_dup_properties.py b/scripts/delete_dup_properties.py
new file mode 100644
index 0000000..82779ae
--- /dev/null
+++ b/scripts/delete_dup_properties.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+"""
+Delete the 5 REDUNDANT duplicate GA4 properties created 2026-08-18.
+
+Each of these 5 domains already had a live GA4 property (kept); this session minted a
+duplicate. We delete only the DUPLICATE measurement id's property. GA4 delete_property is
+a SOFT delete (moves to Trash, recoverable ~7 days), so this is reversible.
+
+Resolves measurement id -> property by listing properties under account 15714274 and each
+property's web data streams. Only deletes a property whose stream carries one of the DUP ids.
+"""
+from __future__ import annotations
+
+import sys
+from pathlib import Path
+
+SCRIPT_DIR = Path(__file__).parent
+SKILLS_DIR = Path.home() / ".claude" / "skills" / "analytics" / "scripts"
+sys.path.insert(0, str(SKILLS_DIR))
+
+from _auth import ensure_credentials # noqa: E402
+from google.analytics.admin import AnalyticsAdminServiceClient # noqa: E402
+
+ACCOUNT = "accounts/15714274"
+
+# domain -> the DUPLICATE (redundant) id to delete; the EXISTING id (kept) is in the comment.
+DUPS = {
+ "commercialdesignreps.com": "G-1C6HDZJT1T", # keep G-PRJ51PTW5G
+ "designerrepresentatives.com": "G-X4WY2B9Z27", # keep G-MVZFTCQY3X
+ "designtradelive.com": "G-LCM67ZD8PS", # keep G-E8R8V9RDXN
+ "wallsandfabrics.com": "G-7CTCV6VS2D", # keep G-429EVNMHVY
+ "iwascute.com": "G-3084642QM4", # keep G-2DHDBP8R78
+}
+TARGET_IDS = set(DUPS.values())
+
+
+def main() -> None:
+ apply = "--apply" in sys.argv
+ ensure_credentials()
+ client = AnalyticsAdminServiceClient()
+
+ # measurement_id -> (property_name, property_display_name)
+ mid_map: dict[str, tuple] = {}
+ for prop in client.list_properties(request={"filter": f"parent:{ACCOUNT}", "show_deleted": False}):
+ for ds in client.list_data_streams(request={"parent": prop.name}):
+ wsd = getattr(ds, "web_stream_data", None)
+ mid = getattr(wsd, "measurement_id", "") if wsd else ""
+ if mid:
+ mid_map[mid] = (prop.name, prop.display_name)
+
+ print(f"Account {ACCOUNT}: mapped {len(mid_map)} measurement ids to properties\n")
+ to_delete = []
+ for domain, dup in DUPS.items():
+ hit = mid_map.get(dup)
+ if hit:
+ print(f" {domain:32} dup {dup} -> {hit[0]} (display: {hit[1]})")
+ to_delete.append((domain, dup, hit[0]))
+ else:
+ print(f" {domain:32} dup {dup} -> NOT FOUND under this account (skip)")
+
+ if not to_delete:
+ print("\nNothing to delete.")
+ return
+
+ if not apply:
+ print(f"\nDRY RUN — {len(to_delete)} properties would be trashed. Re-run with --apply.")
+ return
+
+ print(f"\nDeleting (soft/trash) {len(to_delete)} duplicate properties …")
+ for domain, dup, name in to_delete:
+ try:
+ client.delete_property(request={"name": name})
+ print(f" ✓ trashed {name} ({domain} dup {dup})")
+ except Exception as exc:
+ print(f" ✗ FAILED {name}: {exc}")
+
+
+if __name__ == "__main__":
+ main()
← 44c3dc4 GA4 absence-detector: park-aware + local-repo-aware, strict
·
back to Ga Allsites
·
chore: ruff autofixes on GA4 detector/mint/delete scripts (s 5598972 →