|
1 | | -/* Simple Analytics - Privacy friendly analytics (docs.simpleanalytics.com/script; 2021-11-25; 49af; v2) */ |
| 1 | +/* Simple Analytics - Privacy friendly analytics (docs.simpleanalytics.com/script; 2021-12-30; 26ba; v8) */ |
2 | 2 | /* eslint-env browser */ |
3 | 3 |
|
4 | 4 | (function (window, overwriteOptions, baseUrl, apiUrlPrefix, version, saGlobal) { |
|
51 | 51 | var pagehide = "pagehide"; |
52 | 52 | var platformText = "platform"; |
53 | 53 | var platformVersionText = "platformVersion"; |
| 54 | + var docsUrl = "https://docs.simpleanalytics.com"; |
54 | 55 | var isBotAgent = |
55 | 56 | /(bot|spider|crawl)/i.test(userAgent) && !/(cubot)/i.test(userAgent); |
56 | 57 | var screen = window.screen; |
57 | 58 |
|
58 | | - ///////////////////// |
59 | | - // PAYLOAD FOR BOTH PAGE VIEWS AND EVENTS |
60 | | - // |
61 | | - |
62 | | - var bot = |
63 | | - nav.webdriver || |
64 | | - window.__nightmare || |
65 | | - "callPhantom" in window || |
66 | | - "_phantom" in window || |
67 | | - "phantom" in window || |
68 | | - isBotAgent; |
69 | | - |
70 | | - |
71 | | - var payload = { |
72 | | - version: version, |
73 | | - ua: userAgent, |
74 | | - }; |
75 | | - if (bot) payload.bot = true; |
76 | | - |
77 | | - payload.sri = false; |
78 | | - |
79 | | - // Use User-Agent Client Hints for better privacy |
80 | | - // https://web.dev/user-agent-client-hints/ |
81 | | - if (uaData) { |
82 | | - payload.mobile = uaData.mobile; |
83 | | - payload.brands = stringify(uaData.brands); |
84 | | - } |
85 | | - |
86 | 59 | ///////////////////// |
87 | 60 | // HELPER FUNCTIONS |
88 | 61 | // |
|
186 | 159 |
|
187 | 160 | // Send data via image |
188 | 161 | var sendData = function (data, callback) { |
189 | | - data = assign(payload, data); |
| 162 | + data = assign(payload, page, data); |
190 | 163 |
|
191 | 164 | var image = new Image(); |
192 | 165 | if (callback) { |
|
281 | 254 | attr(scriptElement, "collect-dnt") == trueText; |
282 | 255 |
|
283 | 256 | // Customers can overwrite their hostname, here we check for that |
284 | | - var definedHostname = |
285 | | - overwriteOptions.hostname || |
286 | | - attr(scriptElement, "hostname") || |
287 | | - locationHostname; |
| 257 | + var overwrittenHostname = |
| 258 | + overwriteOptions.hostname || attr(scriptElement, "hostname"); |
| 259 | + var definedHostname = overwrittenHostname || locationHostname; |
288 | 260 |
|
289 | 261 | // Some customers want to collect page views manually |
290 | 262 | var autoCollect = !( |
|
307 | 279 | ? ignorePagesRaw.split(/, ?/) |
308 | 280 | : []; |
309 | 281 |
|
| 282 | + // Customers can ignore certain pages |
| 283 | + var ignorePagesRaw = |
| 284 | + overwriteOptions.ignorePages || attr(scriptElement, "ignore-pages"); |
| 285 | + |
310 | 286 | ///////////////////// |
311 | | - // ADD HOSTNAME TO PAYLOAD |
| 287 | + // PAYLOAD FOR BOTH PAGE VIEWS AND EVENTS |
312 | 288 | // |
313 | 289 |
|
314 | | - payload.hostname = definedHostname; |
| 290 | + var bot = |
| 291 | + nav.webdriver || |
| 292 | + window.__nightmare || |
| 293 | + "callPhantom" in window || |
| 294 | + "_phantom" in window || |
| 295 | + "phantom" in window || |
| 296 | + isBotAgent; |
| 297 | + |
| 298 | + var payload = { |
| 299 | + version: version, |
| 300 | + ua: userAgent, |
| 301 | + https: loc.protocol == https, |
| 302 | + timezone: timezone, |
| 303 | + hostname: definedHostname, |
| 304 | + page_id: uuid(), |
| 305 | + session_id: uuid(), |
| 306 | + }; |
| 307 | + if (bot) payload.bot = true; |
| 308 | + |
| 309 | + payload.sri = false; |
| 310 | + |
| 311 | + // Use User-Agent Client Hints for better privacy |
| 312 | + // https://web.dev/user-agent-client-hints/ |
| 313 | + if (uaData) { |
| 314 | + payload.mobile = uaData.mobile; |
| 315 | + payload.brands = stringify(uaData.brands); |
| 316 | + } |
315 | 317 |
|
316 | 318 | ///////////////////// |
317 | 319 | // ADD WARNINGS |
|
327 | 329 |
|
328 | 330 | // Don't track when Do Not Track is set to true |
329 | 331 | if (!collectDnt && doNotTrack in nav && nav[doNotTrack] == "1") |
330 | | - return warn(notSending + "when " + doNotTrack + " is enabled"); |
| 332 | + return warn( |
| 333 | + notSending + |
| 334 | + "when " + |
| 335 | + doNotTrack + |
| 336 | + " is enabled. See " + |
| 337 | + docsUrl + |
| 338 | + "/dnt" |
| 339 | + ); |
331 | 340 |
|
332 | | - // Don't track when localhost or when it's an IP address |
| 341 | + // Warn when sending from localhost and not having a hostname set |
333 | 342 | if ( |
334 | | - locationHostname.indexOf(".") == -1 || |
335 | | - /^[0-9]+$/.test(locationHostname.replace(/\./g, "")) |
| 343 | + (locationHostname.indexOf(".") == -1 || |
| 344 | + /^[0-9.:]+$/.test(locationHostname)) && |
| 345 | + !overwrittenHostname |
336 | 346 | ) |
337 | | - return warn(notSending + "from " + locationHostname); |
| 347 | + warn( |
| 348 | + "Set a hostname when sending data from " + |
| 349 | + locationHostname + |
| 350 | + ". See " + |
| 351 | + docsUrl + |
| 352 | + "/overwrite-domain-name" |
| 353 | + ); |
338 | 354 |
|
339 | 355 | ///////////////////// |
340 | 356 | // SETUP INITIAL VARIABLES |
341 | 357 | // |
342 | 358 |
|
343 | 359 | var page = {}; |
344 | | - var lastPageId = uuid(); |
345 | 360 | var lastSendPath; |
346 | 361 |
|
347 | 362 | // We don't want to end up with sensitive data so we clean the referrer URL |
|
372 | 387 | var sendBeaconText = "sendBeacon"; |
373 | 388 |
|
374 | 389 | var sendOnLeave = function (id, push) { |
375 | | - var append = { type: "append", original_id: push ? id : lastPageId }; |
| 390 | + var append = { type: "append", original_id: push ? id : payload.page_id }; |
376 | 391 |
|
377 | 392 | append[duration] = Math.round((now() - start - msHidden) / thousand); |
378 | 393 | msHidden = 0; |
|
381 | 396 | append.scrolled = Math.max(0, scrolled, position()); |
382 | 397 |
|
383 | 398 | if (push || !(sendBeaconText in nav)) { |
| 399 | + // sendData will assign payload to request |
384 | 400 | sendData(append); |
385 | 401 | } else { |
386 | 402 | nav[sendBeaconText]( |
|
468 | 484 |
|
469 | 485 | // Send page view and append data to it |
470 | 486 | var sendPageView = function (isPushState, deleteSourceInfo, sameSite) { |
471 | | - if (isPushState) sendOnLeave("" + lastPageId, true); |
472 | | - lastPageId = uuid(); |
473 | | - page.id = lastPageId; |
| 487 | + if (isPushState) sendOnLeave("" + payload.page_id, true); |
| 488 | + payload.page_id = uuid(); |
474 | 489 |
|
475 | 490 | var currentPage = definedHostname + getPath(); |
476 | 491 |
|
477 | 492 | sendData( |
478 | 493 | assign( |
479 | | - page, |
480 | 494 | deleteSourceInfo |
481 | 495 | ? { |
482 | 496 | referrer: sameSite ? referrer : null, |
483 | 497 | } |
484 | 498 | : source, |
485 | 499 | { |
486 | | - https: loc.protocol == https, |
487 | | - timezone: timezone, |
| 500 | + id: payload.page_id, |
488 | 501 | type: pageviewsText, |
489 | 502 | } |
490 | 503 | ) |
|
501 | 514 | if (!path || lastSendPath == path) return; |
502 | 515 |
|
503 | 516 | lastSendPath = path; |
| 517 | + page.path = path; |
504 | 518 |
|
505 | | - var data = { |
506 | | - path: path, |
507 | | - viewport_width: |
508 | | - Math.max(documentElement[clientWidth] || 0, window.innerWidth || 0) || |
509 | | - null, |
510 | | - viewport_height: |
511 | | - Math.max( |
512 | | - documentElement[clientHeight] || 0, |
513 | | - window.innerHeight || 0 |
514 | | - ) || null, |
515 | | - }; |
| 519 | + page.viewport_width = |
| 520 | + Math.max(documentElement[clientWidth] || 0, window.innerWidth || 0) || |
| 521 | + null; |
| 522 | + page.viewport_height = |
| 523 | + Math.max(documentElement[clientHeight] || 0, window.innerHeight || 0) || |
| 524 | + null; |
516 | 525 |
|
517 | | - if (nav[language]) data[language] = nav[language]; |
| 526 | + if (nav[language]) page[language] = nav[language]; |
518 | 527 |
|
519 | 528 | if (screen) { |
520 | | - data.screen_width = screen.width; |
521 | | - data.screen_height = screen.height; |
| 529 | + page.screen_width = screen.width; |
| 530 | + page.screen_height = screen.height; |
522 | 531 | } |
523 | 532 |
|
524 | 533 | // If a user does refresh we need to delete the referrer because otherwise it count double |
|
546 | 555 | : false; |
547 | 556 |
|
548 | 557 | // We set unique variable based on pushstate or back navigation, if no match we check the referrer |
549 | | - data.unique = isPushState || userNavigated ? false : !sameSite; |
550 | | - |
551 | | - page = data; |
| 558 | + page.unique = isPushState || userNavigated ? false : !sameSite; |
552 | 559 |
|
553 | 560 | var triggerSendPageView = function () { |
554 | 561 | fetchedHighEntropyValues = true; |
|
598 | 605 | event = new Event(type); |
599 | 606 | } else { |
600 | 607 | // Fix for IE |
| 608 | + // https://github.com/simpleanalytics/scripts/issues/8 |
601 | 609 | event = doc.createEvent("Event"); |
602 | 610 | event.initEvent(type, true, true); |
603 | 611 | } |
|
647 | 655 | // EVENTS |
648 | 656 | // |
649 | 657 |
|
650 | | - var sessionId = uuid(); |
651 | 658 | var validTypes = ["string", "number"]; |
652 | 659 |
|
653 | 660 | var sendEvent = function (event, callbackRaw) { |
|
676 | 683 |
|
677 | 684 | if (event) { |
678 | 685 | sendData( |
679 | | - assign(source, bot ? { bot: true } : {}, { |
| 686 | + assign(source, { |
680 | 687 | type: "event", |
681 | 688 | event: event, |
682 | | - page_id: page.id, |
683 | | - session_id: sessionId, |
684 | 689 | }), |
685 | 690 | callback |
686 | 691 | ); |
|
718 | 723 | {"saGlobal":INSTALL_OPTIONS.sa_global,"mode":INSTALL_OPTIONS.hash_mode ? 'hash' : null,"collectDnt":INSTALL_OPTIONS.collect_dnt}, |
719 | 724 | INSTALL_OPTIONS.custom_domain || "queue.simpleanalyticscdn.com", |
720 | 725 | "", |
721 | | - "cloudflare_2", |
| 726 | + "cloudflare_8", |
722 | 727 | "sa_event" |
723 | 728 | ); |
0 commit comments