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

54
site/package-lock.json generated
View file

@ -11,7 +11,6 @@
"@astrojs/mdx": "^6.0.3",
"@astrojs/vercel": "^10.0.8",
"@fontsource/oswald": "^5.2.8",
"@vercel/analytics": "^2.0.1",
"astro": "^6.4.4",
"resend": "^6.12.4"
},
@ -2304,48 +2303,6 @@
"integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==",
"license": "ISC"
},
"node_modules/@vercel/analytics": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-2.0.1.tgz",
"integrity": "sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g==",
"license": "MIT",
"peerDependencies": {
"@remix-run/react": "^2",
"@sveltejs/kit": "^1 || ^2",
"next": ">= 13",
"nuxt": ">= 3",
"react": "^18 || ^19 || ^19.0.0-rc",
"svelte": ">= 4",
"vue": "^3",
"vue-router": "^4"
},
"peerDependenciesMeta": {
"@remix-run/react": {
"optional": true
},
"@sveltejs/kit": {
"optional": true
},
"next": {
"optional": true
},
"nuxt": {
"optional": true
},
"react": {
"optional": true
},
"svelte": {
"optional": true
},
"vue": {
"optional": true
},
"vue-router": {
"optional": true
}
}
},
"node_modules/@vercel/cli-config": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@vercel/cli-config/-/cli-config-0.2.0.tgz",
@ -4327,6 +4284,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4347,6 +4305,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4367,6 +4326,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4387,6 +4347,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4407,6 +4368,7 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4427,6 +4389,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4447,6 +4410,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4467,6 +4431,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4487,6 +4452,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4507,6 +4473,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@ -4527,6 +4494,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [

View file

@ -17,7 +17,6 @@
"@astrojs/mdx": "^6.0.3",
"@astrojs/vercel": "^10.0.8",
"@fontsource/oswald": "^5.2.8",
"@vercel/analytics": "^2.0.1",
"astro": "^6.4.4",
"resend": "^6.12.4"
},

View file

@ -1,7 +1,7 @@
---
title: Cookie Policy
description: How PCBJam uses cookies and similar technologies, and the choices you have.
updated: 2026-06-10
updated: 2026-07-15
---
This Cookie Policy explains how **PCBJam** ("PCBJam", "we", "us", "our") uses cookies and similar technologies — such as browser local storage, IndexedDB and cache storage — when you visit **pcbjam.com** or use the PCBJam application (the "Service"), and the choices you have.
@ -84,11 +84,11 @@ If you buy a paid plan, checkout is handled by **Paddle** as our **Merchant of R
## 5. Analytics: how we measure usage without cookies
We want to understand how PCBJam is used so we can improve it, **without tracking you.** We use **Vercel Web Analytics**. According to Vercel's documentation (as revised 18 March 2026), and confirmed by our own inspection of the analytics script as currently shipped on this site, it:
We want to understand how PCBJam is used so we can improve it, **without tracking you.** We use **Plausible Analytics**, an EU-based, open-source, privacy-first analytics service operated by Plausible Insights OÜ. According to Plausible's [data policy](https://plausible.io/data-policy), and confirmed by our own inspection of the analytics script as currently shipped on this site, it:
- sets **no cookie** and stores **no identifier** on your device — visitors are counted using a **hash created from the incoming request**, and the script uses no cookies, local storage, or other device storage;
- does **not** keep that visitor hash — it is **automatically discarded after 24 hours**;
- records **anonymous, aggregated** data points (such as page URL, referrer, approximate location, browser and device type) that are **not** used to build a profile of you or to follow you across other sites.
- does **not** keep a persistent visitor identifier — the hash is generated with a salt that is **rotated and deleted every 24 hours**, so you cannot be recognised from one day to the next, and your raw IP address is not stored;
- records **anonymous, aggregated** data points (such as page URL, referrer, approximate location, browser and device type) that are **not** used to build a profile of you or to follow you across other sites, and the data is **stored on servers in the EU**.
Because it stores nothing on your device and the data it records cannot identify you, **we consider that this measurement does not require your prior consent**, and it is not part of any consent banner.
@ -99,7 +99,8 @@ We do **not** use Google Analytics, advertising pixels, or any cross-site tracki
| Third party | Role | What they may set | Their notice |
|---|---|---|---|
| **Paddle** (Paddle.com Market Limited and affiliates) | Merchant of Record / payments | Checkout, security and fraud-prevention cookies; their own non-essential cookies (with consent where required, via Paddle's own controls). Independent controller. | [Paddle Privacy Policy](https://www.paddle.com/legal/privacy); Paddle's cookie controls appear within its checkout. |
| **Vercel** (Vercel Inc.) | Hosting and cookieless analytics | No analytics cookies (cookieless, see Section 5); at most strictly-necessary hosting cookies. | [Vercel Analytics privacy](https://vercel.com/docs/analytics/privacy-policy) · [Vercel Privacy](https://vercel.com/legal/privacy-policy) |
| **Plausible** (Plausible Insights OÜ) | Cookieless analytics | Nothing — no cookies and no device storage (see Section 5). | [Plausible Data Policy](https://plausible.io/data-policy) · [Plausible Privacy](https://plausible.io/privacy) |
| **Vercel** (Vercel Inc.) | Hosting | At most strictly-necessary hosting cookies. | [Vercel Privacy](https://vercel.com/legal/privacy-policy) |
We are not responsible for the privacy practices of these third parties; please review their notices. We update this list as our integrations change.

View file

@ -1,7 +1,7 @@
---
title: Privacy Policy
description: How PCBJam handles your personal data.
updated: 2026-06-10
updated: 2026-07-15
---
## 1. A quick summary
@ -11,7 +11,7 @@ This summary is here to help you understand our practices at a glance. It is **n
- **Who we are.** PCBJam is a browser-based PCB-design application (built on the open-source KiCad EDA toolchain) operated by Emergence-Engineering Kft. ("PCBJam", "we", "us"). We are the **data controller** for the personal data described here.
- **What we collect.** The email address you give us when you join the waitlist, account details, the projects and design files you create or upload, limited technical and usage data, your communications with us, and — if you buy a paid plan — limited transaction data from our payment provider.
- **Your design files.** Your projects are **private by default.** We process them on our servers only to run the service you ask for (storage, rendering, design-rule checks, compiling, exports, and the collaboration/sharing you choose to enable). We do not sell them and we do not use their contents to advertise to you.
- **Analytics.** We use **Vercel Web Analytics, which is cookieless and does not track you across other websites.** It does not build an advertising profile of you.
- **Analytics.** We use **Plausible Analytics, which is cookieless and does not track you across other websites.** It does not build an advertising profile of you.
- **Payments** are handled by **Paddle**, which acts as the "Merchant of Record" and an **independent data controller** for your payment information (see §8).
- **Your rights.** You can access, correct, export, or delete your data, object to certain processing, and withdraw consent at any time. EU/UK users can complain to a data-protection regulator; California users have specific rights under the CCPA (see §13).
- **Contact.** contact@emergence-engineering.com (or hello@pcbjam.com).
@ -102,13 +102,13 @@ Where we rely on **legitimate interests**, we have weighed our interests against
## 6. Analytics — and why we don't track you
We use **Vercel Web Analytics** to understand how PCBJam is used so we can improve it. According to Vercel, this product is **cookieless** and privacy-focused:
We use **Plausible Analytics** (Plausible Insights OÜ, an EU company) to understand how PCBJam is used so we can improve it. According to Plausible, this product is **cookieless** and privacy-focused:
- it does **not** use third-party cookies; instead, visitors are counted using a **hash generated from the incoming request**, which is **automatically discarded after 24 hours**;
- it does **not** collect identifiers that **track or cross-check you across different applications or websites**, and it is **not tied to your IP address**;
- the data is **anonymous and aggregated** — page views, approximate location, device/OS/browser type, and referrer.
- it does **not** use cookies or any other device storage; instead, visitors are counted using a **hash generated from the incoming request**, with a salt that is **rotated and deleted every 24 hours**, so no persistent identifier exists;
- it does **not** collect identifiers that **track or cross-check you across different applications or websites**, and your **raw IP address is not stored**;
- the data is **anonymous and aggregated** — page views, approximate location, device/OS/browser type, and referrer — and is **stored on servers in the EU**.
Because this analytics does **not** involve cross-context behavioural advertising or cross-site tracking, **we do not consider it a "sale" or "sharing" of personal information** under California law (see §13). Vercel acts as our **processor** for this analytics. See Vercel's [analytics privacy documentation](https://vercel.com/docs/analytics/privacy-policy) and [Data Processing Addendum](https://vercel.com/legal/dpa).
Because this analytics does **not** involve cross-context behavioural advertising or cross-site tracking, **we do not consider it a "sale" or "sharing" of personal information** under California law (see §13). Plausible acts as our **processor** for this analytics. See Plausible's [data policy](https://plausible.io/data-policy) and [Data Processing Agreement](https://plausible.io/dpa).
---
@ -142,7 +142,8 @@ We do **not** sell your personal data. We share it only with the following categ
| Recipient | What they do | Their role | More info |
|---|---|---|---|
| **Vercel** | Hosting/infrastructure and cookieless web analytics | **Processor** | [Vercel DPA](https://vercel.com/legal/dpa) · [Privacy](https://vercel.com/legal/privacy-policy) |
| **Vercel** | Hosting/infrastructure | **Processor** | [Vercel DPA](https://vercel.com/legal/dpa) · [Privacy](https://vercel.com/legal/privacy-policy) |
| **Plausible** | Cookieless web analytics | **Processor** | [Plausible DPA](https://plausible.io/dpa) · [Data policy](https://plausible.io/data-policy) |
| **Paddle** | Payments / Merchant of Record | **Independent controller** (for payment data) | [Paddle Privacy](https://www.paddle.com/legal/privacy) |
| **Resend** | Sending transactional and marketing email | **Processor** | [Resend DPA](https://resend.com/legal/dpa) · [Subprocessors](https://resend.com/legal/subprocessors) |
| **Cloudflare** | Storing your project files (R2 object storage), hosting application/account data, and network delivery & security (CDN, DNS, WAF) | **Processor** | [Cloudflare DPA](https://www.cloudflare.com/cloudflare-customer-dpa/) · [GDPR hub](https://www.cloudflare.com/trust-hub/gdpr/) |

View file

@ -2,7 +2,6 @@
import { ClientRouter } from 'astro:transitions';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import Analytics from '@vercel/analytics/astro';
import '../styles/global.css';
interface Props {
@ -63,6 +62,38 @@ const ogImageAbs = new URL(ogImage, Astro.site ?? Astro.url).href;
{/* SPA-style navigation: swaps the page without a full reload. */}
<ClientRouter />
{/* Privacy-friendly analytics by Plausible (cookieless, no consent banner
needed). The pa- script id keys the shared dashboard covering all
pcbjam properties. Prod builds only — `astro dev` stays untracked, and
Plausible ignores localhost regardless. Auto-tracks pageviews across
ClientRouter navigations (History API). crossorigin="anonymous" so the
script still loads on the COEP require-corp routes (see vercel.json):
cross-origin subresources there must be fetched with CORS. */}
{
import.meta.env.PROD && (
<>
<script
is:inline
async
crossorigin="anonymous"
src="https://plausible.io/js/pa-KjNS9YmidydULZTstsjRg.js"></script>
<script is:inline>
window.plausible =
window.plausible ||
function () {
(plausible.q = plausible.q || []).push(arguments);
};
plausible.init =
plausible.init ||
function (i) {
plausible.o = i || {};
};
plausible.init();
</script>
</>
)
}
</head>
<body>
<Header />
@ -80,6 +111,5 @@ const ogImageAbs = new URL(ogImage, Astro.site ?? Astro.url).href;
)
}
<Footer />
<Analytics />
</body>
</html>