@aranova/tracking-react 0.17.3 → 0.18.1

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/dist/index.js CHANGED
@@ -25,6 +25,7 @@ __export(src_exports, {
25
25
  ConsentBanner: () => ConsentBanner,
26
26
  DEFAULT_DECLINE_TTL_DAYS: () => DEFAULT_DECLINE_TTL_DAYS,
27
27
  DEFAULT_PHONE_COUNTRY: () => DEFAULT_PHONE_COUNTRY,
28
+ EVENT_SEMANTICS: () => EVENT_SEMANTICS,
28
29
  GoogleAdsTracking: () => GoogleAdsTracking,
29
30
  NAMED_RANGES: () => NAMED_RANGES,
30
31
  PhoneField: () => PhoneField,
@@ -45,6 +46,8 @@ __export(src_exports, {
45
46
  fromMinor: () => fromMinor,
46
47
  getConsentChoice: () => getConsentChoice,
47
48
  getConsentState: () => getConsentState,
49
+ getEventSemantics: () => getEventSemantics,
50
+ getTrackingConfigRuntime: () => getTrackingConfigRuntime,
48
51
  onConsentChange: () => onConsentChange,
49
52
  optIn: () => optIn,
50
53
  optOut: () => optOut,
@@ -680,6 +683,7 @@ function parseConversionConfig(raw) {
680
683
  business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
681
684
  customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
682
685
  environment: typeof obj.environment === "string" ? obj.environment : void 0,
686
+ google_tracking_state: obj.google_tracking_state === "active" ? "active" : "disabled",
683
687
  gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
684
688
  meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
685
689
  services,
@@ -815,6 +819,283 @@ function formatDateInTz(iso, timeZone, opts, locale) {
815
819
  }).format(date);
816
820
  }
817
821
 
822
+ // ../tracking-core/src/resources/tracking-config-runtime.ts
823
+ var CACHE_PREFIX2 = "_aranova_cfg_runtime_";
824
+ var AUTHORITY_TTL_MS = 6e4;
825
+ var runtimes = /* @__PURE__ */ new Map();
826
+ var configuredIds = /* @__PURE__ */ new Set();
827
+ var scriptLoad = null;
828
+ var jsInitialized = false;
829
+ function cacheKey2(url) {
830
+ return `${CACHE_PREFIX2}${url}`;
831
+ }
832
+ function readCache2(url) {
833
+ if (typeof window === "undefined") return null;
834
+ try {
835
+ const raw = window.sessionStorage.getItem(cacheKey2(url));
836
+ if (!raw) return null;
837
+ const parsed = JSON.parse(raw);
838
+ const config = parseConversionConfig(parsed.config);
839
+ if (!config) return null;
840
+ return {
841
+ etag: typeof parsed.etag === "string" ? parsed.etag : null,
842
+ config
843
+ };
844
+ } catch {
845
+ return null;
846
+ }
847
+ }
848
+ function writeCache2(url, entry) {
849
+ if (typeof window === "undefined") return;
850
+ try {
851
+ window.sessionStorage.setItem(cacheKey2(url), JSON.stringify(entry));
852
+ } catch {
853
+ }
854
+ }
855
+ function isTombstone(config) {
856
+ return config.google_tracking_state === "disabled" || Object.keys(config.gtag_ids).length === 0;
857
+ }
858
+ function validateConfig(config, ref) {
859
+ return config.business_id === ref.businessId && config.environment === ref.environment && (config.google_tracking_state === "active" || config.google_tracking_state === "disabled");
860
+ }
861
+ function pageViewSnapshot() {
862
+ if (typeof window === "undefined" || typeof document === "undefined") return null;
863
+ return {
864
+ href: window.location.href,
865
+ title: document.title || null,
866
+ referrer: document.referrer || null
867
+ };
868
+ }
869
+ function ensureScript(gtagId) {
870
+ if (typeof window === "undefined" || typeof document === "undefined") return Promise.resolve();
871
+ applyDefaultConsentState();
872
+ loadGtagScript(gtagId);
873
+ if (scriptLoad) return scriptLoad;
874
+ scriptLoad = new Promise((resolve) => {
875
+ const script = document.querySelector(
876
+ 'script[data-aranova-tracking="aranova-gtag-loader"]'
877
+ );
878
+ if (!script) {
879
+ resolve();
880
+ return;
881
+ }
882
+ if (script.dataset.loaded === "true") {
883
+ resolve();
884
+ return;
885
+ }
886
+ window.setTimeout(resolve, 0);
887
+ script.addEventListener(
888
+ "load",
889
+ () => {
890
+ script.dataset.loaded = "true";
891
+ resolve();
892
+ },
893
+ { once: true }
894
+ );
895
+ script.addEventListener("error", () => resolve(), { once: true });
896
+ });
897
+ return scriptLoad;
898
+ }
899
+ var TrackingConfigRuntime = class {
900
+ constructor(ref, fetchImpl = globalThis.fetch) {
901
+ this.ref = ref;
902
+ this.fetchImpl = fetchImpl;
903
+ this.current = null;
904
+ this.etag = null;
905
+ this.stateValue = "unconfirmed";
906
+ this.confirmedAt = 0;
907
+ this.inFlight = null;
908
+ this.conversionQueue = [];
909
+ this.automaticQueue = [];
910
+ this.pageQueue = [];
911
+ this.listeners = /* @__PURE__ */ new Set();
912
+ const cached = readCache2(ref.cdnUrl);
913
+ this.current = cached?.config ?? null;
914
+ this.etag = cached?.etag ?? null;
915
+ void this.revalidate();
916
+ if (typeof window !== "undefined") {
917
+ window.addEventListener("visibilitychange", () => {
918
+ if (document.visibilityState === "visible") void this.revalidate();
919
+ });
920
+ window.addEventListener("focus", () => void this.revalidate());
921
+ }
922
+ }
923
+ state() {
924
+ return this.stateValue;
925
+ }
926
+ config() {
927
+ return this.stateValue === "active" || this.stateValue === "tombstone" ? this.current : null;
928
+ }
929
+ __unsafeExpireAuthorityForTests() {
930
+ this.confirmedAt = 0;
931
+ }
932
+ subscribe(listener) {
933
+ this.listeners.add(listener);
934
+ return () => this.listeners.delete(listener);
935
+ }
936
+ async ensureAuthority() {
937
+ if (this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS) {
938
+ return true;
939
+ }
940
+ await this.revalidate();
941
+ return this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS;
942
+ }
943
+ async revalidate() {
944
+ if (typeof window === "undefined" || !this.fetchImpl) return;
945
+ if (this.inFlight) return this.inFlight;
946
+ this.inFlight = this.revalidateNow().finally(() => {
947
+ this.inFlight = null;
948
+ });
949
+ return this.inFlight;
950
+ }
951
+ queuePageView(snapshot = pageViewSnapshot()) {
952
+ if (!snapshot) return;
953
+ this.pageQueue.push(snapshot);
954
+ void this.flush();
955
+ }
956
+ fireConversion(key, options) {
957
+ this.conversionQueue.push({ key, ...options });
958
+ void this.flush();
959
+ }
960
+ queueAutomaticEvent(eventType, metadata, transactionPath) {
961
+ this.automaticQueue.push({ eventType, metadata, transactionPath });
962
+ void this.flush();
963
+ }
964
+ listGoals() {
965
+ return this.current?.goals ?? [];
966
+ }
967
+ async revalidateNow() {
968
+ try {
969
+ const headers = {};
970
+ if (this.etag) headers["If-None-Match"] = this.etag;
971
+ const response = await this.fetchImpl(this.ref.cdnUrl, {
972
+ method: "GET",
973
+ headers,
974
+ cache: "no-cache"
975
+ });
976
+ if (response.status === 304 && this.current && validateConfig(this.current, this.ref)) {
977
+ this.confirm(this.current, this.etag);
978
+ await this.flush();
979
+ return;
980
+ }
981
+ if (!response.ok) {
982
+ this.expireAuthority();
983
+ return;
984
+ }
985
+ const next = parseConversionConfig(await response.json());
986
+ if (!next || !validateConfig(next, this.ref)) {
987
+ this.expireAuthority();
988
+ return;
989
+ }
990
+ if (this.current && next.config_version < this.current.config_version) {
991
+ this.expireAuthority();
992
+ return;
993
+ }
994
+ this.confirm(next, response.headers.get("ETag"));
995
+ await this.flush();
996
+ } catch {
997
+ this.expireAuthority();
998
+ }
999
+ }
1000
+ expireAuthority() {
1001
+ if (this.stateValue !== "unconfirmed") this.stateValue = "unconfirmed";
1002
+ }
1003
+ confirm(config, etag) {
1004
+ this.current = config;
1005
+ this.etag = etag;
1006
+ this.confirmedAt = Date.now();
1007
+ this.stateValue = isTombstone(config) ? "tombstone" : "active";
1008
+ writeCache2(this.ref.cdnUrl, { etag, config });
1009
+ if (this.stateValue === "tombstone") {
1010
+ this.conversionQueue.length = 0;
1011
+ this.automaticQueue.length = 0;
1012
+ this.pageQueue.length = 0;
1013
+ }
1014
+ for (const listener of this.listeners) listener();
1015
+ }
1016
+ async flush() {
1017
+ if (!await this.ensureAuthority()) return;
1018
+ if (this.stateValue !== "active" || !this.current) return;
1019
+ const ids = Object.values(this.current.gtag_ids).filter(
1020
+ (id) => typeof id === "string" && isValidGtagId(id)
1021
+ );
1022
+ if (ids.length === 0) return;
1023
+ await ensureScript(ids[0]);
1024
+ const gtag = window.gtag;
1025
+ if (typeof gtag !== "function") return;
1026
+ if (!jsInitialized) {
1027
+ gtag("js", /* @__PURE__ */ new Date());
1028
+ jsInitialized = true;
1029
+ }
1030
+ for (const id of ids) {
1031
+ if (configuredIds.has(id)) continue;
1032
+ gtag("config", id, { send_page_view: false });
1033
+ configuredIds.add(id);
1034
+ }
1035
+ while (this.pageQueue.length) {
1036
+ const page = this.pageQueue.shift();
1037
+ gtag("event", "page_view", {
1038
+ page_location: page.href,
1039
+ page_title: page.title ?? void 0,
1040
+ page_referrer: page.referrer ?? void 0
1041
+ });
1042
+ }
1043
+ while (this.automaticQueue.length) {
1044
+ const event = this.automaticQueue.shift();
1045
+ for (const goal of this.current.goals) {
1046
+ if (goal.kind !== "event" || !goal.firing) continue;
1047
+ if (!automaticThresholdMet(goal, event.eventType, event.metadata)) continue;
1048
+ this.conversionQueue.push({
1049
+ key: goal.key,
1050
+ transactionId: `auto:${goal.key}:${event.transactionPath}`
1051
+ });
1052
+ }
1053
+ }
1054
+ while (this.conversionQueue.length) {
1055
+ const item = this.conversionQueue.shift();
1056
+ const goal = this.current.goals.find((g) => g.key === item.key);
1057
+ const firing = goal?.firing;
1058
+ if (!firing || getConsentState() === "denied") continue;
1059
+ const currency = item.currency ?? firing.currency ?? null;
1060
+ const value = item.value ?? (firing.value_cents != null && currency ? fromMinor(firing.value_cents, currency) : null);
1061
+ fireGtagConversion({
1062
+ sendTo: firing.send_to,
1063
+ value,
1064
+ currency,
1065
+ transactionId: item.transactionId ?? null
1066
+ });
1067
+ }
1068
+ }
1069
+ };
1070
+ function automaticThresholdMet(goal, eventType, metadata) {
1071
+ const t = goal.trigger;
1072
+ if (!t || t.event_type !== eventType) return false;
1073
+ switch (eventType) {
1074
+ case "scroll_depth":
1075
+ return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
1076
+ case "time_on_site":
1077
+ return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
1078
+ case "multi_page_session":
1079
+ return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
1080
+ case "specific_page_visit":
1081
+ return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
1082
+ case "page_view":
1083
+ case "form_start":
1084
+ case "phone_click":
1085
+ return true;
1086
+ default:
1087
+ return false;
1088
+ }
1089
+ }
1090
+ function getTrackingConfigRuntime(ref, fetchImpl) {
1091
+ const key = `${ref.cdnUrl}|${ref.businessId}|${ref.environment}`;
1092
+ const existing = runtimes.get(key);
1093
+ if (existing) return existing;
1094
+ const runtime = new TrackingConfigRuntime(ref, fetchImpl ?? globalThis.fetch);
1095
+ runtimes.set(key, runtime);
1096
+ return runtime;
1097
+ }
1098
+
818
1099
  // ../tracking-core/src/resources/conversion-autofire.ts
819
1100
  function thresholdMet(goal, eventType, metadata) {
820
1101
  const t = goal.trigger;
@@ -847,6 +1128,12 @@ function createConversionAutoFire(store) {
847
1128
  for (const goal of store.listGoals()) {
848
1129
  if (goal.kind !== "event" || !goal.firing) continue;
849
1130
  if (!thresholdMet(goal, eventType, metadata)) continue;
1131
+ if ("queueAutomaticEvent" in store) {
1132
+ store.fireConversion(goal.key, {
1133
+ transactionId: `auto:${goal.key}:${currentPath()}`
1134
+ });
1135
+ continue;
1136
+ }
850
1137
  const firing = goal.firing;
851
1138
  const cents = firing.value_cents ?? null;
852
1139
  const currency = firing.currency ?? null;
@@ -862,6 +1149,10 @@ function createConversionAutoFire(store) {
862
1149
  }
863
1150
  return {
864
1151
  onAutomaticEvent(eventType, metadata) {
1152
+ if ("queueAutomaticEvent" in store) {
1153
+ store.queueAutomaticEvent(eventType, metadata, currentPath());
1154
+ return;
1155
+ }
865
1156
  if (store.isReady()) {
866
1157
  fireMatching(eventType, metadata);
867
1158
  return;
@@ -1579,69 +1870,154 @@ var timeOnSiteConfigSchema = import_zod11.z.object({
1579
1870
  thresholdSeconds: import_zod11.z.number().int().positive()
1580
1871
  }).strict();
1581
1872
 
1873
+ // ../tracking-core/src/events/semantics.ts
1874
+ var EVENT_SEMANTICS = {
1875
+ page_view: {
1876
+ label: "Page view",
1877
+ category: "page",
1878
+ outcomeRole: "navigation",
1879
+ clientVisibility: "simple"
1880
+ },
1881
+ time_on_site: {
1882
+ label: "Time on site",
1883
+ category: "engagement",
1884
+ outcomeRole: "engagement",
1885
+ clientVisibility: "detailed"
1886
+ },
1887
+ specific_page_visit: {
1888
+ label: "Key page visit",
1889
+ category: "engagement",
1890
+ outcomeRole: "engagement",
1891
+ clientVisibility: "detailed"
1892
+ },
1893
+ scroll_depth: {
1894
+ label: "Scroll depth",
1895
+ category: "engagement",
1896
+ outcomeRole: "engagement",
1897
+ clientVisibility: "detailed"
1898
+ },
1899
+ multi_page_session: {
1900
+ label: "Multi-page session",
1901
+ category: "engagement",
1902
+ outcomeRole: "engagement",
1903
+ clientVisibility: "detailed"
1904
+ },
1905
+ form_start: {
1906
+ label: "Form started",
1907
+ category: "engagement",
1908
+ outcomeRole: "engagement",
1909
+ clientVisibility: "simple"
1910
+ },
1911
+ sdk_heartbeat: {
1912
+ label: "SDK heartbeat",
1913
+ category: "system",
1914
+ outcomeRole: "diagnostic",
1915
+ clientVisibility: "hidden"
1916
+ },
1917
+ page_exit: {
1918
+ label: "Page exit",
1919
+ category: "engagement",
1920
+ outcomeRole: "diagnostic",
1921
+ clientVisibility: "detailed"
1922
+ },
1923
+ form_submit: {
1924
+ label: "Form submitted",
1925
+ category: "lead",
1926
+ outcomeRole: "lead",
1927
+ clientVisibility: "simple"
1928
+ },
1929
+ phone_click: {
1930
+ label: "Phone click",
1931
+ category: "lead",
1932
+ outcomeRole: "lead",
1933
+ clientVisibility: "simple"
1934
+ },
1935
+ cta_click: {
1936
+ label: "CTA click",
1937
+ category: "engagement",
1938
+ outcomeRole: "engagement",
1939
+ clientVisibility: "simple"
1940
+ }
1941
+ };
1942
+ function getEventSemantics(eventName) {
1943
+ return eventName in EVENT_SEMANTICS ? EVENT_SEMANTICS[eventName] : null;
1944
+ }
1945
+
1582
1946
  // ../tracking-core/src/events/registry.ts
1583
1947
  var EVENT_REGISTRY = {
1584
1948
  // --- automatic triggers ---
1585
1949
  page_view: {
1586
1950
  kind: "automatic",
1951
+ semantics: EVENT_SEMANTICS.page_view,
1587
1952
  metadataSchema: pageViewMetadataSchema,
1588
1953
  configSchema: pageViewConfigSchema
1589
1954
  },
1590
1955
  time_on_site: {
1591
1956
  kind: "automatic",
1957
+ semantics: EVENT_SEMANTICS.time_on_site,
1592
1958
  metadataSchema: timeOnSiteMetadataSchema,
1593
1959
  configSchema: timeOnSiteConfigSchema
1594
1960
  },
1595
1961
  specific_page_visit: {
1596
1962
  kind: "automatic",
1963
+ semantics: EVENT_SEMANTICS.specific_page_visit,
1597
1964
  metadataSchema: specificPageVisitMetadataSchema,
1598
1965
  configSchema: specificPageVisitConfigSchema
1599
1966
  },
1600
1967
  scroll_depth: {
1601
1968
  kind: "automatic",
1969
+ semantics: EVENT_SEMANTICS.scroll_depth,
1602
1970
  metadataSchema: scrollDepthMetadataSchema,
1603
1971
  configSchema: scrollDepthConfigSchema
1604
1972
  },
1605
1973
  multi_page_session: {
1606
1974
  kind: "automatic",
1975
+ semantics: EVENT_SEMANTICS.multi_page_session,
1607
1976
  metadataSchema: multiPageSessionMetadataSchema,
1608
1977
  configSchema: multiPageSessionConfigSchema
1609
1978
  },
1610
1979
  form_start: {
1611
1980
  kind: "automatic",
1981
+ semantics: EVENT_SEMANTICS.form_start,
1612
1982
  metadataSchema: formStartMetadataSchema,
1613
1983
  configSchema: formStartConfigSchema
1614
1984
  },
1615
1985
  // --- SDK-internal automatic (not consumer-configurable) ---
1616
1986
  sdk_heartbeat: {
1617
1987
  kind: "automatic",
1988
+ semantics: EVENT_SEMANTICS.sdk_heartbeat,
1618
1989
  metadataSchema: sdkHeartbeatMetadataSchema,
1619
1990
  configSchema: sdkHeartbeatConfigSchema
1620
1991
  },
1621
1992
  page_exit: {
1622
1993
  kind: "automatic",
1994
+ semantics: EVENT_SEMANTICS.page_exit,
1623
1995
  metadataSchema: pageExitMetadataSchema,
1624
1996
  configSchema: pageExitConfigSchema
1625
1997
  },
1626
1998
  // --- manual triggers ---
1627
1999
  form_submit: {
1628
2000
  kind: "manual",
2001
+ semantics: EVENT_SEMANTICS.form_submit,
1629
2002
  metadataSchema: formSubmitMetadataSchema,
1630
2003
  configSchema: formSubmitConfigSchema
1631
2004
  },
1632
2005
  phone_click: {
1633
2006
  kind: "manual",
2007
+ semantics: EVENT_SEMANTICS.phone_click,
1634
2008
  metadataSchema: phoneClickMetadataSchema,
1635
2009
  configSchema: phoneClickConfigSchema
1636
2010
  },
1637
2011
  cta_click: {
1638
2012
  kind: "manual",
2013
+ semantics: EVENT_SEMANTICS.cta_click,
1639
2014
  metadataSchema: ctaClickMetadataSchema,
1640
2015
  configSchema: ctaClickConfigSchema
1641
2016
  }
1642
2017
  };
1643
2018
  var ALL_AUTOMATIC_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "automatic").map(([name]) => name);
1644
2019
  var ALL_MANUAL_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "manual").map(([name]) => name);
2020
+ var ALL_LEAD_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.semantics.outcomeRole === "lead").map(([name]) => name);
1645
2021
  function getEventDefinition(name) {
1646
2022
  return EVENT_REGISTRY[name];
1647
2023
  }
@@ -2374,6 +2750,14 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
2374
2750
  const txnBase = input.external_id ?? sale.id;
2375
2751
  for (const item of recorded) {
2376
2752
  if (!item.service) continue;
2753
+ if ("fireConversion" in firing) {
2754
+ firing.fireConversion(item.service, {
2755
+ value: item.amount_cents != null ? fromMinor(item.amount_cents, currency) : void 0,
2756
+ currency,
2757
+ transactionId: `${txnBase}:${item.service}`
2758
+ });
2759
+ continue;
2760
+ }
2377
2761
  const config = firing.getFiring(item.service);
2378
2762
  if (!config) continue;
2379
2763
  const cents = item.amount_cents ?? config.value_cents ?? null;
@@ -2416,6 +2800,14 @@ function createSalesClient(config) {
2416
2800
  // recordSale is the intent-revealing alias — same behavior, clearer call site.
2417
2801
  recordSale: record,
2418
2802
  trackConversion(key, options) {
2803
+ if (config.firing && "fireConversion" in config.firing) {
2804
+ config.firing.fireConversion(key, {
2805
+ value: options?.value ?? void 0,
2806
+ currency: options?.currency ?? config.defaultCurrency ?? void 0,
2807
+ transactionId: options?.transactionId ?? null
2808
+ });
2809
+ return;
2810
+ }
2419
2811
  const firing = config.firing?.getFiring(key);
2420
2812
  if (!firing) return;
2421
2813
  const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
@@ -2920,21 +3312,28 @@ var import_react3 = require("react");
2920
3312
  function AdPlatformTracking({
2921
3313
  gtagId,
2922
3314
  gtagIds,
3315
+ trackingConfig,
3316
+ standalonePageView = false,
2923
3317
  metaPixelId,
2924
3318
  metaPixelIds
2925
3319
  }) {
3320
+ const trackingConfigKey = trackingConfig ? `${trackingConfig.cdnUrl}:${trackingConfig.businessId}:${trackingConfig.environment}` : "";
2926
3321
  const gtagIdsKey = (0, import_react3.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
2927
3322
  const metaPixelIdsKey = (0, import_react3.useMemo)(
2928
3323
  () => metaPixelIds ? JSON.stringify(metaPixelIds) : "",
2929
3324
  [metaPixelIds]
2930
3325
  );
2931
3326
  (0, import_react3.useEffect)(() => {
2932
- if (gtagIds && Object.keys(gtagIds).length > 0) {
3327
+ if (trackingConfig) {
3328
+ const runtime = getTrackingConfigRuntime(trackingConfig);
3329
+ if (standalonePageView) runtime.queuePageView();
3330
+ else void runtime.revalidate();
3331
+ } else if (gtagIds && Object.keys(gtagIds).length > 0) {
2933
3332
  bootstrapMultipleGtags(gtagIds);
2934
3333
  } else if (gtagId) {
2935
3334
  bootstrapGoogleAdsTracking(gtagId);
2936
3335
  }
2937
- }, [gtagId, gtagIdsKey]);
3336
+ }, [gtagId, gtagIdsKey, trackingConfigKey, standalonePageView]);
2938
3337
  (0, import_react3.useEffect)(() => {
2939
3338
  if (metaPixelIds && Object.keys(metaPixelIds).length > 0) {
2940
3339
  bootstrapMultiplePixels(metaPixelIds);
@@ -2964,7 +3363,7 @@ function GoogleAdsTracking(props) {
2964
3363
  var import_react6 = require("react");
2965
3364
 
2966
3365
  // package.json
2967
- var version = "0.17.3";
3366
+ var version = "0.18.1";
2968
3367
 
2969
3368
  // ../tracking-core/src/phone-react.tsx
2970
3369
  var import_react5 = require("react");
@@ -3063,7 +3462,16 @@ var NOOP_CLIENT = {
3063
3462
  getVisitorId: () => ""
3064
3463
  };
3065
3464
  function createTracking(options) {
3066
- const { apiKey, endpoint, triggers, environment, debug, phone, conversionConfig } = options;
3465
+ const {
3466
+ apiKey,
3467
+ endpoint,
3468
+ triggers,
3469
+ environment,
3470
+ debug,
3471
+ phone,
3472
+ conversionConfig,
3473
+ trackingConfig
3474
+ } = options;
3067
3475
  if (!apiKey || !endpoint) {
3068
3476
  if (apiKey || endpoint) {
3069
3477
  console.warn(
@@ -3109,7 +3517,9 @@ function createTracking(options) {
3109
3517
  );
3110
3518
  const gtagIdsKey = (0, import_react6.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
3111
3519
  (0, import_react6.useEffect)(() => {
3112
- if (gtagIds && Object.keys(gtagIds).length > 0) {
3520
+ if (trackingConfig) {
3521
+ void getTrackingConfigRuntime(trackingConfig).revalidate();
3522
+ } else if (gtagIds && Object.keys(gtagIds).length > 0) {
3113
3523
  bootstrapMultipleGtags(gtagIds);
3114
3524
  } else if (gtagId) {
3115
3525
  bootstrapGoogleAdsTracking(gtagId);
@@ -3139,13 +3549,20 @@ function createTracking(options) {
3139
3549
  });
3140
3550
  return attachClientCapturesOnce(rawClient, () => {
3141
3551
  const detachers = [];
3142
- const conversionStore = conversionConfig ? resolveConversionConfig({
3552
+ const conversionStore = trackingConfig ? getTrackingConfigRuntime(trackingConfig) : conversionConfig ? resolveConversionConfig({
3143
3553
  cdnUrl: conversionConfig.cdnUrl,
3144
3554
  baked: conversionConfig.baked
3145
3555
  }) : null;
3146
3556
  const detectorClient = conversionStore ? withConversionAutoFire(rawClient, createConversionAutoFire(conversionStore)) : rawClient;
3147
- detachers.push(attachAutoPageView(detectorClient));
3148
- detachers.push(attachBfcacheRestore(detectorClient));
3557
+ const pageClient = trackingConfig && conversionStore && "queuePageView" in conversionStore ? {
3558
+ ...detectorClient,
3559
+ trackEvent: (input) => {
3560
+ detectorClient.trackEvent(input);
3561
+ if (input.eventType === "page_view") conversionStore.queuePageView();
3562
+ }
3563
+ } : detectorClient;
3564
+ detachers.push(attachAutoPageView(pageClient));
3565
+ detachers.push(attachBfcacheRestore(pageClient));
3149
3566
  detachers.push(attachPageExit(detectorClient));
3150
3567
  const timeOnSite = triggers.automatic.time_on_site;
3151
3568
  if (timeOnSite) {
@@ -3202,6 +3619,7 @@ function createTracking(options) {
3202
3619
  ConsentBanner,
3203
3620
  DEFAULT_DECLINE_TTL_DAYS,
3204
3621
  DEFAULT_PHONE_COUNTRY,
3622
+ EVENT_SEMANTICS,
3205
3623
  GoogleAdsTracking,
3206
3624
  NAMED_RANGES,
3207
3625
  PhoneField,
@@ -3222,6 +3640,8 @@ function createTracking(options) {
3222
3640
  fromMinor,
3223
3641
  getConsentChoice,
3224
3642
  getConsentState,
3643
+ getEventSemantics,
3644
+ getTrackingConfigRuntime,
3225
3645
  onConsentChange,
3226
3646
  optIn,
3227
3647
  optOut,