"` from
terminating this script tag. %>
posthog.init("phc_ellvZYbbslQNdyxufj8RjamjZFARzm5lqBoLwikS0we", {
api_host: 'https://eu.i.posthog.com',
person_profiles: 'identified_only',
capture_pageview: true,
capture_pageleave: true,
autocapture: true,
rageclick: true,
// Capture unhandled window.onerror / unhandledrejection events
// and ship them to PostHog as $exception events. Pairs with the
// server-side posthog-rails exception capture so we see both
// tiers in one place.
capture_exceptions: true,
// Web vitals (LCP, INP, CLS, FCP, TTFB) + navigation/resource
// timings. Structured form is explicit-and-future-proof; the
// posthog-js default `capture_performance: true` enables the
// same things but using the object form means we can prune
// metrics here if a specific one ever turns out to be
// expensive at scale.
capture_performance: {
network_timing: true,
web_vitals: true
},
// CONSENT (audit M-tier): the snippet always runs, but capture
// is gated off by default. The Termly consent-event listener at
// the bottom of calls posthog.opt_in_capturing() once
// the user accepts analytics — so reaching the `loaded:`
// callback below does NOT imply consent. Capture begins only
// after the user accepts (or revokes again, via the listener).
opt_out_capturing_by_default: true,
// Mark the PostHog cookies Secure now that the Rails session is
// also Secure (force_ssl is on in production).
secure_cookie: true,
session_recording: {
recordConsoleLog: true,
// PATIENT DATA SAFETY: this is a diabetes-management app —
// blood-glucose readings, insulin doses, carb counts, diary
// notes about blood-sugar are all PHI under HIPAA-equivalent
// rules. Be explicit about masking rather than relying on
// posthog-js defaults to stay generous.
//
// maskAllInputs is the posthog-js default, but be EXPLICIT
// so a future config refactor can't silently un-mask
// everything by accident.
maskAllInputs: true,
// Per-field masking: any element whose ancestor tree matches
// this selector gets its TEXT contents replaced with ***. Add
// a class anywhere medical data is rendered in a view; the
// sweep in this commit covers the known sites.
maskTextSelector: '.ph-no-capture, [data-ph-no-capture], .diary-cell, .diary-comments, .pm-body, .carb-amount, .insulin-dose, .blood-glucose, .user-bio',
// Hard-block selector: matched elements are removed from the
// recording entirely (not just masked). Reserve for whole
// sub-trees we never want a frame of (signup form, password
// reset form etc.).
blockSelector: '.ph-block, [data-ph-block]'
},
loaded: function(posthog) {
// CONSENT: reaching this callback does NOT imply consent —
// the snippet runs unconditionally now. The Termly consent-
// event listener at the bottom of is the sole source
// of truth for opt_in/opt_out. Run identify and group
// unconditionally though, because identify itself does not
// emit a network call until capture is opted in; PostHog
// queues the data and flushes it on the first capture call.
}
});