CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/hub/analytics-script.ts
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
* CoCalc native analytics
8
*
9
* This script saves some information about how, from where and why someone came on a cocalc page.
10
* It checks for UTM parameters and the referral and landing page.
11
* On kucalc, static pages are served without going through the hub.
12
* Therefore we have to do the extraction on static pages,
13
* which will also work on adjacent pages like the documentation.
14
* The cookies are only set if they're new.
15
* e.g. this filters the SSO auth pages, which are uninteresting referrals
16
*/
17
18
// variable PREFIX, NAME, DOMAIN and ID are injected in the hub's http server
19
declare var NAME, ID, DOMAIN, PREFIX, window, document;
20
21
// write cookie. it would be cool to set this via the http request itself,
22
// but for reasons I don't know it doesn't work across subdomains.
23
const maxage = 7 * 24 * 60 * 60; // 7 days
24
document.cookie = `${NAME}=${ID}; path=/; domain=${DOMAIN}; max-age=${maxage}`;
25
26
const { href, protocol, host, pathname } = window.location;
27
28
// TODO: use the array defined in packages/util/misc.js
29
const UTM_KEYS: ReadonlyArray<string> = Object.freeze([
30
"source",
31
"medium",
32
"campaign",
33
"term",
34
"content",
35
]);
36
37
type Response = Partial<{
38
utm: { [key: string]: string };
39
referrer: string;
40
landing: string;
41
}>;
42
43
const response: Response = {};
44
45
const UTM = {};
46
const params = href.slice(href.indexOf("?") + 1).split("&");
47
let have_utm = false;
48
for (let i = 0; i < params.length; i++) {
49
const part = params[i];
50
const k_v = part.split("=");
51
let k = k_v[0];
52
const v = k_v[1];
53
if (k == null || v == null) continue;
54
if (k.slice(0, 4) !== "utm_") continue;
55
k = k.slice(4);
56
if (!UTM_KEYS.includes(k)) continue;
57
UTM[k] = window.decodeURIComponent(v.slice(0, 100));
58
have_utm = true;
59
}
60
61
if (have_utm) {
62
response["utm"] = UTM;
63
}
64
65
// do we have a referrer? (not just "")
66
if (document.referrer.length > 0) {
67
response["referrer"] = document.referrer;
68
}
69
70
// also keep a note about the very first landing page
71
response["landing"] = `${protocol}//${host}${pathname}`;
72
73
// PREFIX could be "/", "//{domain}/", "/some/path", or even "//{domain}/some/path"
74
// @see backend/base-path.ts + hub/analytics.ts
75
// Note: don't use double // in the URL, because that will redirect and CORS doesn't work with redirects -- #5506
76
const delim = PREFIX[PREFIX.length - 1] === "/" ? "" : "/";
77
const fetch_url = `${PREFIX}${delim}analytics.js`;
78
79
// send back a beacon (token is in an http-only cookie)
80
window
81
.fetch(fetch_url, {
82
method: "POST",
83
mode: "cors",
84
cache: "no-cache",
85
credentials: "include",
86
headers: {
87
"Content-Type": "application/json",
88
},
89
redirect: "follow",
90
body: JSON.stringify(response),
91
})
92
//.then(response => console.log("Success:", response))
93
.catch((error) => console.error("Error:", error));
94
95
// so it is a module.
96
export {};
97
98