[object Object]

← back to Ga4 Fleet

Add 19 new GA4 properties + harvest 8 existing IDs (TK-10204)

703dd10475d41bef9a340ed43239bf0ec2b56372 · 2026-08-04 14:26:48 -0700 · Steve Abrams

All 19 domains confirmed absent before creation (idempotency check).
Created under accounts/136095445, HOME_AND_GARDEN, America/Los_Angeles, USD.
8 harvest IDs pulled from live API listing.
Total: 86 domain->measurementId entries in measurement-ids.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files touched

Diff

commit 703dd10475d41bef9a340ed43239bf0ec2b56372
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Aug 4 14:26:48 2026 -0700

    Add 19 new GA4 properties + harvest 8 existing IDs (TK-10204)
    
    All 19 domains confirmed absent before creation (idempotency check).
    Created under accounts/136095445, HOME_AND_GARDEN, America/Los_Angeles, USD.
    8 harvest IDs pulled from live API listing.
    Total: 86 domain->measurementId entries in measurement-ids.json.
    
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---
 batch_create_19.py   | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++
 measurement-ids.json |  43 ++++++++++++++++----
 2 files changed, 144 insertions(+), 8 deletions(-)

diff --git a/batch_create_19.py b/batch_create_19.py
new file mode 100644
index 0000000..c7e90ff
--- /dev/null
+++ b/batch_create_19.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+"""Batch-create 19 GA4 properties under accounts/136095445.
+Idempotency: caller must pre-verify none exist (done by analytics agent).
+"""
+from __future__ import annotations
+import json
+import os
+import sys
+import time
+from pathlib import Path
+
+KEY_PATH = Path.home() / ".config" / "ga-analytics-agent" / "service-account.json"
+os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = str(KEY_PATH)
+
+ACCOUNT_ID = "accounts/136095445"
+
+DOMAINS = [
+    ("astek.designerwallcoverings.com",          "Astek DW"),
+    ("crcp.agentabrams.com",                     "CRCP"),
+    ("designersalesreps.com",                    "Designer Sales Reps"),
+    ("fallingstar.designerwallcoverings.com",    "Falling Star DW"),
+    ("grant.agentabrams.com",                    "Grant"),
+    ("homesonspec.com",                          "Homes On Spec"),
+    ("leads.venturaclaw.com",                    "Leads Ventura Claw"),
+    ("new.engine.designerwallcoverings.com",     "New Engine DW"),
+    ("pairs.designerwallcoverings.com",          "Pairs DW"),
+    ("patterndesignlab.com",                     "Pattern Design Lab"),
+    ("pitchguard.designerwallcoverings.com",     "Pitchguard DW"),
+    ("quadrille.designerwallcoverings.com",      "Quadrille DW"),
+    ("reidwitlin.designerwallcoverings.com",     "Reid Witlin DW"),
+    ("rentv.agentabrams.com",                    "RENTV"),
+    ("sixskills.agentabrams.com",                "Six Skills"),
+    ("sublease.agentabrams.com",                 "Sublease"),
+    ("textiletuesday.com",                       "Textile Tuesday"),
+    ("tools.designerwallcoverings.com",          "Tools DW"),
+    ("trending.designerwallcoverings.com",       "Trending DW"),
+]
+
+MEASUREMENT_IDS_PATH = Path("/Users/macstudio3/Projects/ga4-fleet/measurement-ids.json")
+
+
+def load_existing():
+    if MEASUREMENT_IDS_PATH.exists():
+        return json.loads(MEASUREMENT_IDS_PATH.read_text())
+    return {}
+
+
+def save_ids(ids: dict):
+    MEASUREMENT_IDS_PATH.write_text(json.dumps(ids, indent=2, sort_keys=True) + "\n")
+
+
+def main():
+    from google.analytics.admin import AnalyticsAdminServiceClient
+    from google.analytics.admin_v1alpha.types import Property, DataStream
+
+    client = AnalyticsAdminServiceClient()
+    results = []
+
+    existing_ids = load_existing()
+
+    for domain, display_name in DOMAINS:
+        if domain in existing_ids:
+            print(f"SKIP (already in JSON): {domain} -> {existing_ids[domain]}")
+            results.append((domain, existing_ids[domain], "ALREADY-IN-JSON"))
+            continue
+
+        print(f"Creating property for {domain} ...", flush=True)
+        try:
+            prop = Property(
+                parent=ACCOUNT_ID,
+                display_name=display_name,
+                time_zone="America/Los_Angeles",
+                currency_code="USD",
+                industry_category="HOME_AND_GARDEN",
+            )
+            created = client.create_property(property=prop)
+            prop_name = created.name
+
+            stream = DataStream(
+                type_=DataStream.DataStreamType.WEB_DATA_STREAM,
+                display_name=f"{display_name} Web",
+                web_stream_data=DataStream.WebStreamData(
+                    default_uri=f"https://{domain}",
+                ),
+            )
+            stream = client.create_data_stream(parent=prop_name, data_stream=stream)
+            measurement_id = stream.web_stream_data.measurement_id
+
+            print(f"  OK: {prop_name} -> {measurement_id}")
+            existing_ids[domain] = measurement_id
+            save_ids(existing_ids)
+            results.append((domain, measurement_id, "CREATED"))
+
+            # Small delay to be courteous to the API
+            time.sleep(0.5)
+
+        except Exception as e:
+            print(f"  ERROR: {e}")
+            results.append((domain, "ERROR", str(e)))
+
+    print("\n=== RESULTS ===")
+    for domain, mid, status in results:
+        print(f"{domain:<55} {mid:<20} {status}")
+
+    return results
+
+
+if __name__ == "__main__":
+    main()
diff --git a/measurement-ids.json b/measurement-ids.json
index 3c8fff2..1b7f1cb 100644
--- a/measurement-ids.json
+++ b/measurement-ids.json
@@ -1,6 +1,4 @@
 {
-  "interiordesignershowroom.com": "G-DH9G5HL7YJ",
-  "wallpapersback.com": "G-SS6HZVZE4H",
   "1890swallpaper.com": "G-EJG8QNBGLC",
   "1900swallpaper.com": "G-MXZXJ095DV",
   "1920swallpaper.com": "G-KBCHLWV7XZ",
@@ -12,50 +10,79 @@
   "agedwallpaper.com": "G-RWLYGLL8GE",
   "apartmentwallpaper.com": "G-KP5P2XHN8Y",
   "architecturalwallcoverings.com": "G-PN839G9FD8",
+  "astek.designerwallcoverings.com": "G-E4QVVZP23C",
   "bestwallpaperplace.com": "G-SSNGG2BQC3",
+  "bubbesblock.com": "G-DG1WN1HSHS",
+  "chinoiseriewallpaper.com": "G-J2NV5SCB3W",
   "contractwallpaper.com": "G-1VPJ5CRQX3",
   "corkwallcovering.com": "G-5YRWGWLMPT",
+  "crcp.agentabrams.com": "G-7R2X3B2V18",
+  "customdigitalmurals.com": "G-P6Z6JNS2MM",
+  "designersalesreps.com": "G-1NEJ4Q1X08",
   "dw.agentabrams.com": "G-53F1QBZSG0",
+  "fabricfriday.com": "G-L0S8Z1QV55",
   "fabricwallpaper.com": "G-YKX6TCF159",
+  "fallingstar.designerwallcoverings.com": "G-RTT4PDVSRC",
   "ffepurchasing.com": "G-WJ8QQQ1YEW",
   "glassbeadedwallpaper.com": "G-MFPLD6B0SR",
   "glitterwalls.com": "G-RK1X75MQ68",
   "goldleafwallpaper.com": "G-NP93HLD33N",
+  "grant.agentabrams.com": "G-7TFNM1DPJF",
+  "grassclothwallpaper.com": "G-2580K40HG4",
   "greenwallcoverings.com": "G-PXFNW86BJY",
   "handcraftedwallpaper.com": "G-VX7QFH0BB5",
   "healthcarewallpaper.com": "G-9ZL3DWRN8W",
   "hollywoodwallcoverings.com": "G-JBB1K6YNJ3",
+  "homesonspec.com": "G-ZGFNZ3RQ6S",
   "hospitalitydesignreps.com": "G-M79CJBLRFH",
   "hospitalitywallcoverings.com": "G-M95EMTVZ9T",
   "hospitalitywallpaper.com": "G-XM0936TL4N",
   "hotelwallcoverings.com": "G-XB60SLTE0B",
+  "interiordesignershowroom.com": "G-DH9G5HL7YJ",
+  "leads.venturaclaw.com": "G-E1T9LFN72Z",
   "linenwallpaper.com": "G-DKS5X482LQ",
   "madagascarwallpaper.com": "G-L17XK33LW0",
   "metallicwallpaper.com": "G-R82V9K1JL4",
   "micawallpaper.com": "G-2V0JCZXVVD",
+  "momentum.designerwallcoverings.com": "G-9K93LH6GH1",
   "museumwallpaper.com": "G-E6Y8PDCT60",
   "mylarwallpaper.com": "G-DX4F30FJQ6",
+  "naturaltextilewallpaper.com": "G-N663FGSP6M",
   "naturalwallcoverings.com": "G-FS7PV5RKHR",
+  "new.engine.designerwallcoverings.com": "G-3GH91C9B5T",
+  "pairs.designerwallcoverings.com": "G-2MSJ6WRK45",
   "pastelwallpaper.com": "G-2T3S64TW0Y",
+  "patterndesignlab.com": "G-0YXZBYXQ6R",
+  "philipperomano.com": "G-8WGHZ5FTV0",
   "photocapture.designerwallcoverings.com": "G-NP93HLD33N",
+  "pitchguard.designerwallcoverings.com": "G-27Y5BMH20B",
+  "quadrille.designerwallcoverings.com": "G-YLT07D5F0L",
   "raffiawallcoverings.com": "G-T1YJPBQ2XY",
+  "reidwitlin.designerwallcoverings.com": "G-PCWCG9XF2F",
+  "rentv.agentabrams.com": "G-JFNM7W38FL",
   "restaurantwallpaper.com": "G-GL80YLPJJ9",
   "restorationwallpaper.com": "G-1MKHDYFPWR",
   "saloonwallpaper.com": "G-5QPBHCGK8M",
   "silkwallcoverings.com": "G-NMVC4V48LE",
   "silkwallpaper.com": "G-CNTJNLTEW8",
   "silverleafwallpaper.com": "G-1V8HW7Q3BF",
+  "sixskills.agentabrams.com": "G-M3C61TTLNE",
   "starsofdesign.com": "G-YCT0F2Q692",
+  "sublease.agentabrams.com": "G-9ZBC0J2M9S",
   "suedewallpaper.com": "G-0EGN8D3NG5",
+  "textiletuesday.com": "G-P5ZKK7G6GF",
   "textilewallpaper.com": "G-KG2EY6R7DW",
+  "tools.designerwallcoverings.com": "G-ZBBGQK49LS",
+  "trending.designerwallcoverings.com": "G-SDQHZRV7S1",
   "vinylwallpaper.com": "G-22J410QW7S",
   "wallpapercanada.com": "G-EBXJH28088",
   "wallpapercontractor.com": "G-LC83F70YHV",
+  "wallpaperdefinitions.com": "G-NEXET3M920",
+  "wallpaperdictionary.com": "G-W1CY3DRMF8",
   "wallpaperdistributors.com": "G-NBZ5WTBW8F",
   "wallpaperestimator.com": "G-T3TWEXYWQX",
-  "philipperomano.com": "G-8WGHZ5FTV0",
-  "grassclothwallpaper.com": "G-2580K40HG4",
-  "chinoiseriewallpaper.com": "G-J2NV5SCB3W",
-  "customdigitalmurals.com": "G-P6Z6JNS2MM",
-  "momentum.designerwallcoverings.com": "G-9K93LH6GH1"
-}
\ No newline at end of file
+  "wallpaperglossary.com": "G-TZ311J5HJL",
+  "wallpaperhistory.com": "G-84JNTME53X",
+  "wallpapersback.com": "G-SS6HZVZE4H",
+  "wallpaperwednesday.com": "G-ZDKW8DQS5X"
+}

← 40d1be6 GA4: momentum.designerwallcoverings.com G-9K93LH6GH1  ·  back to Ga4 Fleet  ·  retire rentv-website: drop stale domain reference (TK-10123, be66a40 →