mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-05 23:29:00 +02:00
[web] Add third-party tracking Propensity (#26638)
* Rename `suppressGoogleAnalytics` to `suppressAnalytics` * Add Propensity script * Add LinkedIn Insight Tag script * Version the cookie to prevent adding unconsented tracking * Move tracking loaders to Typescript, insert them in foot_scripts.pug * Show the cookie-banner when tracking other than GA is set * Revert `oa` cookie versioning * Remove `async` from propensity script * Use shared tracking loader for Hotjar, LinkedIn, and Propensity * Reusable `insertScript` * Remove tracking-linkedin * Test the scripts by adding fake ids * Revert "Test the scripts by adding fake ids" This reverts commit 50759bb6b40fd2684d1b967d83dd71e8517c3de9. GitOrigin-RevId: 2a7b36bfc70ac1fc983f837dd4693a19a385cbc6
This commit is contained in:
@@ -420,6 +420,7 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
|
||||
Settings.analytics &&
|
||||
Settings.analytics.ga &&
|
||||
Settings.analytics.ga.tokenV4,
|
||||
propensityId: Settings?.analytics?.propensity?.id,
|
||||
cookieDomain: Settings.cookieDomain,
|
||||
templateLinks: Settings.templateLinks,
|
||||
labsEnabled: Settings.labs && Settings.labs.enable,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mixin foot-scripts
|
||||
each file in entrypointScripts(entrypoint)
|
||||
script(type='text/javascript' nonce=scriptNonce src=file defer=deferScripts)
|
||||
|
||||
if settings.devToolbar.enabled
|
||||
each file in entrypointScripts('devToolbar')
|
||||
script(
|
||||
@@ -9,3 +10,12 @@ mixin foot-scripts
|
||||
src=file
|
||||
defer=deferScripts
|
||||
)
|
||||
|
||||
if typeof suppressAnalytics == 'undefined'
|
||||
each file in entrypointScripts('tracking')
|
||||
script(
|
||||
type='text/javascript'
|
||||
nonce=scriptNonce
|
||||
src=file
|
||||
defer=deferScripts
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ html(
|
||||
)
|
||||
|
||||
//- Scripts
|
||||
if typeof suppressGoogleAnalytics == 'undefined'
|
||||
if typeof suppressAnalytics == 'undefined'
|
||||
include _google_analytics
|
||||
|
||||
block meta
|
||||
|
||||
@@ -3,7 +3,7 @@ extends ../../layout-react
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
- var suppressGoogleAnalytics = true
|
||||
- var suppressAnalytics = true
|
||||
- isWebsiteRedesign = 'true'
|
||||
|
||||
block entrypointVar
|
||||
|
||||
@@ -3,7 +3,7 @@ extends ../layout-react
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
- var suppressGoogleAnalytics = true
|
||||
- var suppressAnalytics = true
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/compromised-password'
|
||||
|
||||
@@ -29,7 +29,8 @@ function setConsent(value) {
|
||||
|
||||
if (
|
||||
getMeta('ol-ExposedSettings').gaToken ||
|
||||
getMeta('ol-ExposedSettings').gaTokenV4
|
||||
getMeta('ol-ExposedSettings').gaTokenV4 ||
|
||||
getMeta('ol-ExposedSettings').propensityId
|
||||
) {
|
||||
document
|
||||
.querySelectorAll('[data-ol-cookie-banner-set-consent]')
|
||||
|
||||
@@ -1,43 +1,18 @@
|
||||
import getMeta from '@/utils/meta'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { initializeHotjar } from '@/infrastructure/hotjar-snippet'
|
||||
import { createTrackingLoader } from '@/infrastructure/tracking-loader'
|
||||
|
||||
const { hotjarId, hotjarVersion } = getMeta('ol-ExposedSettings')
|
||||
const shouldLoadHotjar = getMeta('ol-shouldLoadHotjar')
|
||||
|
||||
let hotjarInitialized = false
|
||||
|
||||
if (hotjarId && hotjarVersion && shouldLoadHotjar) {
|
||||
const loadHotjar = () => {
|
||||
// consent needed
|
||||
if (!document.cookie.split('; ').some(item => item === 'oa=1')) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!/^\d+$/.test(hotjarId) || !/^\d+$/.test(hotjarVersion)) {
|
||||
debugConsole.error('Invalid Hotjar id or version')
|
||||
return
|
||||
}
|
||||
|
||||
// avoid inserting twice
|
||||
if (!hotjarInitialized) {
|
||||
debugConsole.log('Loading Hotjar')
|
||||
hotjarInitialized = true
|
||||
initializeHotjar(hotjarId, hotjarVersion)
|
||||
}
|
||||
}
|
||||
|
||||
// load when idle, if supported
|
||||
if (typeof window.requestIdleCallback === 'function') {
|
||||
window.requestIdleCallback(loadHotjar)
|
||||
if (!/^\d+$/.test(hotjarId) || !/^\d+$/.test(hotjarVersion)) {
|
||||
debugConsole.error('Invalid Hotjar id or version')
|
||||
} else {
|
||||
loadHotjar()
|
||||
createTrackingLoader(
|
||||
() => initializeHotjar(hotjarId, hotjarVersion),
|
||||
'Hotjar'
|
||||
)
|
||||
}
|
||||
|
||||
// listen for consent
|
||||
window.addEventListener('cookie-consent', event => {
|
||||
if ((event as CustomEvent<boolean>).detail) {
|
||||
loadHotjar()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
|
||||
export const createTrackingLoader = (cb: () => void, name: string) => {
|
||||
// avoid inserting twice
|
||||
let initialized = false
|
||||
|
||||
const loadTracking = () => {
|
||||
// consent needed
|
||||
const consent = document.cookie.split('; ').some(item => item === 'oa=1')
|
||||
if (initialized || !consent) {
|
||||
return
|
||||
}
|
||||
debugConsole.log('Loading Analytics', name)
|
||||
initialized = true
|
||||
cb()
|
||||
}
|
||||
|
||||
// load when idle, if supported
|
||||
if (typeof window.requestIdleCallback === 'function') {
|
||||
window.requestIdleCallback(loadTracking)
|
||||
} else {
|
||||
loadTracking()
|
||||
}
|
||||
|
||||
// listen for consent
|
||||
window.addEventListener('cookie-consent', event => {
|
||||
if ((event as CustomEvent<boolean>).detail) {
|
||||
loadTracking()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const insertScript = (attr: {
|
||||
src: string
|
||||
crossorigin?: string
|
||||
async?: boolean
|
||||
onload?: () => void
|
||||
}) => {
|
||||
const script = document.createElement('script')
|
||||
script.setAttribute('src', attr.src)
|
||||
|
||||
if (attr.crossorigin) {
|
||||
script.setAttribute('crossorigin', attr.crossorigin)
|
||||
}
|
||||
|
||||
if (attr.async) {
|
||||
script.setAttribute('async', 'async')
|
||||
}
|
||||
|
||||
if (attr.onload) {
|
||||
script.onload = attr.onload
|
||||
}
|
||||
|
||||
document.querySelector('head')?.append(script)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import getMeta from '@/utils/meta'
|
||||
import {
|
||||
createTrackingLoader,
|
||||
insertScript,
|
||||
} from '@/infrastructure/tracking-loader'
|
||||
|
||||
const { propensityId } = getMeta('ol-ExposedSettings')
|
||||
|
||||
if (propensityId) {
|
||||
createTrackingLoader(() => loadPropensityScript(propensityId), 'Propensity')
|
||||
}
|
||||
|
||||
const loadPropensityScript = (id: string) => {
|
||||
insertScript({
|
||||
src: 'https://cdn.propensity.com/propensity/propensity_analytics.js',
|
||||
crossorigin: 'anonymous',
|
||||
onload: () => {
|
||||
if (typeof window.propensity !== 'undefined') {
|
||||
window.propensity(id)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import './tracking-propensity'
|
||||
@@ -25,6 +25,7 @@ export type ExposedSettings = {
|
||||
isOverleaf: boolean
|
||||
maxEntitiesPerProject: number
|
||||
projectUploadTimeout: number
|
||||
propensityId?: string
|
||||
maxUploadSize: number
|
||||
recaptchaDisabled: {
|
||||
invite: boolean
|
||||
|
||||
@@ -25,5 +25,7 @@ declare global {
|
||||
}
|
||||
ga?: (...args: any) => void
|
||||
gtag?: (...args: any) => void
|
||||
|
||||
propensity?: (propensityId?: string) => void
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ const entryPoints = {
|
||||
'main-light-style': './frontend/stylesheets/main-light-style.less',
|
||||
'main-style-bootstrap-5':
|
||||
'./frontend/stylesheets/bootstrap-5/main-style.scss',
|
||||
tracking: './frontend/js/infrastructure/tracking.ts',
|
||||
}
|
||||
|
||||
// Add entrypoints for each "page"
|
||||
|
||||
Reference in New Issue
Block a user