@analitikisler/ai-tag-debugger 0.20.1 → 0.21.0

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.
@@ -3,8 +3,9 @@
3
3
  // [data-vp-switch], details.card), so shell.js drives it; the JOURNEYS script in script.js only keeps the viewport
4
4
  // when the journey changes. Ids come from lib.js (stepAnchor, hitId, pushId, requestId) so Findings links land here.
5
5
  import { canonicalEvent } from "../checks.js";
6
- import { parseTrackingRequest, providerOf, PROVIDERS } from "../parsers.js";
7
- import { decodeGa4Item, isEventParam, paramTip } from "../glossary.js";
6
+ import { CONSENT_SIGNALS, parseTrackingRequest, providerOf, PROVIDERS } from "../parsers.js";
7
+ import { decodeGa4Item, paramTip } from "../glossary.js";
8
+ import { callsForHit, hitParams, paramSets } from "../hit-params.js";
8
9
  import { SEVERITY_RANK, isConsentEntry } from "../report-shared.js";
9
10
  import {
10
11
  sectionBlock, use, plat, platIcon, badge, chip, n, esc, secs, pathOf, hostPath, safeKey, platformLabel, sortPlatforms, detailHtml,
@@ -63,53 +64,7 @@ function pushesForHit(run, hit) {
63
64
  return twins.length > 1 && pushes.length === twins.length ? [pushes[twins.indexOf(hit)]] : pushes;
64
65
  }
65
66
 
66
- /** The network request that carried the hit. Identical hits (duplicates) are paired with identical requests in order. */
67
- function callsForHit(run, hit) {
68
- // A late hit was sent during a later step, so its request is recorded there.
69
- const sentIn = hit.late?.during ?? hit.step;
70
- const calls = (run.network ?? []).filter((c) => c.step === sentIn && c.url === hit.url);
71
- const twins = run.hits.filter((h) => (h.late?.during ?? h.step) === sentIn && h.url === hit.url);
72
- return twins.length > 1 && calls.length === twins.length ? [calls[twins.indexOf(hit)]] : calls;
73
- }
74
-
75
- /* ---------- request parameters, moved from the 0.17 renderer ---------- */
76
-
77
- /** Nested JSON as dotted keys (properties.value); arrays stay JSON text. */
78
- function flatten(obj, prefix = "", out = []) {
79
- for (const [k, v] of Object.entries(obj ?? {})) {
80
- const key = prefix ? `${prefix}.${k}` : k;
81
- if (v && typeof v === "object" && !Array.isArray(v) && prefix.split(".").length < 3) flatten(v, key, out);
82
- else out.push([key, cell(v)]);
83
- }
84
- return out;
85
- }
86
-
87
- /** The parameter sets a request carried: one per event in a GA4 batch (query plus each body line), the query plus a flattened JSON body, or just the query. */
88
- function paramSets(call) {
89
- let u;
90
- try {
91
- u = new URL(call.url);
92
- } catch {
93
- return [[]];
94
- }
95
- const query = [...u.searchParams];
96
- const body = call.postData;
97
- if (!body) return [query];
98
- const trimmed = body.trim();
99
- if (trimmed.startsWith("{")) {
100
- try {
101
- return [[...query, ...flatten(JSON.parse(trimmed))]];
102
- } catch { /* not JSON, or cut at the size limit */ }
103
- }
104
- if (/^[^\s{]*=/.test(trimmed)) {
105
- return trimmed.split("\n").filter(Boolean).map((line) => {
106
- const merged = new Map(query);
107
- for (const [k, v] of new URLSearchParams(line)) merged.set(k, v);
108
- return [...merged];
109
- });
110
- }
111
- return [query];
112
- }
67
+ /* ---------- request parameters ---------- */
113
68
 
114
69
  /** Parameter rows with a glossary tip: the "?" shows the tip on hover and takes no focus; screen readers read the hidden span. */
115
70
  function paramRows(lang, entries) {
@@ -120,24 +75,6 @@ function paramRows(lang, entries) {
120
75
  }).join("");
121
76
  }
122
77
 
123
- /**
124
- * What a hit card shows as its parameters: the request's own parameter set (raw keys, with glossary tips), split
125
- * into the event's parameters and the session, device, page and consent ones. A GA4 batch carries one set per
126
- * event; the hit takes the set with its name. Without a captured request, the hit's parsed parameters.
127
- */
128
- function hitParams(run, hit) {
129
- const call = callsForHit(run, hit)[0] ?? null;
130
- if (!call) return { call, batch: null, event: Object.entries(hit.params ?? {}).filter(([k]) => !(k === "items" && hit.items?.length)).map(([k, v]) => [k, cell(v)]), context: [] };
131
- const sets = paramSets(call);
132
- let i = 0;
133
- if (sets.length > 1) {
134
- const names = (parseTrackingRequest(call.url, call.postData ?? null) ?? []).map((h) => h.name);
135
- i = Math.max(0, names.indexOf(hit.name));
136
- }
137
- const entries = sets[i] ?? [];
138
- return { call, batch: sets.length > 1 ? [i + 1, sets.length] : null, event: entries.filter(([k]) => isEventParam(k)), context: entries.filter(([k]) => !isEventParam(k)) };
139
- }
140
-
141
78
  /* ---------- items: GA4 item strings and dataLayer item objects as one table ---------- */
142
79
 
143
80
  const STANDARD_ITEM_KEYS = new Set(["item_id", "item_name", "affiliation", "coupon", "discount", "index", "item_brand", "item_category", "item_category2", "item_category3", "item_category4", "item_category5", "item_list_id", "item_list_name", "item_variant", "location_id", "price", "quantity", "promotion_id", "promotion_name", "creative_name", "creative_slot"]);
@@ -178,7 +115,7 @@ function consentChip(t, key, v) {
178
115
  return `<span class="chip chip-consent ${safeKey(v)}" title="${esc(`${key}: ${v}`)}"><span class="k" aria-hidden="true">${esc(t.signals[key] ?? key)}</span><span aria-hidden="true">${mark}</span><span class="sr">${esc(`${key} ${v}`)}</span></span>`;
179
116
  }
180
117
  const hitConsent = (t, c) => {
181
- const keys = c ? ["ad_storage", "analytics_storage"].filter((k) => typeof c[k] === "string") : [];
118
+ const keys = c ? CONSENT_SIGNALS.filter((k) => typeof c[k] === "string") : [];
182
119
  return keys.length ? keys.map((k) => consentChip(t, k, c[k])).join("") : `<span class="chip chip-consent none" title="${esc(t.noSignalTitle)}">${esc(t.noSignal)}</span>`;
183
120
  };
184
121
  const missingChip = (m, k) => `<span class="chip chip-sev broken jr-miss"><span class="k">${esc(k)}</span>${esc(m.ui.missing)}</span>`;
@@ -339,6 +276,27 @@ function parityNote(m, run, step, parity) {
339
276
  }).join("");
340
277
  }
341
278
 
279
+ /** The step's cookie changes by name, and what the analytics and ad cookies say when the step changed it. */
280
+ function cookiePane(m, run, step) {
281
+ const changes = (run.cookieChanges ?? []).filter((c) => c.step === step.index);
282
+ const id = step.identity;
283
+ const before = (run.steps ?? []).filter((st) => st.index < step.index && st.identity).at(-1)?.identity;
284
+ const facts = [];
285
+ if (id && (changes.length || JSON.stringify(id) !== JSON.stringify(before))) {
286
+ if (id.ga_client_id) {
287
+ const prev = before?.ga_client_id;
288
+ const since = (run.steps ?? []).find((st) => st.identity?.ga_client_id === id.ga_client_id)?.index;
289
+ facts.push(m.ui.gaClientId(id.ga_client_id, prev ? since : null, prev && prev !== id.ga_client_id ? prev : null));
290
+ }
291
+ if (id.gcl_aw) facts.push(m.ui.gclAw(id.gcl_aw === "landing"));
292
+ if (id.fbc) facts.push(m.ui.fbc(id.fbc === "landing"));
293
+ }
294
+ const table = changes.length
295
+ ? `<table class="tbl jr-req" aria-label="${esc(m.ui.tabCookies)}"><thead><tr><th scope="col">${esc(m.ui.cookieCol)}</th><th scope="col">${esc(m.ui.domainCol)}</th><th scope="col">${esc(m.ui.changeCol)}</th></tr></thead><tbody>${changes.map((c) => `<tr><td><code>${esc(c.name)}</code></td><td class="mono xs">${esc(c.domain)}</td><td>${esc(m.ui.cookieChange[c.change] ?? c.change)}</td></tr>`).join("")}</tbody></table>`
296
+ : "";
297
+ return { count: changes.length, live: changes.length > 0 || facts.length > 0, html: `${facts.map((f) => `<p class="xs jr-note-s">${esc(f)}</p>`).join("")}${table ? `<div class="tscroll">${table}</div>` : ""}<p class="muted xs jr-note-s">${esc(m.ui.cookieNamesOnly)}</p>` };
298
+ }
299
+
342
300
  function stepPane(ctx, t, rows, run, ri, step, sev, selected) {
343
301
  const { m } = ctx;
344
302
  const id = stepAnchor(ri, step.index);
@@ -347,15 +305,19 @@ function stepPane(ctx, t, rows, run, ri, step, sev, selected) {
347
305
  const calls = requestsOf(run, step.index);
348
306
  const skipped = skippedOf(run, step.index);
349
307
  const skippedN = skipped.reduce((a, [, c]) => a + c, 0);
308
+ const cookies = cookiePane(m, run, step);
350
309
  const meta = [step.pagePath ? pathOf(step.pagePath) : null, ...actionText(m, step), secs(run, step.t)].filter(Boolean).map((x) => `<span>${esc(x)}</span>`).join("");
351
310
  const reqNotes = `${skippedN ? `<p class="muted xs jr-note-s">${esc(m.ui.skippedInStep(skipped.map(([v, c]) => `${v} ${c}`).join(", "), skippedN))}</p>` : ""}${calls.some((c) => c.bodyDropped) ? `<p class="muted xs jr-note-s">${esc(m.ui.bodyDropped)}</p>` : ""}`;
352
311
  const tabs = [
353
312
  ["hits", esc(m.html.hitsCol), m.html.hitsInStep, hits.length, hits.length ? `<div class="jr-list">${hits.map((h, k) => hitCard(ctx, t, rows, run, ri, step, h, k)).join("")}</div>` : `<p class="muted xs jr-empty">${esc(m.ui.noHits)}</p>`],
354
313
  ["dl", esc(t.dataLayer), t.dataLayer, pushes.length, pushes.length ? `<div class="jr-list">${pushes.map((e, k) => pushCard(ctx, t, run, ri, step, e, k)).join("")}</div>` : `<p class="muted xs jr-empty">${esc(m.ui.noPushes)}</p>`],
355
314
  ["req", esc(m.ui.tabNetwork), m.ui.tabNetwork, calls.length, `${calls.length ? requestTable(ctx, t, run, ri, step, calls) : `<p class="muted xs jr-empty">${esc(m.ui.noRequests)}</p>`}${reqNotes}`],
315
+ // Captures from before cookies were tracked per step have no cookieChanges, and no tab for them.
316
+ ...(run.cookieChanges ? [["ck", esc(m.ui.tabCookies), m.ui.tabCookies, cookies.count, cookies.html]] : []),
356
317
  ];
357
- // A tab with nothing in it is shown but disabled; the requests tab stays open when it only has the skipped-requests note.
358
- const live = (k, c) => c > 0 || (k === "req" && Boolean(reqNotes));
318
+ // A tab with nothing in it is shown but disabled; the requests tab stays open when it only has the skipped-requests note,
319
+ // and the cookies tab when it only says what the click id and client id cookies hold.
320
+ const live = (k, c) => c > 0 || (k === "req" && Boolean(reqNotes)) || (k === "ck" && cookies.live);
359
321
  const first = tabs.find(([k, , , c]) => live(k, c));
360
322
  const body = first
361
323
  ? `<div class="tabs jr-tabs" data-tabs><div role="tablist" aria-label="${esc(t.stepOf(step.index))}">${tabs.map(([k, label, , c]) => `<button type="button" role="tab" aria-controls="${id}-${k}" aria-selected="${first[0] === k}"${live(k, c) ? "" : " disabled"}>${label} ${n(c)}</button>`).join("")}</div>
@@ -172,7 +172,7 @@ function scorecard(ctx) {
172
172
  <p class="sc-verdict sev-${sev}">${use(`sev-${sev}`, 26)}${esc(verdict.statusText)}</p>
173
173
  <p class="sc-head">${esc(headline)}</p>
174
174
  ${aiLine(ctx)}${costLines(ctx, noScore)}
175
- ${statusChips(ctx)}${accepted > 0 ? `\n<p class="meta accepted-line">${esc(m.ui.acceptedLine(accepted))}</p>` : ""}
175
+ ${statusChips(ctx)}${accepted > 0 ? `\n<p class="meta accepted-line">${esc(m.ui.acceptedLine(accepted))}</p>` : ""}${ctx.runs.some((r) => r.live) ? `\n<p class="meta sev-warning">${use("sev-warning", 14)} ${esc(m.ui.liveRun)}</p>` : ""}
176
176
  </div>`;
177
177
  }
178
178
 
package/src/i18n.js CHANGED
@@ -86,6 +86,39 @@ const en = {
86
86
  request: "Request",
87
87
  noPushes: "No dataLayer pushes in this step.",
88
88
  noRequests: "No requests to the chosen providers in this step.",
89
+ cmp: {
90
+ title: "Consent platform",
91
+ unknown: "a consent platform the tool doesn't recognise",
92
+ built: (date) => `Its site bundle was compiled on ${date}.`,
93
+ scriptDated: (date, where) => `Its script (${where}) last changed on ${date}.`,
94
+ script: (url) => `Bundle: ${url}.`,
95
+ language: (name) => `The setup in force is the one for the ${name} language.`,
96
+ categories: (list) => `Categories: ${list.join(", ")}.`,
97
+ modeOn: (vendor, mapping) => `${vendor}'s own Consent Mode integration is on, with ${mapping}.`,
98
+ modeOff: (vendor, mapping) => `${vendor}'s own Consent Mode integration is off, so the consent signals come from elsewhere, such as a GTM template or the site's code${mapping ? `; its configured mapping (${mapping}) is not in force` : ""}.`,
99
+ mapping: (pairs) => pairs.map(([signal, category]) => `${signal} → ${category}`).join(", "),
100
+ passthrough: (urlPassthrough, redaction) => `URL passthrough is ${urlPassthrough ? "on" : "off"} and ads data redaction is ${redaction ? "on" : "off"}.`,
101
+ autoBlocking: (on, rules) => (on ? `Auto-blocking is on${rules ? `, with ${rules} blocking rule${rules === 1 ? "" : "s"}` : ""}.` : "Auto-blocking is off."),
102
+ tcf: (on) => `IAB TCF is ${on ? "on" : "off"}.`,
103
+ law: (law) => `The law its banner follows here: ${law.toUpperCase()}.`,
104
+ modeFixed: (vendor, mapping) => `${vendor} maps its categories to Consent Mode the same way on every site: ${mapping}.`,
105
+ providerBlocking: (n) => (n ? `It holds back scripts from ${n} provider${n === 1 ? "" : "s"} until their category is allowed.` : "It holds back no providers' scripts by itself."),
106
+ version: (v) => `Version ${v}.`,
107
+ setupFile: (url) => `Its setup for this site: ${url}.`,
108
+ published: (date, where) => `That setup (${where}) was last published on ${date}.`,
109
+ model: (model, region) => `It handled this visit${region ? `, placed in ${region},` : ""} under its "${model}" consent model.`,
110
+ implied: "It counted this visit as consent given without a choice, so tags could run before any choice; for a visitor from a region that needs opt-in they would not. Read the No choice columns with that in mind.",
111
+ redaction: (v) => `Ads data redaction: ${v}.`,
112
+ },
113
+ tabCookies: "Cookies",
114
+ cookieCol: "Cookie",
115
+ domainCol: "Domain",
116
+ changeCol: "Change",
117
+ cookieChange: { added: "added", changed: "changed", removed: "removed" },
118
+ cookieNamesOnly: "Names only: cookie values are never recorded.",
119
+ gaClientId: (cid, since, prev) => `GA4 client id (_ga): ${cid}, ${prev ? `changed from ${prev}` : since === null ? "new at this step" : `the same since step ${since}`}.`,
120
+ gclAw: (landing) => (landing ? "_gcl_aw holds the gclid the landing page was opened with." : "_gcl_aw holds a gclid other than the landing page's."),
121
+ fbc: (landing) => (landing ? "_fbc holds the fbclid the landing page was opened with." : "_fbc holds an fbclid other than the landing page's."),
89
122
  eventParams: "Event parameters",
90
123
  contextParams: "Session, device, page and consent parameters",
91
124
  rawRequest: "Raw request",
@@ -100,6 +133,7 @@ const en = {
100
133
  skippedInStep: (list, n) => `Only requests to the chosen providers are shown. ${n} out-of-scope ${n === 1 ? "request was" : "requests were"} skipped in this step: ${list}.`,
101
134
  tabJourneys: "Journeys",
102
135
  sections: "Report sections",
136
+ liveRun: "Live run: tracking requests reached the real analytics and ad accounts, so this test traffic is in their reports.",
103
137
  checkedAgainst: (id) => `Checked against plan ${id}`,
104
138
  planChangesLine: (pc) => (pc.same ? `Plan unchanged since ${pc.previous}` : `Plan changed since ${pc.previous}: ${pc.added.length} added, ${pc.removed.length} removed, ${pc.changed.length} changed`),
105
139
  planVsSite: "Plan vs. site",
@@ -134,7 +168,23 @@ const en = {
134
168
  consentDefault: "Default",
135
169
  consentUpdate: "Update",
136
170
  scenarios: "Consent scenarios",
137
- scenarioCols: { before: "No choice yet", accept: "Accept all", reject: "Reject all", analytics: "Analytics only" },
171
+ scenarioCols: { before: "No choice yet", ignore: "No choice, next page", accept: "Accept all", reject: "Reject all", analytics: "Analytics only" },
172
+ matrix: {
173
+ title: "Consent matrix",
174
+ intro: (landing) => `Each column is a fresh browser that opened ${landing}, made the choice (or none) and opened the page again.`,
175
+ rows: { firstHit: "First Google hit", campaign: "Campaign parameters on it", clientId: "GA4 client id", gclAw: "_gcl_aw cookie", cookies: "Cookies set", loaded: "Tags called, after the page started", tagConsent: "The Google tag's consent" },
176
+ none: "none",
177
+ notRun: "–",
178
+ kept: "all kept",
179
+ lost: (names) => `lost: ${names.join(", ")}`,
180
+ cid: { cookie: "in a cookie already", cookieless: "without a cookie", kept: "kept", changed: "changed", new: "new", none: "none" },
181
+ gcl: { landing: "holds the landing gclid", other: "holds another gclid", none: "not set" },
182
+ cookies: (n, names) => (n ? `${n}: ${names.join(", ")}` : "none"),
183
+ ms: (ms) => (ms < 1000 ? `${Math.round(ms)} ms` : `${(ms / 1000).toFixed(1)} s`),
184
+ signals: { ad_storage: "ad", analytics_storage: "an", ad_user_data: "ud", ad_personalization: "ap" },
185
+ problem: "should not happen with this choice",
186
+ legend: "ad, an, ud, ap: ad_storage, analytics_storage, ad_user_data, ad_personalization; ✓ granted, ✗ denied. ⚠ marks what should not happen with that choice.",
187
+ },
138
188
  scenarioNotRun: "Not supported here",
139
189
  scenarioTag: "Tag",
140
190
  skippedLine: (list, n) => `${n} out-of-scope ${n === 1 ? "request was" : "requests were"} skipped: ${list}.`,
@@ -250,6 +300,9 @@ const en = {
250
300
  journeyIncomplete: (note) => `The journey did not reach its goal${note ? `: ${note}` : "."} Events after that point could not be checked.`,
251
301
  missingEvent: (platform, name) => `${label(platform)} ${q(name)} was not sent on this journey, although the journey reached its goal. ${label(platform)} recorded nothing for it.`,
252
302
  missingEventEarly: (name) => `${q(name)} was not seen, but the journey stopped early, so it is unverified rather than missing.`,
303
+ missingEventUnverified: (name) => `${q(name)} was not seen, but a page on the way was a bot challenge or crashed in the browser, so it is unverified rather than missing.`,
304
+ pageBlocked: (vendor) => `The page was a bot challenge from ${vendor} instead of the site, so the browser never saw the real page and nothing captured there says anything about its tracking.`,
305
+ pageCrashed: (vendor, refused) => `The page crashed in the browser (the ${vendor} error screen)${refused ? `, after ${refused} of its own scripts came back as HTML pages instead of code` : ""}, so its tags may never have run.`,
253
306
  missingEnhanced: (name, setting) => `GA4 ${q(name)} was not sent on this journey, although the journey reached its goal. GA4 sends it by itself, with no tag, when enhanced measurement is on: in GA4, Admin > Data streams > the web stream > Enhanced measurement, switch on "${en.ga4Settings[setting]}". A tag that sends it instead works too.`,
254
307
  missingAutomatic: (name) => `GA4 ${q(name)} was not seen. GA4 makes it by itself, with no tag (first_visit and session_start from flags on its other hits, user_engagement when the page is hidden or left), so it needs no setup and is not counted as missing.`,
255
308
  missingParams: (name, params) => `${q(name)} was sent without ${andList(sortParams(params).map(q), "and")}.`,
@@ -268,8 +321,11 @@ const en = {
268
321
  campaignLost: (names, finalUrl) => `The landing address carried ${names.join(", ")}, but the page ended up on ${finalUrl} without ${names.length === 1 ? "it" : "them"}. A redirect dropped ${names.length === 1 ? "the parameter" : "the parameters"}, so ad clicks lose their attribution.`,
269
322
  campaignMissingInHits: (platform, name, names) => `${label(platform)} ${q(name)} on the landing page reports a page address without ${names.join(", ")}, though the page still had ${names.length === 1 ? "it" : "them"}. The visit can be credited to direct traffic instead of the campaign.`,
270
323
  campaignOk: (names) => `${names.join(", ")} survived the landing page's redirects and reached the hits.`,
324
+ gclidNotStored: () => `The landing address carried a gclid and ad storage was granted, but the _gcl_aw cookie never held it. Google Ads cannot tie a conversion later in the visit, or on a later visit, to the ad click.`,
325
+ clientIdChanged: (from, at) => `The GA4 client id in the _ga cookie changed between "${from}" and "${at}". GA4 counts the visit before and after as two different users.`,
271
326
  consentDefaultMissing: () => "No Google Consent Mode default command (gtag('consent', 'default', ...)) was found in the dataLayer.",
272
327
  consentDefaultLate: () => "The Consent Mode default was set after the first tracking hit was sent.",
328
+ consentDefaultNotApplied: () => "The page pushed a Consent Mode default, but the Google tag never applied it, so its tags ran without one. Tag Assistant shows Consent Mode as not configured.",
273
329
  beforeConsentNever: (platform, name) => `${label(platform)} ${q(name)} was sent although the visitor never made a consent choice on this journey. ${label(platform)} receives data from visitors who have not agreed.`,
274
330
  beforeConsent: (platform, name) => `${label(platform)} ${q(name)} was sent before the visitor made a consent choice. ${label(platform)} receives data from visitors who have not agreed.`,
275
331
  consentV2Missing: (keys) => `The Consent Mode default does not set ${keys.map(q).join(" and ")}. Consent Mode v2 needs them for Google ads in the EEA and UK; without them ad personalization and conversion measurement can stop.`,
@@ -318,6 +374,10 @@ const en = {
318
374
  purchase_mismatch: "Google and Meta received different revenue for the same order, so one of them reports and bids on the wrong number.",
319
375
  campaign_lost_redirect: "A redirect strips the campaign parameters from the landing address, so paid clicks arrive as direct traffic and campaigns get no credit.",
320
376
  campaign_missing_in_hits: "The landing page kept the campaign parameters but the hit did not report them, so the visit is credited to direct traffic.",
377
+ page_blocked: "Nothing about the site's tracking can be judged from the pages behind the challenge; events not seen there are unverified, not missing.",
378
+ page_crashed: "Visitors who get the same error see a broken page, and the tags on it may not run.",
379
+ gclid_not_stored: "Conversions are not linked to the ad click that brought the visitor, so Google Ads under-reports them and bids on less data.",
380
+ client_id_changed: "One visitor becomes two users in GA4: the visit is split, the journey before the change loses its conversions, and attribution starts over.",
321
381
  campaign_params: "Campaign parameters survived the landing redirect and reached the hits, so paid clicks are credited to their campaigns.",
322
382
  event_id_reused: "Two different events share one event ID, so the platform keeps the first and silently drops the other: a real event is lost.",
323
383
  event_id_mismatch: "The browser and server copies of this event carry different IDs, so Meta cannot pair them and counts the conversion twice.",
@@ -327,6 +387,7 @@ const en = {
327
387
  server_endpoint: "A server container answers on the site's domain; the events it forwards to ad platforms are not visible here.",
328
388
  consent_default_missing: "Google tags run with no consent default, so they behave as if every visitor had consented before being asked.",
329
389
  consent_default_late: "The first Google hit went out before the consent default was set, so that hit ignored the visitor's choice.",
390
+ consent_default_not_applied: "Google tags run as if no default had been set: before the visitor chooses, they read and write cookies the default was meant to hold back.",
330
391
  consent_v2_missing: "The consent default lacks the v2 signals, so for EEA and UK traffic Google can stop ad personalisation and conversion measurement.",
331
392
  consent_v2_update: "After the visitor accepted, the v2 signals stayed denied, so Google Ads conversions and remarketing stay off even for consenting visitors.",
332
393
  before_consent: "The event was sent before the visitor made a choice, so the platform receives data from visitors who have not agreed.",
@@ -355,6 +416,10 @@ const en = {
355
416
  purchase_mismatch: "Make both tags read the same order fields; usually one reads a subtotal or a different currency. Then compare one order in both platforms.",
356
417
  campaign_lost_redirect: "Make the redirect keep the query string, or land paid traffic on the final address directly.",
357
418
  campaign_missing_in_hits: "Make the tag report the full landing address, parameters included; look for a page URL override or a page_location variable that fills in late.",
419
+ page_blocked: "Run the audit from a network the site trusts, such as your own computer, or have the bot protection let the audit's browser through, for example by its IP address.",
420
+ page_crashed: "Open the page in an ordinary browser. If it works there, the site's bot protection refused its scripts to the audit's network; if not, a deployment serves pages that ask for script files it no longer has.",
421
+ gclid_not_stored: "Fire the Conversion Linker tag (or the Google tag with the Ads ID) on every page, on consent granted as well as on page load, and keep the gclid on the landing address until it has run.",
422
+ client_id_changed: "Look for what rewrites or deletes _ga at that step: a consent platform clearing cookies, a second GA4 setup with another cookie_domain or cookie_prefix, or a cross-domain link without the _gl parameter.",
358
423
  campaign_params: "Nothing to fix. Check the redirects again when the landing pages change.",
359
424
  event_id_reused: "Generate a new event ID for every event, not once per page load.",
360
425
  event_id_mismatch: "Use one event ID for the pixel event and the server copy: pass the same value to both tags.",
@@ -364,6 +429,7 @@ const en = {
364
429
  server_endpoint: "Nothing to fix in the browser. Check what the server container forwards in its own preview mode.",
365
430
  consent_default_missing: "Set a Consent Mode default (all denied where the law requires it) before any Google tag loads, usually in the consent banner's script or a GTM template.",
366
431
  consent_default_late: "Move the consent default ahead of the Google tag: it must run before gtm.js or gtag.js loads.",
432
+ consent_default_not_applied: "Set the default with gtag('consent', 'default', {...}), where gtag pushes its arguments object; a plain array pushed to the dataLayer is ignored. Check that it goes to the dataLayer the Google tag reads, in the page itself, before gtm.js or gtag.js loads.",
367
433
  consent_v2_missing: "Add ad_user_data and ad_personalization to the consent default, next to ad_storage and analytics_storage.",
368
434
  consent_v2_update: "Grant ad_user_data and ad_personalization in the consent update the banner sends after the visitor accepts.",
369
435
  before_consent: "Give the tag a consent check (its consent settings or an additional consent trigger), or fire it only after the banner's choice.",
@@ -392,6 +458,10 @@ const en = {
392
458
  purchase_mismatch: "money",
393
459
  campaign_lost_redirect: "money",
394
460
  campaign_missing_in_hits: "money",
461
+ page_blocked: "hygiene",
462
+ page_crashed: "hygiene",
463
+ gclid_not_stored: "money",
464
+ client_id_changed: "money",
395
465
  campaign_params: "money",
396
466
  event_id_reused: "money",
397
467
  event_id_mismatch: "money",
@@ -401,6 +471,7 @@ const en = {
401
471
  server_endpoint: "hygiene",
402
472
  consent_default_missing: "legal",
403
473
  consent_default_late: "legal",
474
+ consent_default_not_applied: "legal",
404
475
  consent_v2_missing: "legal",
405
476
  consent_v2_update: "money",
406
477
  before_consent: "legal",
@@ -676,7 +747,7 @@ const en = {
676
747
  // ---- html.consent: strings of src/html/consent.js, edited only by its builder ----
677
748
  consent: {
678
749
  statusLabel: "Consent status per platform",
679
- cols: { before: "No choice", accept: "Accept", reject: "Reject", analytics: "Analytics only" },
750
+ cols: { before: "No choice", ignore: "Next page, no choice", accept: "Accept", reject: "Reject", analytics: "Analytics only" },
680
751
  state: { denied: "denied", granted: "granted", none: "no signal" },
681
752
  tally: (n, state) => `${n} · ${state}`,
682
753
  scenarios: "Scenarios",
@@ -689,6 +760,9 @@ const en = {
689
760
  noDefault: "No default",
690
761
  v2: "v2",
691
762
  v2Missing: "v2 missing",
763
+ tagState: "The Google tag's own state",
764
+ tagFlags: (usedDefault, usedUpdate, late, timedOut) => `${usedDefault ? "default applied" : "no default applied"}${usedUpdate ? ", update applied" : ""}${late ? ", default set late" : ""}${timedOut ? ", wait_for_update ran out" : ""}`,
765
+ defaultViaTag: "No consent command in the dataLayer: the default was set elsewhere, such as a consent platform's GTM template, and the Google tag applied it.",
692
766
  timing: (lo, hi) => (lo === hi ? `${lo} ms` : `${lo}–${hi} ms`),
693
767
  runsWith: (k, n) => (k === n ? `${n} ${n === 1 ? "run" : "runs"}` : `${k} of ${n} runs`),
694
768
  resent: (n) => `Sent again on ${n} more page ${n === 1 ? "load" : "loads"}`,
@@ -790,6 +864,39 @@ const tr = {
790
864
  request: "İstek",
791
865
  noPushes: "Bu adımda dataLayer gönderimi yok.",
792
866
  noRequests: "Bu adımda seçilen sağlayıcılara istek yok.",
867
+ cmp: {
868
+ title: "Onay platformu",
869
+ unknown: "aracın tanımadığı bir onay platformu",
870
+ built: (date) => `Site paketi ${date} tarihinde derlendi.`,
871
+ scriptDated: (date, where) => `Betiği (${where}) en son ${date} tarihinde değişti.`,
872
+ script: (url) => `Paket: ${url}.`,
873
+ language: (name) => `Geçerli kurulum ${name} dili için olanı.`,
874
+ categories: (list) => `Kategoriler: ${list.join(", ")}.`,
875
+ modeOn: (vendor, mapping) => `${vendor}'nin kendi Consent Mode entegrasyonu açık; eşleme: ${mapping}.`,
876
+ modeOff: (vendor, mapping) => `${vendor}'nin kendi Consent Mode entegrasyonu kapalı; onay sinyalleri başka bir yerden, örneğin bir GTM şablonundan ya da sitenin kodundan geliyor${mapping ? `; ayarlı eşlemesi (${mapping}) geçerli değil` : ""}.`,
877
+ mapping: (pairs) => pairs.map(([signal, category]) => `${signal} → ${category}`).join(", "),
878
+ passthrough: (urlPassthrough, redaction) => `URL passthrough ${urlPassthrough ? "açık" : "kapalı"}, reklam verisi karartma ${redaction ? "açık" : "kapalı"}.`,
879
+ autoBlocking: (on, rules) => (on ? `Otomatik engelleme açık${rules ? `, ${rules} engelleme kuralıyla` : ""}.` : "Otomatik engelleme kapalı."),
880
+ tcf: (on) => `IAB TCF ${on ? "açık" : "kapalı"}.`,
881
+ law: (law) => `Bannerın burada uyduğu yasa: ${law.toUpperCase()}.`,
882
+ modeFixed: (vendor, mapping) => `${vendor} kategorilerini her sitede aynı şekilde Consent Mode'a eşler: ${mapping}.`,
883
+ providerBlocking: (n) => (n ? `${n} sağlayıcının betiklerini kategorilerine izin verilene kadar bekletir.` : "Kendiliğinden hiçbir sağlayıcının betiğini bekletmez."),
884
+ version: (v) => `Sürüm ${v}.`,
885
+ setupFile: (url) => `Bu site için kurulumu: ${url}.`,
886
+ published: (date, where) => `Bu kurulum (${where}) en son ${date} tarihinde yayımlandı.`,
887
+ model: (model, region) => `Bu ziyareti${region ? ` (${region} olarak konumlandırılan)` : ""} "${model}" onay modeliyle ele aldı.`,
888
+ implied: "Bu ziyareti seçim yapılmadan verilmiş onay saydı; etiketler herhangi bir seçimden önce çalışabildi. Açık onay gerektiren bir bölgeden gelen ziyaretçi için çalışmazlardı. Seçim yok sütunlarını bunu göz önünde tutarak okuyun.",
889
+ redaction: (v) => `Reklam verisi karartma: ${v}.`,
890
+ },
891
+ tabCookies: "Çerezler",
892
+ cookieCol: "Çerez",
893
+ domainCol: "Alan adı",
894
+ changeCol: "Değişiklik",
895
+ cookieChange: { added: "eklendi", changed: "değişti", removed: "silindi" },
896
+ cookieNamesOnly: "Yalnızca adlar: çerez değerleri hiçbir zaman kaydedilmez.",
897
+ gaClientId: (cid, since, prev) => `GA4 istemci kimliği (_ga): ${cid}, ${prev ? `${prev} değerinden değişti` : since === null ? "bu adımda oluştu" : `${since}. adımdan beri aynı`}.`,
898
+ gclAw: (landing) => (landing ? "_gcl_aw, açılış sayfasının açıldığı gclid'i tutuyor." : "_gcl_aw, açılış sayfasınınkinden farklı bir gclid tutuyor."),
899
+ fbc: (landing) => (landing ? "_fbc, açılış sayfasının açıldığı fbclid'i tutuyor." : "_fbc, açılış sayfasınınkinden farklı bir fbclid tutuyor."),
793
900
  eventParams: "Olay parametreleri",
794
901
  contextParams: "Oturum, cihaz, sayfa ve onay parametreleri",
795
902
  rawRequest: "Ham istek",
@@ -804,6 +911,7 @@ const tr = {
804
911
  skippedInStep: (list, n) => `Yalnızca seçilen sağlayıcıların istekleri gösterilir. Bu adımda kapsam dışı ${n} istek atlandı: ${list}.`,
805
912
  tabJourneys: "Yolculuklar",
806
913
  sections: "Rapor bölümleri",
914
+ liveRun: "Canlı çalıştırma: takip istekleri gerçek analitik ve reklam hesaplarına ulaştı; bu test trafiği onların raporlarında görünür.",
807
915
  checkedAgainst: (id) => `${id} planına göre kontrol edildi`,
808
916
  planChangesLine: (pc) => (pc.same ? `Plan ${pc.previous} sürümünden bu yana değişmedi` : `Plan ${pc.previous} sürümünden bu yana değişti: ${pc.added.length} eklendi, ${pc.removed.length} çıkarıldı, ${pc.changed.length} değişti`),
809
917
  planVsSite: "Plan ve site",
@@ -838,7 +946,23 @@ const tr = {
838
946
  consentDefault: "Varsayılan",
839
947
  consentUpdate: "Güncelleme",
840
948
  scenarios: "Onay senaryoları",
841
- scenarioCols: { before: "Henüz seçim yok", accept: "Tümünü kabul", reject: "Tümünü reddet", analytics: "Yalnızca analitik" },
949
+ scenarioCols: { before: "Henüz seçim yok", ignore: "Seçim yok, sonraki sayfa", accept: "Tümünü kabul", reject: "Tümünü reddet", analytics: "Yalnızca analitik" },
950
+ matrix: {
951
+ title: "Onay matrisi",
952
+ intro: (landing) => `Her sütun, ${landing} adresini açan, seçimi yapan (ya da yapmayan) ve sayfayı yeniden açan ayrı bir tarayıcıdır.`,
953
+ rows: { firstHit: "İlk Google isteği", campaign: "Üzerindeki kampanya parametreleri", clientId: "GA4 istemci kimliği", gclAw: "_gcl_aw çerezi", cookies: "Yazılan çerezler", loaded: "Çağrılan etiketler, sayfa başladıktan sonra", tagConsent: "Google etiketinin onay durumu" },
954
+ none: "yok",
955
+ notRun: "–",
956
+ kept: "hepsi korundu",
957
+ lost: (names) => `kayboldu: ${names.join(", ")}`,
958
+ cid: { cookie: "zaten bir çerezde", cookieless: "çerezsiz", kept: "korundu", changed: "değişti", new: "yeni", none: "yok" },
959
+ gcl: { landing: "açılış gclid'ini tutuyor", other: "başka bir gclid tutuyor", none: "yazılmadı" },
960
+ cookies: (n, names) => (n ? `${n}: ${names.join(", ")}` : "yok"),
961
+ ms: (ms) => (ms < 1000 ? `${Math.round(ms)} ms` : `${(ms / 1000).toFixed(1).replace(".", ",")} sn`),
962
+ signals: { ad_storage: "ad", analytics_storage: "an", ad_user_data: "ud", ad_personalization: "ap" },
963
+ problem: "bu seçimle olmamalı",
964
+ legend: "ad, an, ud, ap: ad_storage, analytics_storage, ad_user_data, ad_personalization; ✓ izin verildi, ✗ reddedildi. ⚠ o seçimle olmaması gerekeni gösterir.",
965
+ },
842
966
  scenarioNotRun: "Burada desteklenmiyor",
843
967
  scenarioTag: "Etiket",
844
968
  skippedLine: (list, n) => `Kapsam dışı ${n} istek atlandı: ${list}.`,
@@ -950,6 +1074,9 @@ const tr = {
950
1074
  journeyIncomplete: (note) => `Yolculuk hedefine ulaşmadı${note ? `: ${note}` : "."} Bu noktadan sonraki olaylar kontrol edilemedi.`,
951
1075
  missingEvent: (platform, name) => `${label(platform)} ${q(name)} bu yolculukta gönderilmedi; oysa yolculuk hedefine ulaştı. ${label(platform)} bu olay için hiçbir veri almadı.`,
952
1076
  missingEventEarly: (name) => `${q(name)} görülmedi; ancak yolculuk erken durduğu için bu olay eksik değil, doğrulanmamış sayılır.`,
1077
+ missingEventUnverified: (name) => `${q(name)} görülmedi; ancak yoldaki bir sayfa bot doğrulaması çıktı ya da tarayıcıda çöktü, bu yüzden eksik değil, doğrulanmamış sayılır.`,
1078
+ pageBlocked: (vendor) => `Sayfa sitenin yerine ${vendor} bot doğrulamasıydı; tarayıcı gerçek sayfayı hiç görmedi ve orada yakalananlar sitenin takibi hakkında bir şey söylemez.`,
1079
+ pageCrashed: (vendor, refused) => `Sayfa tarayıcıda çöktü (${vendor} hata ekranı)${refused ? `; öncesinde kendi betiklerinden ${refused} tanesi kod yerine HTML sayfası olarak geldi` : ""}; etiketleri hiç çalışmamış olabilir.`,
953
1080
  missingEnhanced: (name, setting) => `GA4 ${q(name)} bu yolculukta gönderilmedi; oysa yolculuk hedefine ulaştı. GA4 bu olayı geliştirilmiş ölçüm açıkken etiket gerekmeden kendisi gönderir: GA4'te Yönetici > Veri akışları > web akışı > Geliştirilmiş ölçüm altında "${tr.ga4Settings[setting]}" ayarını açın. Olayı gönderen bir etiket de aynı işi görür.`,
954
1081
  missingAutomatic: (name) => `GA4 ${q(name)} görülmedi. GA4 bu olayı etiket gerekmeden kendisi oluşturur (first_visit ve session_start diğer isteklerindeki işaretlerden, user_engagement sayfa gizlendiğinde ya da kapatıldığında), bu yüzden kurulum gerektirmez ve eksik sayılmaz.`,
955
1082
  missingParams: (name, params) => `${q(name)} olayı ${andList(sortParams(params).map(q), "ve")} ${params.length > 1 ? "parametreleri" : "parametresi"} olmadan gönderildi.`,
@@ -968,8 +1095,11 @@ const tr = {
968
1095
  campaignLost: (names, finalUrl) => `Açılış adresi ${names.join(", ")} taşıyordu, ancak sayfa ${finalUrl} adresinde ${names.length === 1 ? "onsuz" : "onlarsız"} sonlandı. Bir yönlendirme ${names.length === 1 ? "parametreyi" : "parametreleri"} düşürdü, bu yüzden reklam tıklamalarının atfı kaybolur.`,
969
1096
  campaignMissingInHits: (platform, name, names) => `Açılış sayfasındaki ${label(platform)} ${q(name)} isteği ${names.join(", ")} olmadan bir sayfa adresi bildiriyor, oysa sayfada ${names.length === 1 ? "o" : "onlar"} hâlâ vardı. Ziyaret kampanyaya değil doğrudan trafiğe yazılabilir.`,
970
1097
  campaignOk: (names) => `${names.join(", ")} açılış sayfasının yönlendirmelerinden geçti ve isteklere ulaştı.`,
1098
+ gclidNotStored: () => `Açılış adresi bir gclid taşıyordu ve reklam depolamasına izin verildi, ancak _gcl_aw çerezi onu hiç tutmadı. Google Ads, ziyaretin ilerleyen adımlarındaki ya da sonraki bir ziyaretteki dönüşümü reklam tıklamasına bağlayamaz.`,
1099
+ clientIdChanged: (from, at) => `_ga çerezindeki GA4 istemci kimliği "${from}" ile "${at}" arasında değişti. GA4 değişiklikten önceki ve sonraki ziyareti iki ayrı kullanıcı sayar.`,
971
1100
  consentDefaultMissing: () => "dataLayer'da Google Consent Mode varsayılan komutu (gtag('consent', 'default', ...)) bulunamadı.",
972
1101
  consentDefaultLate: () => "Consent Mode varsayılanı, ilk izleme isteği gönderildikten sonra ayarlandı.",
1102
+ consentDefaultNotApplied: () => "Sayfa bir Consent Mode varsayılanı gönderdi, ancak Google etiketi onu hiç uygulamadı; etiketleri varsayılan olmadan çalıştı. Tag Assistant, Consent Mode'u yapılandırılmamış gösterir.",
973
1103
  beforeConsentNever: (platform, name) => `${label(platform)} ${q(name)}, ziyaretçi bu yolculukta hiç onay seçimi yapmadığı hâlde gönderildi. ${label(platform)}, onay vermemiş ziyaretçilerden veri alıyor.`,
974
1104
  beforeConsent: (platform, name) => `${label(platform)} ${q(name)}, ziyaretçi onay seçimini yapmadan önce gönderildi. ${label(platform)}, onay vermemiş ziyaretçilerden veri alıyor.`,
975
1105
  consentV2Missing: (keys) => `Consent Mode varsayılanı ${keys.map(q).join(" ve ")} değerlerini ayarlamıyor. Consent Mode v2, AEA ve Birleşik Krallık'taki Google reklamları için bunları ister; yoksa reklam kişiselleştirme ve dönüşüm ölçümü durabilir.`,
@@ -1017,6 +1147,10 @@ const tr = {
1017
1147
  purchase_mismatch: "Google ve Meta aynı sipariş için farklı gelir aldı; biri yanlış sayıyı raporluyor ve ona göre teklif veriyor.",
1018
1148
  campaign_lost_redirect: "Bir yönlendirme kampanya parametrelerini siliyor; ücretli tıklamalar doğrudan trafik sayılıyor, kampanyalar sattıklarının karşılığını alamıyor.",
1019
1149
  campaign_missing_in_hits: "Açılış sayfası kampanya parametrelerini korudu ama istek onları bildirmedi; ziyaret doğrudan trafiğe yazılıyor.",
1150
+ page_blocked: "Doğrulamanın arkasındaki sayfalardan sitenin takibi hakkında hüküm verilemez; orada görülmeyen olaylar eksik değil, doğrulanmamıştır.",
1151
+ page_crashed: "Aynı hatayı alan ziyaretçiler bozuk bir sayfa görür ve sayfadaki etiketler çalışmayabilir.",
1152
+ gclid_not_stored: "Dönüşümler ziyaretçiyi getiren reklam tıklamasına bağlanmıyor; Google Ads onları eksik raporluyor ve daha az veriyle teklif veriyor.",
1153
+ client_id_changed: "Bir ziyaretçi GA4'te iki kullanıcıya dönüşüyor: ziyaret bölünüyor, değişiklikten önceki yolculuk dönüşümlerini kaybediyor ve atıf baştan başlıyor.",
1020
1154
  campaign_params: "Kampanya parametreleri açılış yönlendirmesinden geçip isteklere ulaştı; ücretli tıklamalar kendi kampanyalarına yazılıyor.",
1021
1155
  event_id_reused: "İki farklı olay tek bir olay kimliğini paylaşıyor; platform ilkini tutup diğerini sessizce atıyor, gerçek bir olay kayboluyor.",
1022
1156
  event_id_mismatch: "Bu olayın tarayıcı ve sunucu kopyaları farklı kimlik taşıyor; Meta ikisini eşleştiremiyor ve dönüşümü iki kez sayıyor.",
@@ -1026,6 +1160,7 @@ const tr = {
1026
1160
  server_endpoint: "Sitenin alan adında bir sunucu container'ı yanıt veriyor; reklam platformlarına ilettiği olaylar burada görünmez.",
1027
1161
  consent_default_missing: "Google etiketleri onay varsayılanı olmadan çalışıyor; her ziyaretçi sorulmadan onay vermiş gibi davranıyorlar.",
1028
1162
  consent_default_late: "İlk Google isteği onay varsayılanı ayarlanmadan çıktı; o istek ziyaretçinin seçimini yok saydı.",
1163
+ consent_default_not_applied: "Google etiketleri hiç varsayılan ayarlanmamış gibi çalışıyor: ziyaretçi seçim yapmadan, varsayılanın engellemesi gereken çerezleri okuyup yazıyorlar.",
1029
1164
  consent_v2_missing: "Onay varsayılanında v2 sinyalleri yok; AEA ve Birleşik Krallık trafiğinde Google reklam kişiselleştirmeyi ve dönüşüm ölçümünü durdurabilir.",
1030
1165
  consent_v2_update: "Ziyaretçi kabul ettikten sonra v2 sinyalleri reddedilmiş kaldı; onay verenler için bile Google Ads dönüşümleri ve yeniden pazarlama kapalı.",
1031
1166
  before_consent: "Olay ziyaretçi seçim yapmadan gönderildi; platform, onay vermemiş ziyaretçilerden veri alıyor.",
@@ -1052,6 +1187,10 @@ const tr = {
1052
1187
  purchase_mismatch: "İki etiketin de aynı sipariş alanlarını okumasını sağlayın; genellikle biri ara toplamı ya da farklı bir para birimini okur. Sonra bir siparişi iki platformda da karşılaştırın.",
1053
1188
  campaign_lost_redirect: "Yönlendirmenin sorgu dizesini korumasını sağlayın ya da ücretli trafiği doğrudan son adrese indirin.",
1054
1189
  campaign_missing_in_hits: "Etiketin açılış adresini parametreleriyle birlikte eksiksiz bildirmesini sağlayın; bir sayfa URL'si geçersiz kılması ya da geç dolan bir page_location değişkeni olup olmadığına bakın.",
1190
+ page_blocked: "Denetimi sitenin güvendiği bir ağdan, örneğin kendi bilgisayarınızdan çalıştırın ya da bot korumasının denetim tarayıcısını, örneğin IP adresiyle, geçirmesini sağlayın.",
1191
+ page_crashed: "Sayfayı sıradan bir tarayıcıda açın. Orada çalışıyorsa sitenin bot koruması betiklerini denetimin ağına vermedi; çalışmıyorsa bir dağıtım artık sahip olmadığı betik dosyalarını isteyen sayfalar sunuyor.",
1192
+ gclid_not_stored: "Dönüşüm bağlayıcı etiketini (ya da Ads kimliğiyle Google etiketini) her sayfada, sayfa yüklenince olduğu kadar onay verildiğinde de çalıştırın ve gclid'i o etiket çalışana kadar açılış adresinde tutun.",
1193
+ client_id_changed: "O adımda _ga'yı yeniden yazan ya da silen şeyi arayın: çerezleri temizleyen bir onay platformu, başka bir cookie_domain ya da cookie_prefix ile ikinci bir GA4 kurulumu, ya da _gl parametresi olmayan alan adları arası bir bağlantı.",
1055
1194
  campaign_params: "Düzeltilecek bir şey yok. Açılış sayfaları değiştiğinde yönlendirmeleri yeniden kontrol edin.",
1056
1195
  event_id_reused: "Her olay için yeni bir olay kimliği üretin; sayfa yüklemesi başına bir kez değil.",
1057
1196
  event_id_mismatch: "Piksel olayı ve sunucu kopyası için tek bir olay kimliği kullanın: aynı değeri iki etikete de verin.",
@@ -1061,6 +1200,7 @@ const tr = {
1061
1200
  server_endpoint: "Tarayıcı tarafında düzeltilecek bir şey yok. Sunucu container'ının neyi ilettiğini kendi önizleme modunda kontrol edin.",
1062
1201
  consent_default_missing: "Herhangi bir Google etiketi yüklenmeden önce, genellikle onay banner'ının betiğinde veya bir GTM şablonunda, bir Consent Mode varsayılanı ayarlayın (yasanın gerektirdiği yerde hepsi reddedilmiş).",
1063
1202
  consent_default_late: "Onay varsayılanını Google etiketinin önüne alın: gtm.js veya gtag.js yüklenmeden önce çalışmalı.",
1203
+ consent_default_not_applied: "Varsayılanı gtag('consent', 'default', {...}) ile ayarlayın; gtag arguments nesnesini gönderir, dataLayer'a gönderilen düz bir dizi yok sayılır. Google etiketinin okuduğu dataLayer'a, sayfanın kendisinde ve gtm.js ya da gtag.js yüklenmeden önce gittiğini kontrol edin.",
1064
1204
  consent_v2_missing: "Onay varsayılanına ad_storage ve analytics_storage'ın yanına ad_user_data ve ad_personalization sinyallerini ekleyin.",
1065
1205
  consent_v2_update: "Banner'ın ziyaretçi kabul ettikten sonra gönderdiği onay güncellemesinde ad_user_data ve ad_personalization iznini verin.",
1066
1206
  before_consent: "Etikete bir onay kontrolü ekleyin (etiketin onay ayarları ya da ek bir onay tetikleyicisi) veya onu yalnızca banner seçiminden sonra çalıştırın.",
@@ -1088,6 +1228,10 @@ const tr = {
1088
1228
  purchase_mismatch: "money",
1089
1229
  campaign_lost_redirect: "money",
1090
1230
  campaign_missing_in_hits: "money",
1231
+ page_blocked: "hygiene",
1232
+ page_crashed: "hygiene",
1233
+ gclid_not_stored: "money",
1234
+ client_id_changed: "money",
1091
1235
  campaign_params: "money",
1092
1236
  event_id_reused: "money",
1093
1237
  event_id_mismatch: "money",
@@ -1097,6 +1241,7 @@ const tr = {
1097
1241
  server_endpoint: "hygiene",
1098
1242
  consent_default_missing: "legal",
1099
1243
  consent_default_late: "legal",
1244
+ consent_default_not_applied: "legal",
1100
1245
  consent_v2_missing: "legal",
1101
1246
  consent_v2_update: "money",
1102
1247
  before_consent: "legal",
@@ -1368,7 +1513,7 @@ const tr = {
1368
1513
  // ---- html.consent: strings of src/html/consent.js, edited only by its builder ----
1369
1514
  consent: {
1370
1515
  statusLabel: "Platform başına onay durumu",
1371
- cols: { before: "Seçim yok", accept: "Kabul", reject: "Reddet", analytics: "Yalnızca analitik" },
1516
+ cols: { before: "Seçim yok", ignore: "Seçimsiz sonraki sayfa", accept: "Kabul", reject: "Reddet", analytics: "Yalnızca analitik" },
1372
1517
  state: { denied: "reddedildi", granted: "verildi", none: "sinyal yok" },
1373
1518
  tally: (n, state) => `${n} · ${state}`,
1374
1519
  scenarios: "Senaryolar",
@@ -1381,6 +1526,9 @@ const tr = {
1381
1526
  noDefault: "Varsayılan yok",
1382
1527
  v2: "v2",
1383
1528
  v2Missing: "v2 eksik",
1529
+ tagState: "Google etiketinin kendi durumu",
1530
+ tagFlags: (usedDefault, usedUpdate, late, timedOut) => `${usedDefault ? "varsayılan uygulandı" : "varsayılan uygulanmadı"}${usedUpdate ? ", güncelleme uygulandı" : ""}${late ? ", varsayılan geç ayarlandı" : ""}${timedOut ? ", wait_for_update süresi doldu" : ""}`,
1531
+ defaultViaTag: "dataLayer'da onay komutu yok: varsayılan başka bir yerde, örneğin bir onay platformunun GTM şablonunda ayarlandı ve Google etiketi onu uyguladı.",
1384
1532
  timing: (lo, hi) => (lo === hi ? `${lo} ms` : `${lo}–${hi} ms`),
1385
1533
  runsWith: (k, n) => (k === n ? `${n} çalıştırma` : `${n} çalıştırmadan ${k} tanesi`),
1386
1534
  resent: (n) => `${n} sayfa yüklemesinde daha yeniden gönderildi`,