This commit is contained in:
Felix Klement committed 2026-10-09 13:57:19 +02:00
1 parent 52c8f831d1
commit b446132107
8 files changed
+130 -4

No files matched your search

+7 -2
View File
@@ -106,8 +106,13 @@ Environment; see *Contact form* below.
after the alpha mail is sent or on withdrawal. The result pages `/notify/confirmed` and after the alpha mail is sent or on withdrawal. The result pages `/notify/confirmed` and
`/notify/error` are `noindex` and left out of the sitemap. Set the flag to false to bring back `/notify/error` are `noindex` and left out of the sitemap. Set the flag to false to bring back
the full product page. the full product page.
- **Matomo.** The privacy page links to the existing opt-out on `cipher.uber.space`. The tracking - **Matomo.** Production builds load the tracker from the self-hosted Matomo at
snippet itself is not included; add it in `src/layouts/Base.astro` if analytics should continue. `matomo.ciphercell.de` (`src/components/Matomo.astro`, included in `src/layouts/Base.astro`);
URL and site ID are in `src/data/analytics.ts`. It runs without cookies and honours Do Not
Track, as the privacy page states; `astro dev` never loads it. The opt-out on the privacy page
(`src/components/OptOut.astro`) asks the same tracker: opting out stores the one cookie
`mtm_consent_removed`, opting back in deletes it. With Do Not Track, or when a blocker keeps
`matomo.js` from loading, it says that nothing is counted instead of showing the button.
## Insights filter ## Insights filter
+23
View File
@@ -0,0 +1,23 @@
---
/**
* The Matomo tracker: a page view per page, outgoing links and downloads, no cookies, Do Not
* Track honoured. matomo.js loads async from our own Matomo, so it never holds up the page.
*/
import { matomo } from '../data/analytics';
const { url, siteId, enabled } = matomo;
---
{enabled && (
<script is:inline define:vars={{ url, siteId }}>
var _paq = (window._paq = window._paq || []);
_paq.push(['setDoNotTrack', true]);
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
_paq.push(['setTrackerUrl', url + 'matomo.php']);
_paq.push(['setSiteId', siteId]);
var s = document.createElement('script');
s.async = true;
s.src = url + 'matomo.js';
document.head.appendChild(s);
</script>
)}
+63
View File
@@ -0,0 +1,63 @@
---
/**
* The Matomo opt-out on the privacy page, in the site's own type rather than Matomo's embed. It
* asks the tracker already on the page: optUserOut stores the one cookie the tracker keeps with
* cookies disabled (mtm_consent_removed), forgetUserOptOut removes it. If the tracker never
* arrives (a content blocker, or a development build), the page says so: nothing is counted.
*/
import { t, type Lang } from '../i18n/ui';
interface Props { lang: Lang }
const { lang } = Astro.props;
const o = t(lang).legal.optOut;
---
<div class="optout" data-optout data-status-in={o.in} data-status-out={o.out} data-status-dnt={o.dnt} data-status-missing={o.missing} data-label-out={o.stop} data-label-in={o.resume}>
<p class="optout__status" role="status" data-optout-status>{o.checking}</p>
<button class="button button--small" type="button" data-optout-toggle hidden></button>
<noscript><p class="optout__status">{o.noscript}</p></noscript>
</div>
<style>
.optout { display: grid; gap: var(--space-4); justify-items: start; }
.optout__status { color: var(--ink-muted); }
.optout .button { font: inherit; font-size: var(--step-small); font-weight: var(--weight-medium); border: 0; cursor: pointer; }
</style>
<script>
type Tracker = { isUserOptedOut(): boolean; optUserOut(): void; forgetUserOptOut(): void };
type Paq = { push(cmd: unknown[]): void };
const root = document.querySelector<HTMLElement>('[data-optout]');
const status = root?.querySelector<HTMLElement>('[data-optout-status]');
const toggle = root?.querySelector<HTMLButtonElement>('[data-optout-toggle]');
if (root && status && toggle) {
const d = root.dataset;
const dnt = navigator.doNotTrack === '1' || (window as { doNotTrack?: string }).doNotTrack === '1';
let tracker: Tracker | undefined;
const render = () => {
if (dnt) { status.textContent = d.statusDnt!; toggle.hidden = true; return; }
if (!tracker) { status.textContent = d.statusMissing!; toggle.hidden = true; return; }
const out = tracker.isUserOptedOut();
status.textContent = out ? d.statusOut! : d.statusIn!;
toggle.textContent = out ? d.labelIn! : d.labelOut!;
toggle.hidden = false;
};
toggle.addEventListener('click', () => {
if (!tracker) return;
if (tracker.isUserOptedOut()) tracker.forgetUserOptOut(); else tracker.optUserOut();
render();
});
// A function pushed onto _paq runs with the tracker as `this` once matomo.js has loaded.
const paq = (window as { _paq?: Paq })._paq;
if (paq && !dnt) {
paq.push([function (this: Tracker) { tracker = this; render(); }]);
// If it has not arrived in a few seconds, it is blocked or not part of this build.
window.setTimeout(() => { if (!tracker) render(); }, 4000);
} else {
render();
}
}
</script>
+9
View File
@@ -0,0 +1,9 @@
/* Matomo, self-hosted. The tracker runs without cookies and honours Do Not Track; the privacy
page states both, and its opt-out (src/components/OptOut.astro) talks to the same tracker.
Only production builds load it, so local development is never counted. */
export const matomo = {
url: 'https://matomo.ciphercell.de/',
/* The site's ID in Matomo: Administration, Websites, Manage. */
siteId: '1',
enabled: import.meta.env.PROD,
};
+20
View File
@@ -376,6 +376,16 @@ const en = {
mailing: 'Mailing address', mailing: 'Mailing address',
contact: 'Contact', contact: 'Contact',
asOf: 'As of 14 June 2025', asOf: 'As of 14 June 2025',
optOut: {
checking: 'Checking whether your visits are counted.',
in: 'Your visits are counted, anonymously and without cookies.',
out: 'Your visits are not counted. To remember that, this browser keeps one cookie, mtm_consent_removed.',
dnt: 'Your browser sends Do Not Track. Your visits are not counted.',
missing: 'The statistics script is not loaded in this browser, for example because of a content blocker. Your visits are not counted.',
noscript: 'Without JavaScript the statistics script does not run. Your visits are not counted.',
stop: 'Stop counting my visits',
resume: 'Count my visits again',
},
}, },
}; };
@@ -727,6 +737,16 @@ const de: typeof en = {
mailing: 'Postanschrift', mailing: 'Postanschrift',
contact: 'Kontakt', contact: 'Kontakt',
asOf: 'Stand: 14. Juni 2025', asOf: 'Stand: 14. Juni 2025',
optOut: {
checking: 'Es wird geprüft, ob Ihre Besuche gezählt werden.',
in: 'Ihre Besuche werden gezählt, anonymisiert und ohne Cookies.',
out: 'Ihre Besuche werden nicht gezählt. Damit das so bleibt, speichert dieser Browser ein Cookie: mtm_consent_removed.',
dnt: 'Ihr Browser sendet „Do Not Track“. Ihre Besuche werden nicht gezählt.',
missing: 'Das Statistik-Skript ist in diesem Browser nicht geladen, etwa wegen eines Inhaltsblockers. Ihre Besuche werden nicht gezählt.',
noscript: 'Ohne JavaScript läuft das Statistik-Skript nicht. Ihre Besuche werden nicht gezählt.',
stop: 'Besuche nicht mehr zählen',
resume: 'Besuche wieder zählen',
},
}, },
}; };
+2
View File
@@ -2,6 +2,7 @@
import '../styles/base.css'; import '../styles/base.css';
import Header from '../components/Header.astro'; import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro'; import Footer from '../components/Footer.astro';
import Matomo from '../components/Matomo.astro';
import { langFromUrl, switchLang, t, type Lang } from '../i18n/ui'; import { langFromUrl, switchLang, t, type Lang } from '../i18n/ui';
interface Props { interface Props {
@@ -51,6 +52,7 @@ const altDe = new URL(switchLang(Astro.url, 'de'), Astro.site);
<meta property="og:locale" content={lang === 'de' ? 'de_DE' : 'en_GB'} /> <meta property="og:locale" content={lang === 'de' ? 'de_DE' : 'en_GB'} />
<meta name="generator" content={Astro.generator} /> <meta name="generator" content={Astro.generator} />
<script is:inline>document.documentElement.classList.add('js');</script> <script is:inline>document.documentElement.classList.add('js');</script>
<Matomo />
</head> </head>
<body> <body>
<a class="skip-link" href="#main">{ui.nav.skip}</a> <a class="skip-link" href="#main">{ui.nav.skip}</a>
+3 -1
View File
@@ -1,5 +1,6 @@
--- ---
import Legal from '../_Legal.astro'; import Legal from '../_Legal.astro';
import OptOut from '../../components/OptOut.astro';
import { t } from '../../i18n/ui'; import { t } from '../../i18n/ui';
const ui = t('de'); const ui = t('de');
--- ---
@@ -9,7 +10,8 @@ const ui = t('de');
<h2>Webanalyse mit Matomo (ohne Cookies)</h2> <h2>Webanalyse mit Matomo (ohne Cookies)</h2>
<p>Wir verwenden auf unserer Website die Open-Source-Webanalysesoftware Matomo, um das Nutzungsverhalten auf datenschutzfreundliche Weise auszuwerten und unsere Website technisch und inhaltlich zu verbessern. Dabei haben wir Matomo so konfiguriert, dass keine Cookies gesetzt werden und Ihre IP-Adresse anonymisiert gespeichert wird. Es werden keine personenbezogenen Daten verarbeitet, und es erfolgt keine Weitergabe an Dritte. Die Verarbeitung erfolgt auf Grundlage unseres berechtigten Interesses gemäß Art. 6 Abs. 1 lit. f DSGVO an der statistischen Analyse des Nutzerverhaltens zur Optimierung unseres Webangebots. Wenn Ihr Browser die „Do Not Track“-Funktion unterstützt und aktiviert ist, wird Ihr Besuch von Matomo automatisch ignoriert. Sie können der anonymisierten Analyse Ihres Besuchs dennoch jederzeit widersprechen. Nutzen Sie dazu bitte den folgenden Opt-out.</p> <p>Wir verwenden auf unserer Website die Open-Source-Webanalysesoftware Matomo, um das Nutzungsverhalten auf datenschutzfreundliche Weise auszuwerten und unsere Website technisch und inhaltlich zu verbessern. Dabei haben wir Matomo so konfiguriert, dass keine Cookies gesetzt werden und Ihre IP-Adresse anonymisiert gespeichert wird. Es werden keine personenbezogenen Daten verarbeitet, und es erfolgt keine Weitergabe an Dritte. Die Verarbeitung erfolgt auf Grundlage unseres berechtigten Interesses gemäß Art. 6 Abs. 1 lit. f DSGVO an der statistischen Analyse des Nutzerverhaltens zur Optimierung unseres Webangebots. Wenn Ihr Browser die „Do Not Track“-Funktion unterstützt und aktiviert ist, wird Ihr Besuch von Matomo automatisch ignoriert. Sie können der anonymisierten Analyse Ihres Besuchs dennoch jederzeit widersprechen. Nutzen Sie dazu bitte den folgenden Opt-out.</p>
<p><a href="https://cipher.uber.space/matomo/index.php?module=CoreAdminHome&action=optOut&language=de" rel="noopener">Matomo Opt-out</a></p> <p>Der Opt-out speichert ein Cookie, mtm_consent_removed, damit Matomo Ihre Besuche weiterhin ignoriert; es enthält keine Kennung, und sonst wird nichts gespeichert.</p>
<OptOut lang="de" />
<h2>Datensicherheit</h2> <h2>Datensicherheit</h2>
<p>Ihre Nutzerdaten sind bei der Übermittlung auf unsere Server durch den Einsatz von TLS in Verbindung mit einer 256-Bit-Verschlüsselung geschützt. Sie können die Sicherheit der Verbindung anhand der Angaben in der Adresszeile Ihres Browsers prüfen. Beginnt die Adresszeile mit „https“, liegt eine gesicherte Verbindung vor.</p> <p>Ihre Nutzerdaten sind bei der Übermittlung auf unsere Server durch den Einsatz von TLS in Verbindung mit einer 256-Bit-Verschlüsselung geschützt. Sie können die Sicherheit der Verbindung anhand der Angaben in der Adresszeile Ihres Browsers prüfen. Beginnt die Adresszeile mit „https“, liegt eine gesicherte Verbindung vor.</p>
+3 -1
View File
@@ -1,5 +1,6 @@
--- ---
import Legal from './_Legal.astro'; import Legal from './_Legal.astro';
import OptOut from '../components/OptOut.astro';
import { t } from '../i18n/ui'; import { t } from '../i18n/ui';
const ui = t('en'); const ui = t('en');
--- ---
@@ -9,7 +10,8 @@ const ui = t('en');
<h2>Web analytics with Matomo (without cookies)</h2> <h2>Web analytics with Matomo (without cookies)</h2>
<p>We use the open source web analytics software Matomo on our website to evaluate user behavior in a privacy-friendly manner and to improve our website in terms of technology and content. We have configured Matomo so that no cookies are set and your IP address is stored anonymously. No personal data is processed and no data is passed on to third parties. Processing is based on our legitimate interest pursuant to Art. 6 (1) lit. f GDPR in the statistical analysis of user behavior for the purpose of optimizing our website. If your browser supports and has activated the "Do Not Track" function, your visit will be automatically ignored by Matomo. You can still object to the anonymized analysis of your visit at any time. To do so, please use the opt-out below.</p> <p>We use the open source web analytics software Matomo on our website to evaluate user behavior in a privacy-friendly manner and to improve our website in terms of technology and content. We have configured Matomo so that no cookies are set and your IP address is stored anonymously. No personal data is processed and no data is passed on to third parties. Processing is based on our legitimate interest pursuant to Art. 6 (1) lit. f GDPR in the statistical analysis of user behavior for the purpose of optimizing our website. If your browser supports and has activated the "Do Not Track" function, your visit will be automatically ignored by Matomo. You can still object to the anonymized analysis of your visit at any time. To do so, please use the opt-out below.</p>
<p><a href="https://cipher.uber.space/matomo/index.php?module=CoreAdminHome&action=optOut&language=en" rel="noopener">Matomo opt-out</a></p> <p>The opt-out stores one cookie, mtm_consent_removed, so that Matomo keeps ignoring your visits; it contains no identifier and nothing else is stored.</p>
<OptOut lang="en" />
<h2>Data security</h2> <h2>Data security</h2>
<p>Your user data is protected during transmission to our servers through the use of TLS in conjunction with 256-bit encryption. You can check the security of the connection by looking at the information in your browser's address bar. If the beginning of the address line reads "https", the connection is secure.</p> <p>Your user data is protected during transmission to our servers through the use of TLS in conjunction with 256-bit encryption. You can check the security of the connection by looking at the information in your browser's address bar. If the beginning of the address line reads "https", the connection is secure.</p>