analytics: consolidate everything onto one shared Plausible pa- script

All pcbjam properties now load the same new-format Plausible script
(https://plausible.io/js/pa-KjNS9YmidydULZTstsjRg.js — one dashboard,
segment by hostname) instead of per-domain data-domain sites:

- site: replace Vercel Analytics with the pa- snippet in BaseLayout
  (is:inline, prod-only, crossorigin="anonymous" for the COEP
  require-corp routes in vercel.json); drop @vercel/analytics dep.
  Legal pages (cookies/privacy) rewritten Vercel -> Plausible.
- standalone: initAnalytics() rewritten for the new script format
  (queue shim + plausible.init(), async, no data-domain). The gate is
  now VITE_PLAUSIBLE_SRC (script URL, deploy-time opt-in) — unset means
  no tracking, so dev checkouts and third-party GPL builds stay clean.
  VITE_PLAUSIBLE_DOMAIN is gone.
- deploy: build-demo/build-editor --plausible now takes the script URL;
  release.yml/deploy-demo.yml hardcode the (public) pa- URL, so the
  repo Actions variable PLAUSIBLE_DOMAIN is no longer used.

Verified: standalone tsc + vite build (pa- URL present with env, absent
without, crossOrigin kept); astro build has the snippet on all layout
pages and no vercel/insights references; astro dev stays untracked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Istvan Matejcsok 2026-07-15 19:34:09 +02:00
commit 40b53ad530
14 changed files with 116 additions and 95 deletions

View file

@ -42,11 +42,11 @@ VITE_WASM_ROOT=/wasm
# can't follow redirects.
# VITE_WAITLIST_URL=https://www.pcbjam.com/api/waitlist
# Plausible analytics. Unset ⇒ no tracking (dev/checkout default). Set the
# data-domain to enable; override the script URL only if the default plausible.io
# script won't load under COEP require-corp (then self-host/proxy on cdn.pcbjam.com).
# VITE_PLAUSIBLE_DOMAIN=demo.pcbjam.com
# VITE_PLAUSIBLE_SRC=https://plausible.io/js/script.js
# Plausible analytics. Unset ⇒ no tracking (dev/checkout default). Set the shared
# site's pa-*.js script URL to enable (the pa- id keys the dashboard, no
# data-domain). Point it at a self-hosted/proxied copy on cdn.pcbjam.com if the
# plausible.io script won't load under COEP require-corp.
# VITE_PLAUSIBLE_SRC=https://plausible.io/js/pa-KjNS9YmidydULZTstsjRg.js
# Where a backend project's DOCUMENT content lives ("api" default | "ydoc").
# Same /p/<project> URLs either way. "api": file bytes come from the REST

View file

@ -1,10 +1,18 @@
import { PLAUSIBLE_DOMAIN, PLAUSIBLE_SRC } from "./config";
import { PLAUSIBLE_SRC } from "./config";
type PlausibleShim = {
(...args: unknown[]): void;
q?: unknown[][];
init?: (options?: object) => void;
o?: object;
};
/**
* Inject the Plausible analytics script when a domain is configured
* (VITE_PLAUSIBLE_DOMAIN). No-op otherwise, so a plain dev checkout — and any
* deploy that doesn't set the var — stays untracked. Cookieless + privacy-
* friendly, so no consent banner is required.
* Inject the Plausible analytics script when a script URL is configured
* (VITE_PLAUSIBLE_SRC, the site's pa-*.js URL — the pa- id keys the shared
* dashboard, so no data-domain). No-op otherwise, so a plain dev checkout —
* and any deploy that doesn't set the var — stays untracked. Cookieless +
* privacy-friendly, so no consent banner is required.
*
* `crossorigin="anonymous"` is required because the demo is served cross-origin
* isolated (COEP `require-corp`): a third-party script must be fetched with CORS.
@ -12,11 +20,24 @@ import { PLAUSIBLE_DOMAIN, PLAUSIBLE_SRC } from "./config";
* at a self-hosted/proxied copy on cdn.pcbjam.com (which sets CORP).
*/
export function initAnalytics(): void {
if (!PLAUSIBLE_DOMAIN || typeof document === "undefined") return;
if (!PLAUSIBLE_SRC || typeof document === "undefined") return;
if (document.querySelector("script[data-pcbjam-analytics]")) return;
// Official queue shim: buffers plausible() calls until the script loads.
const w = window as Window & { plausible?: PlausibleShim };
const p: PlausibleShim =
w.plausible ||
((...args: unknown[]) => {
(p.q = p.q || []).push(args);
});
p.init =
p.init ||
((options?: object) => {
p.o = options || {};
});
w.plausible = p;
p.init();
const s = document.createElement("script");
s.defer = true;
s.setAttribute("data-domain", PLAUSIBLE_DOMAIN);
s.async = true;
s.setAttribute("data-pcbjam-analytics", "");
s.crossOrigin = "anonymous";
s.src = PLAUSIBLE_SRC;

View file

@ -61,15 +61,14 @@ export const WAITLIST_URL =
import.meta.env.VITE_WAITLIST_URL || "https://www.pcbjam.com/api/waitlist";
/**
* Plausible analytics (privacy-friendly, cookieless). Off unless a domain is set
* (plain dev/checkout stays untracked). `PLAUSIBLE_DOMAIN` is the `data-domain`
* the dashboard is keyed by; `PLAUSIBLE_SRC` is the script URL (override to a
* self-hosted/proxied script — e.g. on cdn.pcbjam.com — if plausible.io won't
* load under the demo's COEP `require-corp`). See main.tsx for the injection.
* Plausible analytics (privacy-friendly, cookieless). Off unless a script URL is
* set (plain dev/checkout stays untracked). `PLAUSIBLE_SRC` is the shared site's
* pa-*.js script URL — the pa- id keys the dashboard, no data-domain needed.
* Point it at a self-hosted/proxied copy — e.g. on cdn.pcbjam.com — if
* plausible.io won't load under the demo's COEP `require-corp`. See main.tsx
* for the injection.
*/
export const PLAUSIBLE_DOMAIN = import.meta.env.VITE_PLAUSIBLE_DOMAIN || null;
export const PLAUSIBLE_SRC =
import.meta.env.VITE_PLAUSIBLE_SRC || "https://plausible.io/js/script.js";
export const PLAUSIBLE_SRC = import.meta.env.VITE_PLAUSIBLE_SRC || null;
/**
* Where the standalone reads PROJECTS from (env VITE_PROJECT_SOURCE):

View file

@ -5,7 +5,7 @@ import App from "./App";
import { initAnalytics } from "./lib/analytics";
import "./index.css";
// Privacy-friendly analytics (Plausible), only when VITE_PLAUSIBLE_DOMAIN is set.
// Privacy-friendly analytics (Plausible), only when VITE_PLAUSIBLE_SRC is set.
initAnalytics();
const queryClient = new QueryClient({

View file

@ -30,6 +30,8 @@ interface ImportMetaEnv {
readonly VITE_YJS_ENDPOINT?: string;
/** Optional connection token for the collab provider. */
readonly VITE_YJS_TOKEN?: string;
/** Plausible pa-*.js script URL; unset ⇒ no tracking (dev default). */
readonly VITE_PLAUSIBLE_SRC?: string;
}
interface ImportMeta {