Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
66e89b3e30d258d1249b914309ba1b8d24b2deb2:src/internals/ssr.template.js:generic-api-key:10
1 change: 1 addition & 0 deletions docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const config = {
themes: ["@docusaurus/theme-mermaid"],

plugins: [
require.resolve("./plugins/consent/index"),
() => ({
name: "resolve-react",
configureWebpack() {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"framer-motion": "^10.18.0",
"gray-matter": "4.0.3",
"js-yaml": "^4.1.0",
"posthog-js": "1.420.0",
"prism-react-renderer": "2.4.0",
"react": "^19.0.0",
"react-calendly": "4.3.1",
Expand Down
132 changes: 132 additions & 0 deletions plugins/consent/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment"
import type { ClientModule } from "@docusaurus/types"
import posthog from "posthog-js"

import { GOOGLE_ADS_ID, POSTHOG_TOKEN } from "./config"

type CookiebotConsent = {
marketing?: boolean
statistics?: boolean
method?: "explicit" | "implied" | null
}

type ConsentWindow = Window & {
Cookiebot?: {
consent?: CookiebotConsent
hasResponse?: boolean
}
dataLayer?: unknown[]
gtag?: (...args: unknown[]) => void
posthog?: typeof posthog
}

let postHogInitialized = false
let currentPageCaptured = false

if (ExecutionEnvironment.canUseDOM) {
const consentWindow = window as ConsentWindow

const applyGoogleAdsConsent = () => {
if (
(navigator as Navigator & { globalPrivacyControl?: boolean })
.globalPrivacyControl === true ||
consentWindow.Cookiebot?.consent?.marketing !== true ||
document.querySelector("script[data-qdb-google-ads]")
) {
return
}

consentWindow.dataLayer = consentWindow.dataLayer || []
consentWindow.gtag =
consentWindow.gtag ||
function (...args: unknown[]) {
consentWindow.dataLayer?.push(args)
}
consentWindow.gtag("js", new Date())
consentWindow.gtag("config", GOOGLE_ADS_ID)

const googleAdsScript = document.createElement("script")
googleAdsScript.async = true
googleAdsScript.src = `https://www.googletagmanager.com/gtag/js?id=${GOOGLE_ADS_ID}`
googleAdsScript.setAttribute("data-qdb-google-ads", "")
document.head.appendChild(googleAdsScript)
}

const initialize = () => {
if (!postHogInitialized) {
posthog.init(POSTHOG_TOKEN, {
api_host: "https://us.i.posthog.com",
capture_pageview: false,
cookieless_mode: "on_reject",
opt_out_capturing_by_default: true,
})
postHogInitialized = true
}
}

const applyCookiebotConsent = (fromCookiebotEvent = false) => {
const cookiebot = consentWindow.Cookiebot
const statistics = cookiebot?.consent?.statistics

// Cookiebot's category values default to false before its stored state is
// ready. Trust a mount-time snapshot only when Cookiebot marks it as a
// response (including a stored rejection) or as implied consent. Its
// lifecycle events are authoritative even when no response was required.
const hasSettledConsent =
fromCookiebotEvent ||
cookiebot?.hasResponse === true ||
cookiebot?.consent?.method === "implied"
if (!hasSettledConsent) return

if (typeof statistics !== "boolean") return

applyGoogleAdsConsent()
initialize()
consentWindow.posthog = posthog
if (statistics) {
posthog.opt_in_capturing({ captureEventName: null })
} else {
posthog.opt_out_capturing()
}

if (!currentPageCaptured) {
currentPageCaptured = true
posthog.capture("$pageview", {
$current_url: window.location.href,
$referrer: document.referrer,
})
}
}

const handleCookiebotEvent = () => applyCookiebotConsent(true)

const cookiebotEvents = [
"CookiebotOnConsentReady",
"CookiebotOnAccept",
"CookiebotOnDecline",
]
cookiebotEvents.forEach((event) =>
window.addEventListener(event, handleCookiebotEvent),
)
applyCookiebotConsent()
}

const clientModule: ClientModule = {
onRouteDidUpdate({ location, previousLocation }) {
if (!postHogInitialized || !previousLocation) return

const nextPath = location.pathname + location.search + location.hash
const previousPath =
previousLocation.pathname +
previousLocation.search +
previousLocation.hash
if (nextPath === previousPath) return

posthog.capture("$pageview", {
$current_url: new URL(nextPath, window.location.origin).href,
$referrer: new URL(previousPath, window.location.origin).href,
})
},
}

export default clientModule
21 changes: 21 additions & 0 deletions plugins/consent/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Consent configuration shared by every documentation page.
*
* Cookiebot owns regional behavior and consent. Google Ads uses Basic Consent
* Mode and is loaded only after marketing consent. Wherever Cookiebot asks
* for statistics consent, PostHog uses normal analytics only after acceptance
* and otherwise runs in its native cookieless mode. Outside the banner
* distribution it uses normal analytics.
*/

/** Public identifiers; all of these values ship in the page source. */
const POSTHOG_TOKEN = "phc_GnFGGyhLRvRDKO6iN6eJRAypiKymw9LGf7GlAtZnaKx" // gitleaks:allow — public client key
const COOKIEBOT_CBID = "947be9a7-2d22-4dbf-8964-1b1a954da422"

const GOOGLE_ADS_ID = "AW-11258045331"

module.exports = {
POSTHOG_TOKEN,
COOKIEBOT_CBID,
GOOGLE_ADS_ID,
}
27 changes: 27 additions & 0 deletions plugins/consent/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const path = require("path")
const { COOKIEBOT_CBID } = require("./config")

module.exports = () => ({
name: "questdb-consent",

getClientModules() {
return [path.resolve(__dirname, "client.ts")]
},

injectHtmlTags() {
return {
headTags: [
{
tagName: "script",
attributes: {
id: "Cookiebot",
async: true,
src: "https://consent.cookiebot.com/uc.js",
"data-cbid": COOKIEBOT_CBID,
"data-blockingmode": "manual",
},
},
],
}
},
})
118 changes: 0 additions & 118 deletions src/components/Subscribe/index.tsx

This file was deleted.

67 changes: 0 additions & 67 deletions src/components/Subscribe/style.module.css

This file was deleted.

Loading
Loading