@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.mjs CHANGED
@@ -608,6 +608,7 @@ function parseConversionConfig(raw) {
608
608
  business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
609
609
  customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
610
610
  environment: typeof obj.environment === "string" ? obj.environment : void 0,
611
+ google_tracking_state: obj.google_tracking_state === "active" ? "active" : "disabled",
611
612
  gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
612
613
  meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
613
614
  services,
@@ -743,6 +744,283 @@ function formatDateInTz(iso, timeZone, opts, locale) {
743
744
  }).format(date);
744
745
  }
745
746
 
747
+ // ../tracking-core/src/resources/tracking-config-runtime.ts
748
+ var CACHE_PREFIX2 = "_aranova_cfg_runtime_";
749
+ var AUTHORITY_TTL_MS = 6e4;
750
+ var runtimes = /* @__PURE__ */ new Map();
751
+ var configuredIds = /* @__PURE__ */ new Set();
752
+ var scriptLoad = null;
753
+ var jsInitialized = false;
754
+ function cacheKey2(url) {
755
+ return `${CACHE_PREFIX2}${url}`;
756
+ }
757
+ function readCache2(url) {
758
+ if (typeof window === "undefined") return null;
759
+ try {
760
+ const raw = window.sessionStorage.getItem(cacheKey2(url));
761
+ if (!raw) return null;
762
+ const parsed = JSON.parse(raw);
763
+ const config = parseConversionConfig(parsed.config);
764
+ if (!config) return null;
765
+ return {
766
+ etag: typeof parsed.etag === "string" ? parsed.etag : null,
767
+ config
768
+ };
769
+ } catch {
770
+ return null;
771
+ }
772
+ }
773
+ function writeCache2(url, entry) {
774
+ if (typeof window === "undefined") return;
775
+ try {
776
+ window.sessionStorage.setItem(cacheKey2(url), JSON.stringify(entry));
777
+ } catch {
778
+ }
779
+ }
780
+ function isTombstone(config) {
781
+ return config.google_tracking_state === "disabled" || Object.keys(config.gtag_ids).length === 0;
782
+ }
783
+ function validateConfig(config, ref) {
784
+ return config.business_id === ref.businessId && config.environment === ref.environment && (config.google_tracking_state === "active" || config.google_tracking_state === "disabled");
785
+ }
786
+ function pageViewSnapshot() {
787
+ if (typeof window === "undefined" || typeof document === "undefined") return null;
788
+ return {
789
+ href: window.location.href,
790
+ title: document.title || null,
791
+ referrer: document.referrer || null
792
+ };
793
+ }
794
+ function ensureScript(gtagId) {
795
+ if (typeof window === "undefined" || typeof document === "undefined") return Promise.resolve();
796
+ applyDefaultConsentState();
797
+ loadGtagScript(gtagId);
798
+ if (scriptLoad) return scriptLoad;
799
+ scriptLoad = new Promise((resolve) => {
800
+ const script = document.querySelector(
801
+ 'script[data-aranova-tracking="aranova-gtag-loader"]'
802
+ );
803
+ if (!script) {
804
+ resolve();
805
+ return;
806
+ }
807
+ if (script.dataset.loaded === "true") {
808
+ resolve();
809
+ return;
810
+ }
811
+ window.setTimeout(resolve, 0);
812
+ script.addEventListener(
813
+ "load",
814
+ () => {
815
+ script.dataset.loaded = "true";
816
+ resolve();
817
+ },
818
+ { once: true }
819
+ );
820
+ script.addEventListener("error", () => resolve(), { once: true });
821
+ });
822
+ return scriptLoad;
823
+ }
824
+ var TrackingConfigRuntime = class {
825
+ constructor(ref, fetchImpl = globalThis.fetch) {
826
+ this.ref = ref;
827
+ this.fetchImpl = fetchImpl;
828
+ this.current = null;
829
+ this.etag = null;
830
+ this.stateValue = "unconfirmed";
831
+ this.confirmedAt = 0;
832
+ this.inFlight = null;
833
+ this.conversionQueue = [];
834
+ this.automaticQueue = [];
835
+ this.pageQueue = [];
836
+ this.listeners = /* @__PURE__ */ new Set();
837
+ const cached = readCache2(ref.cdnUrl);
838
+ this.current = cached?.config ?? null;
839
+ this.etag = cached?.etag ?? null;
840
+ void this.revalidate();
841
+ if (typeof window !== "undefined") {
842
+ window.addEventListener("visibilitychange", () => {
843
+ if (document.visibilityState === "visible") void this.revalidate();
844
+ });
845
+ window.addEventListener("focus", () => void this.revalidate());
846
+ }
847
+ }
848
+ state() {
849
+ return this.stateValue;
850
+ }
851
+ config() {
852
+ return this.stateValue === "active" || this.stateValue === "tombstone" ? this.current : null;
853
+ }
854
+ __unsafeExpireAuthorityForTests() {
855
+ this.confirmedAt = 0;
856
+ }
857
+ subscribe(listener) {
858
+ this.listeners.add(listener);
859
+ return () => this.listeners.delete(listener);
860
+ }
861
+ async ensureAuthority() {
862
+ if (this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS) {
863
+ return true;
864
+ }
865
+ await this.revalidate();
866
+ return this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS;
867
+ }
868
+ async revalidate() {
869
+ if (typeof window === "undefined" || !this.fetchImpl) return;
870
+ if (this.inFlight) return this.inFlight;
871
+ this.inFlight = this.revalidateNow().finally(() => {
872
+ this.inFlight = null;
873
+ });
874
+ return this.inFlight;
875
+ }
876
+ queuePageView(snapshot = pageViewSnapshot()) {
877
+ if (!snapshot) return;
878
+ this.pageQueue.push(snapshot);
879
+ void this.flush();
880
+ }
881
+ fireConversion(key, options) {
882
+ this.conversionQueue.push({ key, ...options });
883
+ void this.flush();
884
+ }
885
+ queueAutomaticEvent(eventType, metadata, transactionPath) {
886
+ this.automaticQueue.push({ eventType, metadata, transactionPath });
887
+ void this.flush();
888
+ }
889
+ listGoals() {
890
+ return this.current?.goals ?? [];
891
+ }
892
+ async revalidateNow() {
893
+ try {
894
+ const headers = {};
895
+ if (this.etag) headers["If-None-Match"] = this.etag;
896
+ const response = await this.fetchImpl(this.ref.cdnUrl, {
897
+ method: "GET",
898
+ headers,
899
+ cache: "no-cache"
900
+ });
901
+ if (response.status === 304 && this.current && validateConfig(this.current, this.ref)) {
902
+ this.confirm(this.current, this.etag);
903
+ await this.flush();
904
+ return;
905
+ }
906
+ if (!response.ok) {
907
+ this.expireAuthority();
908
+ return;
909
+ }
910
+ const next = parseConversionConfig(await response.json());
911
+ if (!next || !validateConfig(next, this.ref)) {
912
+ this.expireAuthority();
913
+ return;
914
+ }
915
+ if (this.current && next.config_version < this.current.config_version) {
916
+ this.expireAuthority();
917
+ return;
918
+ }
919
+ this.confirm(next, response.headers.get("ETag"));
920
+ await this.flush();
921
+ } catch {
922
+ this.expireAuthority();
923
+ }
924
+ }
925
+ expireAuthority() {
926
+ if (this.stateValue !== "unconfirmed") this.stateValue = "unconfirmed";
927
+ }
928
+ confirm(config, etag) {
929
+ this.current = config;
930
+ this.etag = etag;
931
+ this.confirmedAt = Date.now();
932
+ this.stateValue = isTombstone(config) ? "tombstone" : "active";
933
+ writeCache2(this.ref.cdnUrl, { etag, config });
934
+ if (this.stateValue === "tombstone") {
935
+ this.conversionQueue.length = 0;
936
+ this.automaticQueue.length = 0;
937
+ this.pageQueue.length = 0;
938
+ }
939
+ for (const listener of this.listeners) listener();
940
+ }
941
+ async flush() {
942
+ if (!await this.ensureAuthority()) return;
943
+ if (this.stateValue !== "active" || !this.current) return;
944
+ const ids = Object.values(this.current.gtag_ids).filter(
945
+ (id) => typeof id === "string" && isValidGtagId(id)
946
+ );
947
+ if (ids.length === 0) return;
948
+ await ensureScript(ids[0]);
949
+ const gtag = window.gtag;
950
+ if (typeof gtag !== "function") return;
951
+ if (!jsInitialized) {
952
+ gtag("js", /* @__PURE__ */ new Date());
953
+ jsInitialized = true;
954
+ }
955
+ for (const id of ids) {
956
+ if (configuredIds.has(id)) continue;
957
+ gtag("config", id, { send_page_view: false });
958
+ configuredIds.add(id);
959
+ }
960
+ while (this.pageQueue.length) {
961
+ const page = this.pageQueue.shift();
962
+ gtag("event", "page_view", {
963
+ page_location: page.href,
964
+ page_title: page.title ?? void 0,
965
+ page_referrer: page.referrer ?? void 0
966
+ });
967
+ }
968
+ while (this.automaticQueue.length) {
969
+ const event = this.automaticQueue.shift();
970
+ for (const goal of this.current.goals) {
971
+ if (goal.kind !== "event" || !goal.firing) continue;
972
+ if (!automaticThresholdMet(goal, event.eventType, event.metadata)) continue;
973
+ this.conversionQueue.push({
974
+ key: goal.key,
975
+ transactionId: `auto:${goal.key}:${event.transactionPath}`
976
+ });
977
+ }
978
+ }
979
+ while (this.conversionQueue.length) {
980
+ const item = this.conversionQueue.shift();
981
+ const goal = this.current.goals.find((g) => g.key === item.key);
982
+ const firing = goal?.firing;
983
+ if (!firing || getConsentState() === "denied") continue;
984
+ const currency = item.currency ?? firing.currency ?? null;
985
+ const value = item.value ?? (firing.value_cents != null && currency ? fromMinor(firing.value_cents, currency) : null);
986
+ fireGtagConversion({
987
+ sendTo: firing.send_to,
988
+ value,
989
+ currency,
990
+ transactionId: item.transactionId ?? null
991
+ });
992
+ }
993
+ }
994
+ };
995
+ function automaticThresholdMet(goal, eventType, metadata) {
996
+ const t = goal.trigger;
997
+ if (!t || t.event_type !== eventType) return false;
998
+ switch (eventType) {
999
+ case "scroll_depth":
1000
+ return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
1001
+ case "time_on_site":
1002
+ return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
1003
+ case "multi_page_session":
1004
+ return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
1005
+ case "specific_page_visit":
1006
+ return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
1007
+ case "page_view":
1008
+ case "form_start":
1009
+ case "phone_click":
1010
+ return true;
1011
+ default:
1012
+ return false;
1013
+ }
1014
+ }
1015
+ function getTrackingConfigRuntime(ref, fetchImpl) {
1016
+ const key = `${ref.cdnUrl}|${ref.businessId}|${ref.environment}`;
1017
+ const existing = runtimes.get(key);
1018
+ if (existing) return existing;
1019
+ const runtime = new TrackingConfigRuntime(ref, fetchImpl ?? globalThis.fetch);
1020
+ runtimes.set(key, runtime);
1021
+ return runtime;
1022
+ }
1023
+
746
1024
  // ../tracking-core/src/resources/conversion-autofire.ts
747
1025
  function thresholdMet(goal, eventType, metadata) {
748
1026
  const t = goal.trigger;
@@ -775,6 +1053,12 @@ function createConversionAutoFire(store) {
775
1053
  for (const goal of store.listGoals()) {
776
1054
  if (goal.kind !== "event" || !goal.firing) continue;
777
1055
  if (!thresholdMet(goal, eventType, metadata)) continue;
1056
+ if ("queueAutomaticEvent" in store) {
1057
+ store.fireConversion(goal.key, {
1058
+ transactionId: `auto:${goal.key}:${currentPath()}`
1059
+ });
1060
+ continue;
1061
+ }
778
1062
  const firing = goal.firing;
779
1063
  const cents = firing.value_cents ?? null;
780
1064
  const currency = firing.currency ?? null;
@@ -790,6 +1074,10 @@ function createConversionAutoFire(store) {
790
1074
  }
791
1075
  return {
792
1076
  onAutomaticEvent(eventType, metadata) {
1077
+ if ("queueAutomaticEvent" in store) {
1078
+ store.queueAutomaticEvent(eventType, metadata, currentPath());
1079
+ return;
1080
+ }
793
1081
  if (store.isReady()) {
794
1082
  fireMatching(eventType, metadata);
795
1083
  return;
@@ -1507,69 +1795,154 @@ var timeOnSiteConfigSchema = z11.object({
1507
1795
  thresholdSeconds: z11.number().int().positive()
1508
1796
  }).strict();
1509
1797
 
1798
+ // ../tracking-core/src/events/semantics.ts
1799
+ var EVENT_SEMANTICS = {
1800
+ page_view: {
1801
+ label: "Page view",
1802
+ category: "page",
1803
+ outcomeRole: "navigation",
1804
+ clientVisibility: "simple"
1805
+ },
1806
+ time_on_site: {
1807
+ label: "Time on site",
1808
+ category: "engagement",
1809
+ outcomeRole: "engagement",
1810
+ clientVisibility: "detailed"
1811
+ },
1812
+ specific_page_visit: {
1813
+ label: "Key page visit",
1814
+ category: "engagement",
1815
+ outcomeRole: "engagement",
1816
+ clientVisibility: "detailed"
1817
+ },
1818
+ scroll_depth: {
1819
+ label: "Scroll depth",
1820
+ category: "engagement",
1821
+ outcomeRole: "engagement",
1822
+ clientVisibility: "detailed"
1823
+ },
1824
+ multi_page_session: {
1825
+ label: "Multi-page session",
1826
+ category: "engagement",
1827
+ outcomeRole: "engagement",
1828
+ clientVisibility: "detailed"
1829
+ },
1830
+ form_start: {
1831
+ label: "Form started",
1832
+ category: "engagement",
1833
+ outcomeRole: "engagement",
1834
+ clientVisibility: "simple"
1835
+ },
1836
+ sdk_heartbeat: {
1837
+ label: "SDK heartbeat",
1838
+ category: "system",
1839
+ outcomeRole: "diagnostic",
1840
+ clientVisibility: "hidden"
1841
+ },
1842
+ page_exit: {
1843
+ label: "Page exit",
1844
+ category: "engagement",
1845
+ outcomeRole: "diagnostic",
1846
+ clientVisibility: "detailed"
1847
+ },
1848
+ form_submit: {
1849
+ label: "Form submitted",
1850
+ category: "lead",
1851
+ outcomeRole: "lead",
1852
+ clientVisibility: "simple"
1853
+ },
1854
+ phone_click: {
1855
+ label: "Phone click",
1856
+ category: "lead",
1857
+ outcomeRole: "lead",
1858
+ clientVisibility: "simple"
1859
+ },
1860
+ cta_click: {
1861
+ label: "CTA click",
1862
+ category: "engagement",
1863
+ outcomeRole: "engagement",
1864
+ clientVisibility: "simple"
1865
+ }
1866
+ };
1867
+ function getEventSemantics(eventName) {
1868
+ return eventName in EVENT_SEMANTICS ? EVENT_SEMANTICS[eventName] : null;
1869
+ }
1870
+
1510
1871
  // ../tracking-core/src/events/registry.ts
1511
1872
  var EVENT_REGISTRY = {
1512
1873
  // --- automatic triggers ---
1513
1874
  page_view: {
1514
1875
  kind: "automatic",
1876
+ semantics: EVENT_SEMANTICS.page_view,
1515
1877
  metadataSchema: pageViewMetadataSchema,
1516
1878
  configSchema: pageViewConfigSchema
1517
1879
  },
1518
1880
  time_on_site: {
1519
1881
  kind: "automatic",
1882
+ semantics: EVENT_SEMANTICS.time_on_site,
1520
1883
  metadataSchema: timeOnSiteMetadataSchema,
1521
1884
  configSchema: timeOnSiteConfigSchema
1522
1885
  },
1523
1886
  specific_page_visit: {
1524
1887
  kind: "automatic",
1888
+ semantics: EVENT_SEMANTICS.specific_page_visit,
1525
1889
  metadataSchema: specificPageVisitMetadataSchema,
1526
1890
  configSchema: specificPageVisitConfigSchema
1527
1891
  },
1528
1892
  scroll_depth: {
1529
1893
  kind: "automatic",
1894
+ semantics: EVENT_SEMANTICS.scroll_depth,
1530
1895
  metadataSchema: scrollDepthMetadataSchema,
1531
1896
  configSchema: scrollDepthConfigSchema
1532
1897
  },
1533
1898
  multi_page_session: {
1534
1899
  kind: "automatic",
1900
+ semantics: EVENT_SEMANTICS.multi_page_session,
1535
1901
  metadataSchema: multiPageSessionMetadataSchema,
1536
1902
  configSchema: multiPageSessionConfigSchema
1537
1903
  },
1538
1904
  form_start: {
1539
1905
  kind: "automatic",
1906
+ semantics: EVENT_SEMANTICS.form_start,
1540
1907
  metadataSchema: formStartMetadataSchema,
1541
1908
  configSchema: formStartConfigSchema
1542
1909
  },
1543
1910
  // --- SDK-internal automatic (not consumer-configurable) ---
1544
1911
  sdk_heartbeat: {
1545
1912
  kind: "automatic",
1913
+ semantics: EVENT_SEMANTICS.sdk_heartbeat,
1546
1914
  metadataSchema: sdkHeartbeatMetadataSchema,
1547
1915
  configSchema: sdkHeartbeatConfigSchema
1548
1916
  },
1549
1917
  page_exit: {
1550
1918
  kind: "automatic",
1919
+ semantics: EVENT_SEMANTICS.page_exit,
1551
1920
  metadataSchema: pageExitMetadataSchema,
1552
1921
  configSchema: pageExitConfigSchema
1553
1922
  },
1554
1923
  // --- manual triggers ---
1555
1924
  form_submit: {
1556
1925
  kind: "manual",
1926
+ semantics: EVENT_SEMANTICS.form_submit,
1557
1927
  metadataSchema: formSubmitMetadataSchema,
1558
1928
  configSchema: formSubmitConfigSchema
1559
1929
  },
1560
1930
  phone_click: {
1561
1931
  kind: "manual",
1932
+ semantics: EVENT_SEMANTICS.phone_click,
1562
1933
  metadataSchema: phoneClickMetadataSchema,
1563
1934
  configSchema: phoneClickConfigSchema
1564
1935
  },
1565
1936
  cta_click: {
1566
1937
  kind: "manual",
1938
+ semantics: EVENT_SEMANTICS.cta_click,
1567
1939
  metadataSchema: ctaClickMetadataSchema,
1568
1940
  configSchema: ctaClickConfigSchema
1569
1941
  }
1570
1942
  };
1571
1943
  var ALL_AUTOMATIC_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "automatic").map(([name]) => name);
1572
1944
  var ALL_MANUAL_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "manual").map(([name]) => name);
1945
+ var ALL_LEAD_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.semantics.outcomeRole === "lead").map(([name]) => name);
1573
1946
  function getEventDefinition(name) {
1574
1947
  return EVENT_REGISTRY[name];
1575
1948
  }
@@ -2302,6 +2675,14 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
2302
2675
  const txnBase = input.external_id ?? sale.id;
2303
2676
  for (const item of recorded) {
2304
2677
  if (!item.service) continue;
2678
+ if ("fireConversion" in firing) {
2679
+ firing.fireConversion(item.service, {
2680
+ value: item.amount_cents != null ? fromMinor(item.amount_cents, currency) : void 0,
2681
+ currency,
2682
+ transactionId: `${txnBase}:${item.service}`
2683
+ });
2684
+ continue;
2685
+ }
2305
2686
  const config = firing.getFiring(item.service);
2306
2687
  if (!config) continue;
2307
2688
  const cents = item.amount_cents ?? config.value_cents ?? null;
@@ -2344,6 +2725,14 @@ function createSalesClient(config) {
2344
2725
  // recordSale is the intent-revealing alias — same behavior, clearer call site.
2345
2726
  recordSale: record,
2346
2727
  trackConversion(key, options) {
2728
+ if (config.firing && "fireConversion" in config.firing) {
2729
+ config.firing.fireConversion(key, {
2730
+ value: options?.value ?? void 0,
2731
+ currency: options?.currency ?? config.defaultCurrency ?? void 0,
2732
+ transactionId: options?.transactionId ?? null
2733
+ });
2734
+ return;
2735
+ }
2347
2736
  const firing = config.firing?.getFiring(key);
2348
2737
  if (!firing) return;
2349
2738
  const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
@@ -2848,21 +3237,28 @@ import { useEffect as useEffect3, useMemo } from "react";
2848
3237
  function AdPlatformTracking({
2849
3238
  gtagId,
2850
3239
  gtagIds,
3240
+ trackingConfig,
3241
+ standalonePageView = false,
2851
3242
  metaPixelId,
2852
3243
  metaPixelIds
2853
3244
  }) {
3245
+ const trackingConfigKey = trackingConfig ? `${trackingConfig.cdnUrl}:${trackingConfig.businessId}:${trackingConfig.environment}` : "";
2854
3246
  const gtagIdsKey = useMemo(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
2855
3247
  const metaPixelIdsKey = useMemo(
2856
3248
  () => metaPixelIds ? JSON.stringify(metaPixelIds) : "",
2857
3249
  [metaPixelIds]
2858
3250
  );
2859
3251
  useEffect3(() => {
2860
- if (gtagIds && Object.keys(gtagIds).length > 0) {
3252
+ if (trackingConfig) {
3253
+ const runtime = getTrackingConfigRuntime(trackingConfig);
3254
+ if (standalonePageView) runtime.queuePageView();
3255
+ else void runtime.revalidate();
3256
+ } else if (gtagIds && Object.keys(gtagIds).length > 0) {
2861
3257
  bootstrapMultipleGtags(gtagIds);
2862
3258
  } else if (gtagId) {
2863
3259
  bootstrapGoogleAdsTracking(gtagId);
2864
3260
  }
2865
- }, [gtagId, gtagIdsKey]);
3261
+ }, [gtagId, gtagIdsKey, trackingConfigKey, standalonePageView]);
2866
3262
  useEffect3(() => {
2867
3263
  if (metaPixelIds && Object.keys(metaPixelIds).length > 0) {
2868
3264
  bootstrapMultiplePixels(metaPixelIds);
@@ -2892,7 +3288,7 @@ function GoogleAdsTracking(props) {
2892
3288
  import { createContext as createContext2, useContext as useContext2, useEffect as useEffect5, useMemo as useMemo4 } from "react";
2893
3289
 
2894
3290
  // package.json
2895
- var version = "0.17.3";
3291
+ var version = "0.18.1";
2896
3292
 
2897
3293
  // ../tracking-core/src/phone-react.tsx
2898
3294
  import {
@@ -2998,7 +3394,16 @@ var NOOP_CLIENT = {
2998
3394
  getVisitorId: () => ""
2999
3395
  };
3000
3396
  function createTracking(options) {
3001
- const { apiKey, endpoint, triggers, environment, debug, phone, conversionConfig } = options;
3397
+ const {
3398
+ apiKey,
3399
+ endpoint,
3400
+ triggers,
3401
+ environment,
3402
+ debug,
3403
+ phone,
3404
+ conversionConfig,
3405
+ trackingConfig
3406
+ } = options;
3002
3407
  if (!apiKey || !endpoint) {
3003
3408
  if (apiKey || endpoint) {
3004
3409
  console.warn(
@@ -3044,7 +3449,9 @@ function createTracking(options) {
3044
3449
  );
3045
3450
  const gtagIdsKey = useMemo4(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
3046
3451
  useEffect5(() => {
3047
- if (gtagIds && Object.keys(gtagIds).length > 0) {
3452
+ if (trackingConfig) {
3453
+ void getTrackingConfigRuntime(trackingConfig).revalidate();
3454
+ } else if (gtagIds && Object.keys(gtagIds).length > 0) {
3048
3455
  bootstrapMultipleGtags(gtagIds);
3049
3456
  } else if (gtagId) {
3050
3457
  bootstrapGoogleAdsTracking(gtagId);
@@ -3074,13 +3481,20 @@ function createTracking(options) {
3074
3481
  });
3075
3482
  return attachClientCapturesOnce(rawClient, () => {
3076
3483
  const detachers = [];
3077
- const conversionStore = conversionConfig ? resolveConversionConfig({
3484
+ const conversionStore = trackingConfig ? getTrackingConfigRuntime(trackingConfig) : conversionConfig ? resolveConversionConfig({
3078
3485
  cdnUrl: conversionConfig.cdnUrl,
3079
3486
  baked: conversionConfig.baked
3080
3487
  }) : null;
3081
3488
  const detectorClient = conversionStore ? withConversionAutoFire(rawClient, createConversionAutoFire(conversionStore)) : rawClient;
3082
- detachers.push(attachAutoPageView(detectorClient));
3083
- detachers.push(attachBfcacheRestore(detectorClient));
3489
+ const pageClient = trackingConfig && conversionStore && "queuePageView" in conversionStore ? {
3490
+ ...detectorClient,
3491
+ trackEvent: (input) => {
3492
+ detectorClient.trackEvent(input);
3493
+ if (input.eventType === "page_view") conversionStore.queuePageView();
3494
+ }
3495
+ } : detectorClient;
3496
+ detachers.push(attachAutoPageView(pageClient));
3497
+ detachers.push(attachBfcacheRestore(pageClient));
3084
3498
  detachers.push(attachPageExit(detectorClient));
3085
3499
  const timeOnSite = triggers.automatic.time_on_site;
3086
3500
  if (timeOnSite) {
@@ -3136,6 +3550,7 @@ export {
3136
3550
  ConsentBanner,
3137
3551
  DEFAULT_DECLINE_TTL_DAYS,
3138
3552
  DEFAULT_PHONE_COUNTRY,
3553
+ EVENT_SEMANTICS,
3139
3554
  GoogleAdsTracking,
3140
3555
  NAMED_RANGES,
3141
3556
  PhoneField,
@@ -3156,6 +3571,8 @@ export {
3156
3571
  fromMinor,
3157
3572
  getConsentChoice,
3158
3573
  getConsentState,
3574
+ getEventSemantics,
3575
+ getTrackingConfigRuntime,
3159
3576
  onConsentChange,
3160
3577
  optIn,
3161
3578
  optOut,