mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat(telemetry): Sentry + PostHog quality pass (#546)
Comprehensive telemetry quality improvements across Sentry and PostHog, grounded in an audit of the live data plus current best-practice research. Sentry: job_id/instance_id tags, operational fingerprinting, PII-safe settings context on bug events, web tag population + extension-noise filtering, an early-crash buffer, http status/method kept on breadcrumbs, and a gated-off-by-default performance-tracing re-enable (tracesSampler that zeroes db/redis/queue-poll root spans + drops the Redis integration) with worker job spans and canonical-host cron monitors. PostHog: history_change SPA pageviews, instance_id super property for fleet rollups, enriched tool_used (formats, byte sizes, is_batch, execution_hint, real error_kind taxonomy), the previously-dead result_saved/batch_processed/ai_bundle_prompted events fired, search click-through, editor + Automate authoring + auth instrumentation, a before_send PII boundary, and minimal opt-in landing-site pageviews.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
---
|
||||
// biome-ignore-all lint/correctness/noUnusedVariables: Astro template consumes these via define:vars + conditional render.
|
||||
// Minimal, opt-in landing analytics. Respects the site's near-zero-client-JS
|
||||
// ethos: no SDK, just a tiny inline $pageview capture to PostHog's endpoint,
|
||||
// and ONLY when PUBLIC_POSTHOG_KEY is set at build time (nothing is emitted to
|
||||
// the page otherwise). This is a STANDALONE acquisition funnel: a self-hosted
|
||||
// app instance mints its own anonymous id, so landing -> app cannot be joined;
|
||||
// correlate landing conversions to fleet growth via the app's instance_started
|
||||
// event instead. To track a CTA, add data-ph="event_name" to the element.
|
||||
const key = import.meta.env.PUBLIC_POSTHOG_KEY;
|
||||
const host = (import.meta.env.PUBLIC_POSTHOG_HOST || "https://us.i.posthog.com").replace(/\/$/, "");
|
||||
---
|
||||
|
||||
{
|
||||
key && (
|
||||
<script is:inline define:vars={{ key, host }}>
|
||||
(function () {
|
||||
try {
|
||||
var id = localStorage.getItem("ph_did");
|
||||
if (!id) {
|
||||
id =
|
||||
(window.crypto && crypto.randomUUID && crypto.randomUUID()) ||
|
||||
Date.now().toString(36) + Math.random().toString(36).slice(2);
|
||||
localStorage.setItem("ph_did", id);
|
||||
}
|
||||
function send(event, props) {
|
||||
var body = JSON.stringify({
|
||||
api_key: key,
|
||||
event: event,
|
||||
distinct_id: id,
|
||||
properties: Object.assign(
|
||||
// origin + pathname only: never the query string (no PII).
|
||||
{ $current_url: location.origin + location.pathname },
|
||||
props || {},
|
||||
),
|
||||
});
|
||||
var url = host + "/capture/";
|
||||
if (navigator.sendBeacon) {
|
||||
navigator.sendBeacon(url, new Blob([body], { type: "application/json" }));
|
||||
} else {
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: body,
|
||||
keepalive: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
send("$pageview");
|
||||
// Opt-in CTA tracking: <a data-ph="download_click"> etc.
|
||||
document.addEventListener("click", function (e) {
|
||||
var el = e.target && e.target.closest ? e.target.closest("[data-ph]") : null;
|
||||
if (el) send(el.getAttribute("data-ph"), {});
|
||||
});
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user