@datalyr/web 1.0.7 → 1.1.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.
package/dist/datalyr.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @datalyr/web v1.0.7
2
+ * @datalyr/web v1.1.0
3
3
  * Datalyr Web SDK - Modern attribution tracking for web applications
4
4
  * (c) 2025 Datalyr Inc.
5
5
  * Released under the MIT License
@@ -1626,24 +1626,40 @@ var Datalyr = (function () {
1626
1626
  }
1627
1627
  /**
1628
1628
  * Collect minimal fingerprint data (privacy-friendly)
1629
+ * Matches browser tag minimal fingerprinting approach
1629
1630
  */
1630
1631
  collectMinimal() {
1631
- return {
1632
+ const fp = {
1632
1633
  timezone: this.getTimezone(),
1633
1634
  language: navigator.language || null,
1634
- platform: navigator.platform || null,
1635
- canvasEnabled: false,
1636
- localStorageAvailable: this.testStorage('localStorage'),
1637
- sessionStorageAvailable: this.testStorage('sessionStorage')
1635
+ screen_bucket: this.getScreenBucket(),
1636
+ dnt: (navigator.doNotTrack === '1' || window.globalPrivacyControl === true) || null,
1637
+ userAgent: navigator.userAgent || null
1638
1638
  };
1639
+ // User-Agent Client Hints (modern browsers)
1640
+ if ('userAgentData' in navigator) {
1641
+ const uaData = navigator.userAgentData;
1642
+ fp.userAgentData = {
1643
+ brands: uaData.brands || [],
1644
+ mobile: uaData.mobile || false,
1645
+ platform: uaData.platform || null
1646
+ };
1647
+ }
1648
+ return fp;
1639
1649
  }
1640
1650
  /**
1641
1651
  * Collect standard fingerprint data
1652
+ * PRIVACY: Minimal data collection matching browser tag approach
1653
+ * Only collects data necessary for basic analytics and attribution
1642
1654
  */
1643
1655
  collectStandard() {
1644
1656
  const fingerprint = {};
1645
1657
  try {
1646
- // Basic browser data
1658
+ // PRIVACY: Only collect minimal data needed for attribution
1659
+ fingerprint.timezone = this.getTimezone();
1660
+ fingerprint.language = navigator.language || null;
1661
+ fingerprint.screen_bucket = this.getScreenBucket();
1662
+ fingerprint.dnt = (navigator.doNotTrack === '1' || window.globalPrivacyControl === true) || null;
1647
1663
  fingerprint.userAgent = navigator.userAgent || null;
1648
1664
  // User-Agent Client Hints (modern browsers)
1649
1665
  if ('userAgentData' in navigator) {
@@ -1654,125 +1670,14 @@ var Datalyr = (function () {
1654
1670
  platform: uaData.platform || null
1655
1671
  };
1656
1672
  }
1657
- // Language settings
1658
- fingerprint.language = navigator.language || null;
1659
- fingerprint.languages = navigator.languages ?
1660
- navigator.languages.slice(0, 2) : null; // Limit to 2 for privacy
1661
- // Platform and browser features
1662
- fingerprint.platform = navigator.platform || null;
1663
- fingerprint.cookieEnabled = navigator.cookieEnabled || null;
1664
- fingerprint.doNotTrack = navigator.doNotTrack || null;
1665
- // Hardware (coarsened for privacy)
1666
- fingerprint.hardwareConcurrency = this.coarsenHardwareConcurrency();
1667
- fingerprint.deviceMemory = this.coarsenDeviceMemory();
1668
- fingerprint.maxTouchPoints = navigator.maxTouchPoints > 0 ? 'touch' : 'no-touch';
1669
- // Screen (coarsened)
1670
- fingerprint.screenResolution = this.getScreenResolution();
1671
- fingerprint.colorDepth = screen.colorDepth || null;
1672
- fingerprint.pixelRatio = this.coarsenPixelRatio();
1673
- // Timezone
1674
- fingerprint.timezone = this.getTimezone();
1675
- fingerprint.timezoneOffset = this.coarsenTimezoneOffset();
1676
- // Canvas fingerprinting disabled for privacy
1677
- fingerprint.canvasEnabled = false;
1678
- // Plugins count only (not details for privacy)
1679
- fingerprint.pluginsCount = navigator.plugins ? navigator.plugins.length : null;
1680
- // Storage availability
1681
- fingerprint.localStorageAvailable = this.testStorage('localStorage');
1682
- fingerprint.sessionStorageAvailable = this.testStorage('sessionStorage');
1683
- fingerprint.indexedDBAvailable = this.testIndexedDB();
1684
- // Add cached heavy fingerprint data if available
1685
- if (this.heavyFingerprintDone) {
1686
- Object.assign(fingerprint, this.fingerprintCache);
1687
- }
1688
1673
  }
1689
1674
  catch (e) {
1690
1675
  console.warn('[Datalyr] Error collecting fingerprint:', e);
1691
1676
  }
1692
1677
  return fingerprint;
1693
1678
  }
1694
- /**
1695
- * Collect heavy fingerprint data (WebGL, Audio)
1696
- * Called lazily on first event to improve page load performance
1697
- */
1698
- collectHeavyFingerprint() {
1699
- return __awaiter(this, void 0, void 0, function* () {
1700
- if (this.heavyFingerprintDone || this.privacyMode === 'strict') {
1701
- return;
1702
- }
1703
- try {
1704
- // WebGL fingerprinting
1705
- const webglData = this.getWebGLFingerprint();
1706
- if (webglData) {
1707
- this.fingerprintCache.webglVendor = webglData.vendor;
1708
- this.fingerprintCache.webglRenderer = webglData.renderer;
1709
- }
1710
- // Audio fingerprinting
1711
- const audioData = yield this.getAudioFingerprint();
1712
- if (audioData) {
1713
- this.fingerprintCache.audioSampleRate = audioData.sampleRate;
1714
- this.fingerprintCache.audioState = audioData.state;
1715
- this.fingerprintCache.audioMaxChannels = audioData.maxChannels;
1716
- }
1717
- this.heavyFingerprintDone = true;
1718
- }
1719
- catch (e) {
1720
- console.warn('[Datalyr] Heavy fingerprinting failed:', e);
1721
- }
1722
- });
1723
- }
1724
- /**
1725
- * Get WebGL fingerprint
1726
- */
1727
- getWebGLFingerprint() {
1728
- try {
1729
- const canvas = document.createElement('canvas');
1730
- const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
1731
- if (!gl)
1732
- return null;
1733
- const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
1734
- if (!debugInfo) {
1735
- return {
1736
- vendor: gl.getParameter(gl.VENDOR) || 'unknown',
1737
- renderer: gl.getParameter(gl.RENDERER) || 'unknown'
1738
- };
1739
- }
1740
- return {
1741
- vendor: gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) || 'unknown',
1742
- renderer: gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) || 'unknown'
1743
- };
1744
- }
1745
- catch (_a) {
1746
- return null;
1747
- }
1748
- }
1749
- /**
1750
- * Get audio fingerprint
1751
- */
1752
- getAudioFingerprint() {
1753
- return __awaiter(this, void 0, void 0, function* () {
1754
- var _a;
1755
- try {
1756
- const AudioContext = window.AudioContext || window.webkitAudioContext;
1757
- if (!AudioContext)
1758
- return null;
1759
- const audioCtx = new AudioContext();
1760
- const result = {
1761
- sampleRate: audioCtx.sampleRate || null,
1762
- state: audioCtx.state || null,
1763
- maxChannels: ((_a = audioCtx.destination) === null || _a === void 0 ? void 0 : _a.maxChannelCount) || null
1764
- };
1765
- // Close context to free resources
1766
- if (audioCtx.close) {
1767
- yield audioCtx.close();
1768
- }
1769
- return result;
1770
- }
1771
- catch (_b) {
1772
- return null;
1773
- }
1774
- });
1775
- }
1679
+ // PRIVACY: Heavy fingerprinting (WebGL, Audio) removed
1680
+ // Minimal fingerprinting only for privacy compliance
1776
1681
  /**
1777
1682
  * Get timezone
1778
1683
  */
@@ -1785,10 +1690,13 @@ var Datalyr = (function () {
1785
1690
  }
1786
1691
  }
1787
1692
  /**
1788
- * Get screen resolution (coarsened)
1693
+ * Get coarse screen bucket for basic device classification
1694
+ * Rounds to nearest 100px for privacy
1789
1695
  */
1790
- getScreenResolution() {
1696
+ getScreenBucket() {
1791
1697
  try {
1698
+ if (!window.screen)
1699
+ return null;
1792
1700
  const width = Math.round(screen.width / 100) * 100;
1793
1701
  const height = Math.round(screen.height / 100) * 100;
1794
1702
  return `${width}x${height}`;
@@ -1797,96 +1705,8 @@ var Datalyr = (function () {
1797
1705
  return null;
1798
1706
  }
1799
1707
  }
1800
- /**
1801
- * Coarsen hardware concurrency for privacy
1802
- */
1803
- coarsenHardwareConcurrency() {
1804
- try {
1805
- const cores = navigator.hardwareConcurrency;
1806
- if (!cores)
1807
- return null;
1808
- return cores > 8 ? '8+' : cores;
1809
- }
1810
- catch (_a) {
1811
- return null;
1812
- }
1813
- }
1814
- /**
1815
- * Coarsen device memory for privacy
1816
- */
1817
- coarsenDeviceMemory() {
1818
- try {
1819
- const memory = navigator.deviceMemory;
1820
- if (!memory)
1821
- return null;
1822
- return memory > 4 ? '4+' : memory;
1823
- }
1824
- catch (_a) {
1825
- return null;
1826
- }
1827
- }
1828
- /**
1829
- * Coarsen pixel ratio for privacy
1830
- */
1831
- coarsenPixelRatio() {
1832
- try {
1833
- const ratio = window.devicePixelRatio;
1834
- if (!ratio)
1835
- return null;
1836
- // Round to common values
1837
- if (ratio <= 1)
1838
- return '1';
1839
- if (ratio <= 1.5)
1840
- return '1.5';
1841
- if (ratio <= 2)
1842
- return '2';
1843
- if (ratio <= 3)
1844
- return '3';
1845
- return '3+';
1846
- }
1847
- catch (_a) {
1848
- return null;
1849
- }
1850
- }
1851
- /**
1852
- * Coarsen timezone offset for privacy
1853
- */
1854
- coarsenTimezoneOffset() {
1855
- try {
1856
- const offset = new Date().getTimezoneOffset();
1857
- // Round to nearest 30 minutes
1858
- return Math.round(offset / 30) * 30;
1859
- }
1860
- catch (_a) {
1861
- return null;
1862
- }
1863
- }
1864
- /**
1865
- * Test if storage is available
1866
- */
1867
- testStorage(type) {
1868
- try {
1869
- const storage = window[type];
1870
- const testKey = '__dl_test__';
1871
- storage.setItem(testKey, '1');
1872
- storage.removeItem(testKey);
1873
- return true;
1874
- }
1875
- catch (_a) {
1876
- return false;
1877
- }
1878
- }
1879
- /**
1880
- * Test if IndexedDB is available
1881
- */
1882
- testIndexedDB() {
1883
- try {
1884
- return !!window.indexedDB;
1885
- }
1886
- catch (_a) {
1887
- return false;
1888
- }
1889
- }
1708
+ // PRIVACY: Unused helper methods removed (coarsen functions, storage tests)
1709
+ // Minimal fingerprinting only
1890
1710
  /**
1891
1711
  * Generate fingerprint hash
1892
1712
  */
@@ -2526,13 +2346,7 @@ var Datalyr = (function () {
2526
2346
  if (!this.shouldTrack())
2527
2347
  return;
2528
2348
  try {
2529
- // Collect heavy fingerprint on first event (lazy loading)
2530
- if (!this.heavyFingerprintCollected && this.config.enableFingerprinting) {
2531
- this.heavyFingerprintCollected = true;
2532
- this.fingerprint.collectHeavyFingerprint().catch(err => {
2533
- this.log('Heavy fingerprint collection failed:', err);
2534
- });
2535
- }
2349
+ // PRIVACY: Heavy fingerprinting removed - using minimal fingerprinting only
2536
2350
  // Update session activity
2537
2351
  this.session.updateActivity(eventName);
2538
2352
  // Create event payload