@analitikisler/ai-tag-debugger 0.22.6 → 0.22.7

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.22.7 (2026-11-04)
4
+
5
+ - Audits can run in your own Google Chrome. Start Chrome with a debugging port and a profile folder for audits (README: Using your own Chrome), then add `--connect http://127.0.0.1:9222` to `aitd run` or `aitd plan`, or set `connect` in the config or on a local MCP server's `start_audit`. Each journey gets a fresh private window in that Chrome, as clean as the tool's own browser, which closes when the journey ends while Chrome keeps running. Capture, the answered tracking requests, the host limits and logins work as usual. Only a Chrome on the same computer is accepted, an HTTP MCP server never connects to one, and when no Chrome answers, the message gives the command that starts it.
6
+
3
7
  ## 0.22.6 (2026-11-04)
4
8
 
5
9
  - Journeys can log in. Set a test account in `AITD_LOGIN_EMAIL` (or `AITD_LOGIN_USERNAME`) and `AITD_LOGIN_PASSWORD`: the model fills login forms with the placeholders `{{login.email}}`, `{{login.username}}` and `{{login.password}}`, and the browser types the real values, only into the audited site's pages, never into a frame from another site. The values are turned back into their placeholders in everything the tool keeps or shows (page views, steps, hits, dataLayer pushes, network calls, saved steps and reports), a password field's value is never read into the page view, and the browser doesn't get them in its environment. Over MCP, `start_audit` says whether a test account is set up.
package/README.md CHANGED
@@ -421,6 +421,21 @@ The model never sees them. It fills login forms with the placeholders `{{login.e
421
421
 
422
422
  **A saved session**, for a login that needs a person: a CAPTCHA, a code sent to a phone, or single sign-on. `aitd login --site https://yourshop.com` opens the site in a browser window; log in by hand, press Enter in the terminal, and the session (cookies and storage) is saved to `aitd/<domain>/session.json`, readable only by you. `aitd run … --session saved`, the config's `session_file`, or `session: "saved"` on a local MCP server's `start_audit` start every journey logged in. The file holds a live login: keep it private, and save it again when the login expires.
423
423
 
424
+ ### Using your own Chrome
425
+
426
+ Audits normally run in the tool's own Chromium. To watch them in your own Google Chrome instead, on your computer's own network, start Chrome with a debugging port and a profile folder for audits (Chrome refuses remote debugging on your everyday profile, and a folder of its own keeps audits away from it):
427
+
428
+ ```bash
429
+ # macOS
430
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir="$HOME/aitd-chrome"
431
+ # Windows
432
+ "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%USERPROFILE%\aitd-chrome"
433
+ # Linux
434
+ google-chrome --remote-debugging-port=9222 --user-data-dir="$HOME/aitd-chrome"
435
+ ```
436
+
437
+ Then add `--connect http://127.0.0.1:9222` to `aitd run` or `aitd plan` (or `connect` in the config, or `connect` on a local MCP server's `start_audit`). Each journey opens a fresh private window in that Chrome, as clean as the tool's own browser, so every audit is a first visit with no cookies or consent choice left over; the window closes when the journey ends, and Chrome keeps running. Everything else works as usual: tracking requests are answered inside the browser, the site's host limits apply, and a [test account or saved session](#logging-in) logs in. Only a Chrome on the same computer (`127.0.0.1` or `localhost`) is accepted, and an HTTP MCP server never connects to one.
438
+
424
439
  Not sure what to test? `aitd plan --site https://yoursite.com` drafts a measurement plan, and `--against latest` checks the site against it.
425
440
 
426
441
  ### Keeping API usage down
@@ -515,6 +530,7 @@ The file holds one entry per finding, with a `key` the run matches on (the check
515
530
  | `journeys[].steps` | Optional fixed steps for `--scripted` runs: `{ "action": "click", "selector": "#add-to-cart" }`. Without them, `--scripted` repeats the steps of the site's last completed run of the journey. |
516
531
  | `allowed_hosts` | Other hosts journeys may visit, e.g. `["checkout.payments-provider.com"]` for a hosted checkout. The browser otherwise stays on the `site` host and its subdomains. Same as `--allow-host`. |
517
532
  | `session_file` | A session saved with `aitd login`, so every journey starts logged in: `"saved"` for the site's own, or a file path. See [Logging in](#logging-in). |
533
+ | `connect` | Your own Chrome's debugging address, e.g. `http://127.0.0.1:9222`: each journey runs in a fresh window of it. See [Using your own Chrome](#using-your-own-chrome). |
518
534
  | `providers` | Tracking platforms to check, e.g. `["ga4", "meta"]`. Default `["ga4", "google_ads", "meta", "tiktok"]`, plus any other platform the site sends to while this is unset. Same as `--platforms`. |
519
535
  | `campaign_checks` | Default `true`. Each run opens the first page like an ad click (UTM parameters, `gclid`, `fbclid`, or the ones already in the start address) and checks they survive redirects and reach the hits. Set to `false` to open the plain address. |
520
536
  | `block_hits` | Default `true`. Set to `false` to let hits reach your real endpoints. |
@@ -569,7 +585,7 @@ aitd run --site <url> (--against <plan> | --journey <id> | --goal "<text>") [--c
569
585
  [--max-steps <n>] [--viewport desktop|mobile] [--concurrency <n>] [--platforms <list>] [--data-dir <dir>]
570
586
  [--provider anthropic|openai|gemini|openai-compatible] [--model <id>] [--lang en|tr] [--headed]
571
587
  [--fail-on broken|risk|warning|never] [--baseline <file>] [--update-baseline]
572
- [--scripted] [--no-ai] [--save-site <dir>] [--save-steps <file>] [--session saved|<file>]
588
+ [--scripted] [--no-ai] [--save-site <dir>] [--save-steps <file>] [--session saved|<file>] [--connect <url>]
573
589
  aitd replay <dir>... [--update] [--out <dir>]
574
590
  aitd mcp [--http] [--port <n>] [--host <addr>] [--token <secret>] [--public-url <https url>] [--reports <dir>]
575
591
  [--allow-private-network] [--allow-live]
@@ -614,6 +630,7 @@ aitd history --site <url> [--limit <n>] [--json] [--lang en|tr] [--data-dir <dir
614
630
  | `--allow-host <host>` | run | Another host journeys may visit (repeatable). Same as `allowed_hosts`. |
615
631
  | `--session saved\|<file>` | run | Start every journey logged in, from the session `aitd login` saved (`saved`) or a session file. Same as `session_file`. See [Logging in](#logging-in). |
616
632
  | `--save <file>` | login | Where `aitd login` saves the session (default `aitd/<domain>/session.json`). |
633
+ | `--connect <url>` | run, plan | Run in your own Chrome, started with a debugging port, e.g. `http://127.0.0.1:9222`. Same as `connect`. See [Using your own Chrome](#using-your-own-chrome). |
617
634
  | `--keep-bodies` | run | Store tracking requests as sent, without redacting user data. |
618
635
  | `--no-branding` | plan, run | Leave the logo and credit line out of the reports and `plan.html`. |
619
636
  | `--http`, `--port`, `--host`, `--token`, `--public-url`, `--reports`, `--allow-private-network`, `--allow-live` | mcp | See the MCP section below. |
@@ -683,7 +700,7 @@ Tools the server offers:
683
700
  |---|---|
684
701
  | `make_plan` | Drafts a tracking plan for a site (what should be tracked), the same as `aitd plan --site`. Pass `topic` (`custom-events`, `ecommerce`, `forms`, `consent`) to limit it to one kind of event. The plan is saved and its ID can be given as `against` to `finish_audit`. It uses the AI provider configured on the computer that runs the server and takes a few minutes. |
685
702
  | `what_changed` | Returns only the "since last run" diff for a site: the problems fixed and the new ones in its newest saved run (`aitd run`) compared with the run before. No browser and no AI. Pass `language` for a Turkish answer. |
686
- | `start_audit` | Opens a fresh browser on a URL and starts recording all tracking. Pass a ready-made journey (`purchase`, `sign_up`, …) to get its goal and expected events, and `providers` to choose the platforms to check. The assistant asks you which platforms to check first. `live: true` lets the tracking requests through to the site's real accounts, to check them in GA4 Realtime or DebugView, Meta Events Manager or Tag Assistant; the test traffic then shows in the site's reports, and the results and the report say the run was live. Over HTTP the server needs `--allow-live` for it. The first page opens the way an ad click does, with test campaign parameters (`utm_source=aitd`, `gclid=aitd-gclid`, `fbclid=aitd-fbclid`, …), so `finish_audit` checks that they survive redirects and reach the hits; `campaign: false` opens the URL as given, and `campaign: {"utm_source": "newsletter", "gclid": "test123"}` uses your own values. A test account set on the server's computer is used through its placeholders, and `session: "saved"` starts from the session `aitd login` saved (local servers only); see [Logging in](#logging-in). |
703
+ | `start_audit` | Opens a fresh browser on a URL and starts recording all tracking. Pass a ready-made journey (`purchase`, `sign_up`, …) to get its goal and expected events, and `providers` to choose the platforms to check. The assistant asks you which platforms to check first. `live: true` lets the tracking requests through to the site's real accounts, to check them in GA4 Realtime or DebugView, Meta Events Manager or Tag Assistant; the test traffic then shows in the site's reports, and the results and the report say the run was live. Over HTTP the server needs `--allow-live` for it. The first page opens the way an ad click does, with test campaign parameters (`utm_source=aitd`, `gclid=aitd-gclid`, `fbclid=aitd-fbclid`, …), so `finish_audit` checks that they survive redirects and reach the hits; `campaign: false` opens the URL as given, and `campaign: {"utm_source": "newsletter", "gclid": "test123"}` uses your own values. A test account set on the server's computer is used through its placeholders, and `session: "saved"` starts from the session `aitd login` saved (local servers only); see [Logging in](#logging-in). `connect` runs it in a fresh window of your own Chrome (local servers only; see [Using your own Chrome](#using-your-own-chrome)). |
687
704
  | `browser_action` | One click, fill, select, goto, scroll or wait. Returns the step number, the page and the tracking hits that step sent, each with an `[h]` number, its consent (from `gcs`, and `gcd` for `ad_user_data` and `ad_personalization`) and the ids and flags GA4 sends with it (`cid`, `sid`, `gcs`, `gcd`, `_fv`, `_ss`, `_nsi`, …), its dataLayer pushes (Consent Mode commands in full as `key=value`, page addresses never cut) and the calls it read no event from, such as Consent Mode pings with their `gcs`, `gcd` and click ids (`gclid`, `gclid=0 (redacted)` when ads data redaction blanks it, `gclaw` from `_gcl_aw`), and the cookies the step added, changed or removed, by name, with the GA4 client id and whether `_gcl_aw` and `_fbc` hold the landing click ids when that changes. A page_view that arrives during a later wait or scroll is listed on the step that loaded its page, marked late. The page view is compact by default, since long sessions lose their oldest results: up to 40 elements above or below the screen, and the page text or element list replaced by a note when they haven't changed since the last view. Pass `detail: "full"` for everything. |
688
705
  | `get_page` | Shows the current page, in full: every element and the whole page text. |
689
706
  | `get_hit` | Shows one hit in full, by its `step` and `[h]` number: every parameter its request carried, its place in a batched request, where it was sent, and `gcd` decoded per consent signal (default and update). |
package/README.tr.md CHANGED
@@ -421,6 +421,21 @@ Model bunları hiç görmez. Giriş formlarını `{{login.email}}`, `{{login.use
421
421
 
422
422
  **Kaydedilmiş bir oturum**, bir insan gerektiren girişler için: bir CAPTCHA, telefona gelen bir kod ya da tek oturum açma (SSO). `aitd login --site https://magazaniz.com` siteyi bir tarayıcı penceresinde açar; elle giriş yapın, terminalde Enter'a basın; oturum (çerezler ve depolama) yalnızca sizin okuyabileceğiniz `aitd/<alan-adı>/session.json` dosyasına kaydedilir. `aitd run … --session saved`, yapılandırmadaki `session_file` ya da yerel bir MCP sunucusunda `start_audit` için `session: "saved"` her yolculuğu giriş yapılmış olarak başlatır. Dosya canlı bir oturum tutar: gizli tutun ve oturum sona erdiğinde yeniden kaydedin.
423
423
 
424
+ ### Kendi Chrome'unuzu kullanmak
425
+
426
+ Denetimler normalde aracın kendi Chromium'unda çalışır. Bunun yerine onları kendi Google Chrome'unuzda, bilgisayarınızın kendi ağında izlemek için Chrome'u bir hata ayıklama bağlantı noktası ve denetimlere ayrılmış bir profil klasörüyle başlatın (Chrome günlük profilinizde uzaktan hata ayıklamaya izin vermez; ayrı bir klasör de denetimleri ondan uzak tutar):
427
+
428
+ ```bash
429
+ # macOS
430
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir="$HOME/aitd-chrome"
431
+ # Windows
432
+ "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%USERPROFILE%\aitd-chrome"
433
+ # Linux
434
+ google-chrome --remote-debugging-port=9222 --user-data-dir="$HOME/aitd-chrome"
435
+ ```
436
+
437
+ Ardından `aitd run` ya da `aitd plan` komutuna `--connect http://127.0.0.1:9222` ekleyin (ya da yapılandırmada `connect`, yerel bir MCP sunucusunda `start_audit` için `connect`). Her yolculuk o Chrome'da aracın kendi tarayıcısı kadar temiz, yeni bir gizli pencere açar; böylece her denetim, kalan çerez ya da onay seçimi olmayan bir ilk ziyarettir. Yolculuk bitince pencere kapanır, Chrome çalışmaya devam eder. Geri kalan her şey her zamanki gibi çalışır: takip istekleri tarayıcının içinde yanıtlanır, sitenin ana makine sınırları geçerlidir ve bir [test hesabı ya da kaydedilmiş oturum](#giriş-yapmak) giriş yapar. Yalnızca aynı bilgisayardaki bir Chrome (`127.0.0.1` ya da `localhost`) kabul edilir ve bir HTTP MCP sunucusu hiçbir zaman ona bağlanmaz.
438
+
424
439
  Ne test edeceğinizden emin değil misiniz? `aitd plan --site https://yoursite.com` bir ölçümleme planı taslağı çıkarır, `--against latest` de siteyi buna göre kontrol eder.
425
440
 
426
441
  ### API kullanımını düşük tutmak
@@ -515,6 +530,7 @@ Dosyada her bulgu için bir kayıt bulunur: çalıştırmanın eşleştirme yapt
515
530
  | `journeys[].steps` | `--scripted` çalıştırmaları için isteğe bağlı sabit adımlar: `{ "action": "click", "selector": "#add-to-cart" }`. Bunlar yoksa `--scripted`, sitenin o yolculuğu son tamamlayan çalıştırmasının adımlarını tekrarlar. |
516
531
  | `allowed_hosts` | Yolculukların ziyaret edebileceği başka ana makineler, örneğin barındırılan bir ödeme için `["checkout.payments-provider.com"]`. Tarayıcı aksi halde `site` ana makinesinde ve alt alan adlarında kalır. `--allow-host` ile aynıdır. |
517
532
  | `session_file` | `aitd login` ile kaydedilmiş bir oturum; her yolculuk giriş yapılmış olarak başlar: sitenin kendi oturumu için `"saved"` ya da bir dosya yolu. Bkz. [Giriş yapmak](#giriş-yapmak). |
533
+ | `connect` | Kendi Chrome'unuzun hata ayıklama adresi, örneğin `http://127.0.0.1:9222`: her yolculuk onun yeni bir penceresinde çalışır. Bkz. [Kendi Chrome'unuzu kullanmak](#kendi-chromeunuzu-kullanmak). |
518
534
  | `providers` | Kontrol edilecek takip platformları, örneğin `["ga4", "meta"]`. Varsayılan `["ga4", "google_ads", "meta", "tiktok"]`; bu ayar boşken sitenin gönderdiği diğer platformlar da eklenir. `--platforms` ile aynıdır. |
519
535
  | `campaign_checks` | Varsayılan `true`. Her çalıştırma ilk sayfayı bir reklam tıklaması gibi açar (UTM parametreleri, `gclid`, `fbclid` ya da başlangıç adresinde zaten olanlar) ve bunların yönlendirmelerden geçip isteklere ulaştığını denetler. Düz adresi açmak için `false` yapın. |
520
536
  | `block_hits` | Varsayılan `true`. Takip isteklerinin gerçek uç noktalarınıza ulaşmasına izin vermek için `false` yapın. |
@@ -569,7 +585,7 @@ aitd run --site <url> (--against <plan> | --journey <id> | --goal "<metin>") [--
569
585
  [--max-steps <n>] [--viewport desktop|mobile] [--concurrency <n>] [--platforms <liste>] [--data-dir <dir>]
570
586
  [--provider anthropic|openai|gemini|openai-compatible] [--model <id>] [--lang en|tr] [--headed]
571
587
  [--fail-on broken|risk|warning|never] [--baseline <dosya>] [--update-baseline]
572
- [--scripted] [--no-ai] [--save-site <dir>] [--save-steps <dosya>] [--session saved|<dosya>]
588
+ [--scripted] [--no-ai] [--save-site <dir>] [--save-steps <dosya>] [--session saved|<dosya>] [--connect <url>]
573
589
  aitd replay <dir>... [--update] [--out <dir>]
574
590
  aitd mcp [--http] [--port <n>] [--host <adres>] [--token <gizli>] [--public-url <https url>] [--reports <dir>]
575
591
  [--allow-private-network] [--allow-live]
@@ -614,6 +630,7 @@ aitd history --site <url> [--limit <n>] [--json] [--lang en|tr] [--data-dir <dir
614
630
  | `--allow-host <ana makine>` | run | Yolculukların ziyaret edebileceği başka bir ana makine (tekrarlanabilir). `allowed_hosts` ile aynıdır. |
615
631
  | `--session saved\|<dosya>` | run | Her yolculuğu, `aitd login`'in kaydettiği oturumdan (`saved`) ya da bir oturum dosyasından giriş yapılmış olarak başlatır. `session_file` ile aynı. Bkz. [Giriş yapmak](#giriş-yapmak). |
616
632
  | `--save <dosya>` | login | `aitd login`'in oturumu nereye kaydedeceği (varsayılan `aitd/<alan-adı>/session.json`). |
633
+ | `--connect <url>` | run, plan | Bir hata ayıklama bağlantı noktasıyla başlatılmış kendi Chrome'unuzda çalıştırır, örneğin `http://127.0.0.1:9222`. `connect` ile aynı. Bkz. [Kendi Chrome'unuzu kullanmak](#kendi-chromeunuzu-kullanmak). |
617
634
  | `--keep-bodies` | run | Takip isteklerini gönderildiği gibi, kullanıcı verisi gizlenmeden sakla. |
618
635
  | `--no-branding` | plan, run | Logo ve kredi satırını raporlardan ve `plan.html` dosyasından çıkar. |
619
636
  | `--http`, `--port`, `--host`, `--token`, `--public-url`, `--reports`, `--allow-private-network`, `--allow-live` | mcp | Aşağıdaki MCP bölümüne bakın. |
@@ -683,7 +700,7 @@ Sunucunun sunduğu araçlar:
683
700
  |---|---|
684
701
  | `make_plan` | Bir site için takip planı çıkarır (neyin takip edilmesi gerektiği), `aitd plan --site` ile aynıdır. Yalnızca bir tür event için sınırlamak üzere `topic` verin (`custom-events`, `ecommerce`, `forms`, `consent`). Plan kaydedilir ve kimliği `finish_audit` için `against` olarak verilebilir. Sunucuyu çalıştıran bilgisayarda ayarlı yapay zekâ sağlayıcısını kullanır ve birkaç dakika sürer. |
685
702
  | `what_changed` | Bir site için yalnızca "son çalıştırmadan bu yana" farkını döndürür: kayıtlı son çalıştırmanın (`aitd run`) bir öncekine göre düzelen ve yeni sorunları. Tarayıcı ve yapay zekâ kullanmaz. Türkçe yanıt için `language` verin. |
686
- | `start_audit` | Bir URL'de yeni bir tarayıcı açar ve tüm takibi kaydetmeye başlar. Hedefini ve beklenen event'lerini almak için hazır bir yolculuk (`purchase`, `sign_up`, …) verin; kontrol edilecek platformları seçmek için `providers` verin. Asistan önce hangi platformların kontrol edileceğini size sorar. `live: true`, takip isteklerini sitenin gerçek hesaplarına geçirir; böylece GA4 Realtime ya da DebugView, Meta Events Manager veya Tag Assistant'ta kontrol edilebilirler. Test trafiği o zaman sitenin raporlarında görünür; sonuçlar ve rapor çalıştırmanın canlı olduğunu söyler. HTTP üzerinden sunucunun bunun için `--allow-live` ile başlatılması gerekir. İlk sayfa bir reklam tıklaması gibi, test kampanya parametreleriyle (`utm_source=aitd`, `gclid=aitd-gclid`, `fbclid=aitd-fbclid`, …) açılır; böylece `finish_audit` bunların yönlendirmelerden sağ çıkıp isteklere ulaştığını kontrol eder. `campaign: false` URL'yi olduğu gibi açar, `campaign: {"utm_source": "newsletter", "gclid": "test123"}` ise sizin değerlerinizi kullanır. Sunucunun bilgisayarında ayarlı bir test hesabı yer tutucularıyla kullanılır; `session: "saved"` ise `aitd login`'in kaydettiği oturumdan başlar (yalnızca yerel sunucular); bkz. [Giriş yapmak](#giriş-yapmak). |
703
+ | `start_audit` | Bir URL'de yeni bir tarayıcı açar ve tüm takibi kaydetmeye başlar. Hedefini ve beklenen event'lerini almak için hazır bir yolculuk (`purchase`, `sign_up`, …) verin; kontrol edilecek platformları seçmek için `providers` verin. Asistan önce hangi platformların kontrol edileceğini size sorar. `live: true`, takip isteklerini sitenin gerçek hesaplarına geçirir; böylece GA4 Realtime ya da DebugView, Meta Events Manager veya Tag Assistant'ta kontrol edilebilirler. Test trafiği o zaman sitenin raporlarında görünür; sonuçlar ve rapor çalıştırmanın canlı olduğunu söyler. HTTP üzerinden sunucunun bunun için `--allow-live` ile başlatılması gerekir. İlk sayfa bir reklam tıklaması gibi, test kampanya parametreleriyle (`utm_source=aitd`, `gclid=aitd-gclid`, `fbclid=aitd-fbclid`, …) açılır; böylece `finish_audit` bunların yönlendirmelerden sağ çıkıp isteklere ulaştığını kontrol eder. `campaign: false` URL'yi olduğu gibi açar, `campaign: {"utm_source": "newsletter", "gclid": "test123"}` ise sizin değerlerinizi kullanır. Sunucunun bilgisayarında ayarlı bir test hesabı yer tutucularıyla kullanılır; `session: "saved"` ise `aitd login`'in kaydettiği oturumdan başlar (yalnızca yerel sunucular); bkz. [Giriş yapmak](#giriş-yapmak). `connect` onu kendi Chrome'unuzun yeni bir penceresinde çalıştırır (yalnızca yerel sunucular; bkz. [Kendi Chrome'unuzu kullanmak](#kendi-chromeunuzu-kullanmak)). |
687
704
  | `browser_action` | Tek bir tıklama, doldurma, seçme, gitme, kaydırma ya da bekleme. Adım numarasını, sayfayı, o adımın gönderdiği takip isteklerini (her biri bir `[h]` numarası, onay durumu — `gcs`'den, `ad_user_data` ve `ad_personalization` için `gcd`'den — ve GA4'ün onunla gönderdiği kimlik ve işaretlerle: `cid`, `sid`, `gcs`, `gcd`, `_fv`, `_ss`, `_nsi`, …), dataLayer push'larını (Consent Mode komutları `anahtar=değer` olarak eksiksiz, sayfa adresleri hiç kesilmeden) ve event olarak okunmayan çağrıları (ör. `gcs`, `gcd` ve tıklama kimlikleriyle Consent Mode ping'leri: `gclid`, reklam verisi karartma açıksa `gclid=0 (redacted)`, `_gcl_aw`'dan `gclaw`), ayrıca adımın eklediği, değiştirdiği ya da sildiği çerezleri adlarıyla, değiştiğinde de GA4 istemci kimliğini ve `_gcl_aw` ile `_fbc`'nin açılış tıklama kimliklerini tutup tutmadığını döndürür. Sonraki bir bekleme ya da kaydırma sırasında gelen page_view, sayfasını yükleyen adımda gecikmeli olarak işaretlenip gösterilir. Uzun oturumlar en eski sonuçlarını kaybettiği için sayfa görünümü varsayılan olarak kısadır: ekranın üstünde ya da altında en fazla 40 öğe; sayfa metni ya da öğe listesi son görünümden beri değişmediyse yerine bir not. Hepsi için `detail: "full"` verin. |
688
705
  | `get_page` | Geçerli sayfayı eksiksiz gösterir: her öğe ve sayfanın tüm metni. |
689
706
  | `get_hit` | Bir isteği `step` ve `[h]` numarasıyla eksiksiz gösterir: isteğin taşıdığı her parametre, toplu bir istekteki sırası, nereye gönderildiği ve her onay sinyali için çözümlenmiş `gcd` (varsayılan ve güncelleme). |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@analitikisler/ai-tag-debugger",
3
3
  "mcpName": "io.github.analitikisler/ai-tag-debugger",
4
- "version": "0.22.6",
4
+ "version": "0.22.7",
5
5
  "description": "Open-source AI agent that QA-tests your website's analytics, ad and consent tracking (GA4, GTM, Google Ads, Meta, TikTok). Bring your own model (Claude, OpenAI, Gemini) or use it from your chat app over MCP.",
6
6
  "type": "module",
7
7
  "bin": {
package/src/agent.js CHANGED
@@ -205,7 +205,7 @@ export const harName = (journeyId, viewport) => `${String(journeyId).replace(/[^
205
205
  export async function runJourney(config, journey, viewport, opts = {}) {
206
206
  const har = (dir) => (dir ? path.join(dir, harName(journey.id, viewport)) : undefined);
207
207
  const session = new AuditSession({
208
- viewport, site: config.site, allowedHosts: config.allowed_hosts, storageState: config.session_file, providers: config.providers, detect: config.detect_providers, keepBodies: config.keep_bodies === true,
208
+ viewport, site: config.site, allowedHosts: config.allowed_hosts, storageState: config.session_file, connect: config.connect, providers: config.providers, detect: config.detect_providers, keepBodies: config.keep_bodies === true,
209
209
  blockHits: config.block_hits !== false, headless: !opts.headed, recordHar: har(opts.saveSite), replayHar: har(opts.replaySite), log: opts.log,
210
210
  });
211
211
  try {
package/src/browser.js CHANGED
@@ -53,6 +53,36 @@ export const VIEWPORTS = {
53
53
  // Runs in the page before any site script: reports every dataLayer push
54
54
  // (including gtag consent commands) to Node through an exposed binding, so the
55
55
  // log survives page navigations.
56
+ // How to start Chrome for --connect, per system: a debugging port, and a profile folder of its own, which Chrome
57
+ // requires for remote debugging and which keeps the audits away from the everyday profile.
58
+ export const CHROME_START = {
59
+ darwin: `"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir="$HOME/aitd-chrome"`,
60
+ win32: `"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%USERPROFILE%\\aitd-chrome"`,
61
+ linux: `google-chrome --remote-debugging-port=9222 --user-data-dir="$HOME/aitd-chrome"`,
62
+ };
63
+
64
+ /**
65
+ * Connects to a Chrome the user started with a debugging port. Only a Chrome on this computer: the address must be
66
+ * a loopback one, so a config or a chat can't point the tool at someone else's browser.
67
+ */
68
+ export async function connectToChrome(endpoint, { connect = (url) => chromium.connectOverCDP(url, { timeout: 10_000 }), platform = process.platform } = {}) {
69
+ let u;
70
+ try {
71
+ u = new URL(String(endpoint));
72
+ } catch {
73
+ throw new Error(`"${endpoint}" is not an address. Use the debugging address Chrome was started with, e.g. http://127.0.0.1:9222`);
74
+ }
75
+ if (!["http:", "https:", "ws:", "wss:"].includes(u.protocol) || !["127.0.0.1", "localhost", "[::1]", "::1"].includes(u.hostname)) {
76
+ throw new Error(`Only a Chrome on this computer can be connected to (127.0.0.1 or localhost), not ${u.host}.`);
77
+ }
78
+ try {
79
+ return await connect(u.href);
80
+ } catch (err) {
81
+ if (!/ECONNREFUSED|ECONNRESET|socket hang up|404|retrieving websocket url/i.test(String(err?.message))) throw err;
82
+ throw new Error(`No Chrome answers at ${u.href}. Start Chrome with a debugging port and a profile folder for audits, then try again:\n ${CHROME_START[platform] ?? CHROME_START.linux}`);
83
+ }
84
+ }
85
+
56
86
  /** A page address without its hash, for matching page_location to navigations. */
57
87
  const pageKey = (url) => String(url ?? "").split("#")[0];
58
88
  /** The host of a URL, or null. */
@@ -623,6 +653,18 @@ export class AuditSession {
623
653
  if (this.opts.storageState && !existsSync(this.opts.storageState)) throw new Error(`No saved login session at ${this.opts.storageState}. Save one with: aitd login --site <url>`);
624
654
  const device = VIEWPORTS[this.opts.viewport];
625
655
  if (!device) throw new Error(`Unknown viewport "${this.opts.viewport}". Use: ${Object.keys(VIEWPORTS).join(", ")}`);
656
+ if (this.opts.connect) {
657
+ // The user's own Chrome: only the browser is theirs. The audit gets a fresh private window (a new context) in
658
+ // it, exactly as clean as a launched browser, and close() closes that window and disconnects, leaving Chrome.
659
+ if (this.opts.blockPrivate) throw new Error("Connecting to your own Chrome works only from the CLI or a local MCP server, not over HTTP.");
660
+ if (this.opts.replayHar) throw new Error("A saved site replays in the tool's own browser; leave --connect out.");
661
+ this.browser = await connectToChrome(this.opts.connect);
662
+ } else await this.launchBrowser();
663
+ await this.setUpContext(device);
664
+ }
665
+
666
+ /** Launches the tool's own Chromium, through the egress proxy when private addresses are blocked. */
667
+ async launchBrowser() {
626
668
  const launch = { headless: this.opts.headless, env: browserEnv() };
627
669
  if (this.opts.blockPrivate) {
628
670
  // Every connection, WebSockets included, goes to an address the proxy checked.
@@ -643,6 +685,10 @@ export class AuditSession {
643
685
  await installBrowser();
644
686
  this.browser = await chromium.launch(launch);
645
687
  }
688
+ }
689
+
690
+ /** The audit's own context (fresh cookies and storage, or a saved session) with the capture hooks and routes. */
691
+ async setUpContext(device) {
646
692
  const record = this.opts.recordHar ? { recordHar: { path: this.opts.recordHar, mode: "minimal" } } : {};
647
693
  // A session saved with `aitd login`: the browser starts logged in, for sites whose login needs a person.
648
694
  const session = this.opts.storageState ? { storageState: this.opts.storageState } : {};
package/src/cli.js CHANGED
@@ -71,6 +71,7 @@ async function main(args = process.argv.slice(2)) {
71
71
  providers: { type: "string", multiple: true },
72
72
  "allow-host": { type: "string", multiple: true },
73
73
  session: { type: "string" },
74
+ connect: { type: "string" },
74
75
  save: { type: "string" },
75
76
  "allow-private-network": { type: "boolean", default: false },
76
77
  "allow-live": { type: "boolean", default: false },
@@ -177,7 +178,7 @@ async function main(args = process.argv.slice(2)) {
177
178
  const { discoverPlan } = await import("./discover.js");
178
179
  const provider = await createProvider({ name: values.provider, model: values.model, baseUrl: values["base-url"] });
179
180
  console.log(`Exploring ${values.site} to draft its measurement plan…`);
180
- const { plan } = await discoverPlan({ site: values.site, topic: values.topic, provider, maxSteps, headed: values.headed, allowedHosts: values["allow-host"], log: console.log });
181
+ const { plan } = await discoverPlan({ site: values.site, topic: values.topic, provider, maxSteps, headed: values.headed, allowedHosts: values["allow-host"], connect: values.connect, log: console.log });
181
182
  const { id, dir } = await savePlan(plan, { dataDir, site: values.site, branding: !values["no-branding"] });
182
183
  const custom = plan.events.filter((e) => e.custom).length;
183
184
  const rel = path.relative(process.cwd(), dir);
@@ -236,6 +237,8 @@ async function main(args = process.argv.slice(2)) {
236
237
  }
237
238
  if (values["keep-bodies"]) loaded.config = { ...loaded.config, keep_bodies: true };
238
239
  if (values["allow-host"]?.length) loaded.config = { ...loaded.config, allowed_hosts: [...(loaded.config.allowed_hosts ?? []), ...values["allow-host"]] };
240
+ // Your own Chrome, started with a debugging port: every journey runs in a fresh window of it.
241
+ if (values.connect) loaded.config = { ...loaded.config, connect: values.connect };
239
242
  // A session saved with `aitd login` ("saved") or a file: every journey starts logged in.
240
243
  const sessionArg = values.session ?? loaded.config.session_file;
241
244
  if (sessionArg) loaded.config = { ...loaded.config, session_file: resolveSessionFile(sessionArg, { site: loaded.config.site, dataDir: values["data-dir"] ?? DEFAULT_DATA_DIR }) };
package/src/consent.js CHANGED
@@ -184,7 +184,7 @@ export function scenarioLanding(config, campaign) {
184
184
  */
185
185
  async function runState(config, state, opts) {
186
186
  const session = new AuditSession({
187
- viewport: "desktop", site: config.site, allowedHosts: config.allowed_hosts, storageState: config.session_file, providers: config.providers,
187
+ viewport: "desktop", site: config.site, allowedHosts: config.allowed_hosts, storageState: config.session_file, connect: config.connect, providers: config.providers,
188
188
  blockHits: config.block_hits !== false, headless: !opts.headed, ...(opts.blockPrivate ? { blockPrivate: opts.blockPrivate } : {}),
189
189
  });
190
190
  const landing = scenarioLanding(config, opts.campaign);
package/src/discover.js CHANGED
@@ -141,13 +141,13 @@ export function toPlan(site, answer, hits = []) {
141
141
  /**
142
142
  * Lets the AI explore the site (one page per type), then asks it for a measurement plan.
143
143
  * With `topic`, exploring and the plan are limited to that kind of event (see TOPICS).
144
- * @param {{ site: string, topic?: string, provider: any, maxSteps?: number, headed?: boolean, allowedHosts?: string[], viewport?: string, blockPrivate?: boolean, log?: (msg: string) => void }} opts
144
+ * @param {{ site: string, topic?: string, provider: any, maxSteps?: number, headed?: boolean, allowedHosts?: string[], viewport?: string, blockPrivate?: boolean, connect?: string, log?: (msg: string) => void }} opts
145
145
  */
146
146
  export async function discoverPlan(opts) {
147
147
  const log = opts.log ?? (() => {});
148
148
  const topic = TOPICS[checkTopic(opts.topic)];
149
149
  const goal = topic ? `${DISCOVER_GOAL}\nThis plan covers only ${opts.topic}: visit just ${topic.explore}, and skip other kinds of page.` : DISCOVER_GOAL;
150
- const session = new AuditSession({ viewport: opts.viewport ?? "desktop", site: opts.site, allowedHosts: opts.allowedHosts, headless: !opts.headed, blockPrivate: opts.blockPrivate });
150
+ const session = new AuditSession({ viewport: opts.viewport ?? "desktop", site: opts.site, allowedHosts: opts.allowedHosts, headless: !opts.headed, blockPrivate: opts.blockPrivate, connect: opts.connect });
151
151
  const snapshots = [];
152
152
  let outcome;
153
153
  try {
package/src/help.js CHANGED
@@ -43,6 +43,7 @@ Options:
43
43
  --lang <code> Report language: ${Object.keys(LANGUAGES).join(" or ")}
44
44
  --headed Show the browser window
45
45
  --session <file> Start logged in: saved (the session aitd login saved) or a session file
46
+ --connect <url> Run in your own Chrome, started with a debugging port (http://127.0.0.1:9222)
46
47
  --fail-on <level> Exit 1 at this level: broken (default), risk, warning, never
47
48
  --baseline <file> Known findings to accept; they don't count toward --fail-on
48
49
  --update-baseline Write the baseline file after the run (creates it)
@@ -74,6 +75,7 @@ Options:
74
75
  --site <url> The site (required)
75
76
  --topic <name> Only plan one kind of event: custom-events, ecommerce, forms or consent
76
77
  --headed Show the browser window
78
+ --connect <url> Explore in your own Chrome, started with a debugging port
77
79
 
78
80
  AI: --provider <name> --model <id|cheap> (default: whichever API key is set)
79
81
 
package/src/mcp.js CHANGED
@@ -442,6 +442,10 @@ export function buildServer(opts) {
442
442
  .optional()
443
443
  .describe(`Tracking providers to check. Default ${DEFAULT_PROVIDERS.join(", ")} plus any other known platform the site sends to. When given, requests to the others are still answered locally, but they are only counted, not shown or checked.`),
444
444
  campaign: campaignSchema().describe(`Open the first page the way an ad click does, so finish_audit checks that the campaign parameters survive redirects and reach the hits. ${CAMPAIGN_DOC}`),
445
+ connect: z
446
+ .string()
447
+ .optional()
448
+ .describe("Run the audit in a fresh window of the user's own Chrome instead of the tool's browser: the debugging address Chrome was started with, e.g. http://127.0.0.1:9222 (Chrome started with --remote-debugging-port=9222 and its own --user-data-dir). Only a Chrome on the computer running a local server. Use it only when the user asks to see the audit in their Chrome."),
445
449
  session: z
446
450
  .enum(["saved"])
447
451
  .optional()
@@ -449,7 +453,7 @@ export function buildServer(opts) {
449
453
  live: z.boolean().optional().describe("Default false: tracking requests are answered locally and never reach the site's accounts. true lets them through to the real analytics and ad accounts, to check them in GA4 Realtime or DebugView, Meta Events Manager or Tag Assistant: the test traffic then shows in the site's reports. Only when the user asks for it."),
450
454
  },
451
455
  },
452
- async ({ site, journey, viewport, allowed_hosts, providers, campaign = true, live = false, session: savedSession }) => {
456
+ async ({ site, journey, viewport, allowed_hosts, providers, campaign = true, live = false, session: savedSession, connect }) => {
453
457
  let url;
454
458
  try {
455
459
  url = new URL(site);
@@ -468,8 +472,10 @@ export function buildServer(opts) {
468
472
  if (live && !opts.allowLive) return fail("Live audits are off on this server: it was started without --allow-live. Leave live out to audit with tracking requests answered locally.");
469
473
  // A saved login lives on the computer running the server; over HTTP, a chat elsewhere must not use it.
470
474
  if (savedSession && !opts.allowFiles) return fail("A saved login session can only be used on a local server. Leave session out, or log in with the test account during the journey.");
475
+ // A Chrome on the server's computer belongs to whoever runs it; over HTTP, a chat elsewhere must not drive it.
476
+ if (connect && !opts.allowFiles) return fail("Connecting to your own Chrome works only on a local server. Leave connect out to use the tool's browser.");
471
477
  const storageState = savedSession ? resolveSessionFile("saved", { site: url.href, dataDir: opts.dataDir ?? DEFAULT_DATA_DIR }) : undefined;
472
- session = new AuditSession({ viewport: viewport ?? "desktop", site: url.href, allowedHosts: allowed_hosts, providers, blockPrivate: opts.blockPrivate, blockHits: !live, storageState });
478
+ session = new AuditSession({ viewport: viewport ?? "desktop", site: url.href, allowedHosts: allowed_hosts, providers, blockPrivate: opts.blockPrivate, blockHits: !live, storageState, connect });
473
479
  } catch (err) {
474
480
  return fail(err.message);
475
481
  }
@@ -477,7 +483,7 @@ export function buildServer(opts) {
477
483
  await session.start();
478
484
  } catch (err) {
479
485
  await session.close().catch(() => {});
480
- return fail(`Could not start the browser: ${err.message}. If Chromium is missing, run: npx playwright install chromium`);
486
+ return fail(connect ? `Could not connect to Chrome: ${err.message}` : `Could not start the browser: ${err.message}. If Chromium is missing, run: npx playwright install chromium`);
481
487
  }
482
488
  const id = randomUUID().slice(0, 8);
483
489
  const preset = presetFor(journey);
package/src/schema.js CHANGED
@@ -69,6 +69,7 @@ export const CONFIG_SCHEMA = z.looseObject({
69
69
  journeys: z.array(JOURNEY_SCHEMA).optional(),
70
70
  allowed_hosts: names.optional(),
71
71
  session_file: text.optional(),
72
+ connect: text.optional(),
72
73
  providers: z.union([names, text], { error: 'must be a list of platforms, e.g. ["ga4", "meta"]' }).optional(),
73
74
  detect_providers: flag.optional(),
74
75
  campaign_checks: flag.optional(),