Lantunnel
Install Lantunnel Client on each participating device to access your whole LAN from anywhere with P2P-first low-latency routing, encrypted transport, and relay fallback without port forwarding.
翻译准备中
制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Keksmeister is a lightweight cookie consent library built as a Web Component with Shadow DOM encapsulation. It drops into any web application — Angular, React, Vue, Svelte, or plain HTML — without style conflicts or framework dependencies.
Built for footage.one with GDPR/DSGVO compliance as a first-class concern. Live Demo
We evaluated every major open-source consent library and found that none combines all three properties we needed:
| Library | Web Component | Full GDPR Features | Modern ESM + TS |
|---|---|---|---|
| orestbida/cookieconsent | ❌ | ✅ | ✅ |
| Porsche cookie-consent-banner | ✅ | ⚠️ partial | ✅ |
| Klaro | ❌ | ✅ | ❌ |
| tarteaucitron | ❌ | ✅ | ❌ |
| c15t | ❌ | ✅ | ✅ (but Next.js focused) |
| Keksmeister | ✅ | ✅ | ✅ |
data-keksmeister attribute pattern is inspired by Klaro's design.<keksmeister-banner> with Shadow DOM encapsulationdata-keksmeister attribute blocks scripts until consentgtag('consent', 'update', ...) integrationonConsent callback for server-side logging (you own the endpoint), plus an optional minimal file-based logging server in server/ (Bun + Docker, no database)npm install keksmeister
import 'keksmeister';
<keksmeister-banner
privacy-url="/datenschutz"
lang="de"
></keksmeister-banner>
No build step needed. Pick your preferred CDN:
<!-- jsDelivr (recommended) -->
<script type="module" src="https://cdn.jsdelivr.net/npm/keksmeister/dist/keksmeister.min.js"></script>
<!-- or unpkg -->
<script type="module" src="https://unpkg.com/keksmeister/dist/keksmeister.min.js"></script>
<keksmeister-banner
privacy-url="/datenschutz"
lang="de"
></keksmeister-banner>
<keksmeister-trigger position="bottom-left"></keksmeister-trigger>
Pin a specific version for production:
<script type="module" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/keksmeister.min.js"></script>
Browse all available files: keksmeister on jsDelivr
import { KeksmeisterBanner } from 'keksmeister';
const banner = document.querySelector('keksmeister-banner');
banner.config = {
categories: [
{ id: 'essential', label: 'Essential', required: true },
{ id: 'analytics', label: 'Analytics' },
{ id: 'marketing', label: 'Marketing' },
],
privacyUrl: '/datenschutz',
lang: 'de',
revision: '2',
googleConsentMode: true,
onConsent: (record) => {
// Send consent proof to your backend
fetch('/api/consent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(record),
});
},
};
mode)banner.config = {
// ...categories, privacyUrl...
mode: 'opt-in', // default — no cookies until the visitor consents
};
opt-in (default) — all non-essential categories start inactive
until the visitor explicitly consents. Required by DSGVO/ePrivacy.opt-out — all non-essential categories start active, and the
visitor can opt out afterwards. Matches CCPA/CPRA-style "right to opt
out of sale" regimes.⚠️
mode: 'opt-out'is for CCPA-style jurisdictions only — it is unlawful for visitors in the EU/EEA. DSGVO Art. 6(1)(a) + ErwGr 32 and ePrivacy Directive Art. 5(3) require prior, opt-in consent before any non-essential cookie is set; the UK's PECR mirrors this. Only usemode: 'opt-out'for a US-only deployment, or one gated behind a geo-IP check that keeps EU/EEA (and UK) visitors on theopt-indefault. See docs/compliance.md for the full legal background.
DSGVO / TDDDG require you to prove consent. Every ConsentRecord carries the
fields you need for that: a timestamp, the banner revision, the choices, the
method, an action (grant / update / revoke) and a pseudonymous,
cookie-persisted subjectId that ties a visitor's decisions together without
storing any personal data.
You can ship records to your backend in two ways:
onConsent callback — full control, you own the transport (fires on grant/update).logging) — set an endpoint and Keksmeister sends every
decision including revocations via navigator.sendBeacon (so it survives the
navigation after "Accept all"), with a localStorage retry queue for offline/failed
sends:banner.config = {
// ...categories, privacyUrl, revision...
logging: {
endpoint: 'https://consent.example.com/consent',
includeUserAgent: false, // opt-in; raw IP is never sent by the library
},
};
A ready-to-run, database-free endpoint for this is included in
server/ (Bun + Docker; stores each record as a plain JSON
file, ZIP the folder for a regulator export).
See the Consent Proof & Server-Side Logging guide for
the full logging options, audit fields, CORS configuration, and export details.
For how Keksmeister maps to § 25 TDDDG, the DSK Orientierungshilfe, and
the EinwV / § 26 TDDDG boundaries (Keksmeister is a self-hosted library,
not an anerkannter Einwilligungsverwaltungsdienst), see
docs/compliance.md.
data-keksmeister)The blocker now covers every parse-time tracker the EDPB Guidelines
02/2023 v2.0 puts in scope, not just <script>. Same data-keksmeister
attribute, same placeholder pattern (data-src / data-href):
<!-- JS analytics -->
<script type="text/plain" data-keksmeister="analytics" data-src="https://example.com/analytics.js"></script>
<!-- Inline script -->
<script type="text/plain" data-keksmeister="marketing">
// This runs only after marketing consent
</script>
<!-- Tracking pixel (Meta Pixel, 1x1 counter, …) -->
<img data-keksmeister="marketing" data-src="https://example.com/pixel.gif" width="1" height="1" alt="" />
<!-- Embedded widget / map / video -->
<iframe data-keksmeister="marketing" data-src="https://www.youtube.com/embed/…" allowfullscreen></iframe>
<!-- preload / preconnect that fetches a third-party asset -->
<link data-keksmeister="analytics" rel="preload" as="style" data-href="https://example.com/asset.css">
The blocker also handles <source>, <video> and <audio>. <a> is
intentionally not in scope: anchors only fetch on user click.
Many modern analytics libraries (PostHog, Matomo, GA4, etc.) are initialized via JavaScript and have their own opt-in/opt-out APIs. For these, use service adapters instead of script blocking:
import { ConsentManager, ServiceRegistry } from 'keksmeister';
import { createPostHogAdapter } from 'keksmeister/adapters/posthog';
import { createGoogleAnalyticsAdapter } from 'keksmeister/adapters/google-analytics';
import { createMetaPixelAdapter } from 'keksmeister/adapters/meta-pixel';
// PostHog must be initialized with opt_out_capturing_by_default: true
posthog.init('phc_...', {
api_host: 'https://eu.i.posthog.com',
opt_out_capturing_by_default: true,
});
// The banner's ConsentManager is exposed after config is set
const banner = document.querySelector('keksmeister-banner');
const registry = new ServiceRegistry(banner.manager);
// Register adapters — they auto-sync with consent state
registry.register(createPostHogAdapter(posthog));
registry.register(createGoogleAnalyticsAdapter());
registry.register(createMetaPixelAdapter());
| Adapter | Import | Default Category |
|---|---|---|
| PostHog | keksmeister/adapters/posthog | analytics |
| Matomo | keksmeister/adapters/matomo | analytics |
| Google Analytics 4 | keksmeister/adapters/google-analytics | analytics |
| Google Ads | keksmeister/adapters/google-analytics | marketing |
| Meta Pixel | keksmeister/adapters/meta-pixel | marketing |
| Mixpanel | keksmeister/adapters/mixpanel | analytics |
| HubSpot | keksmeister/adapters/hubspot | marketing |
| Plausible | keksmeister/adapters/plausible | analytics |
| TikTok Pixel | keksmeister/adapters/tiktok-pixel | marketing |
Not every tool has a consent API. Some must be blocked from loading entirely until consent is given. Here's a guide for common tools:
| Tool | Approach | Reason |
|---|---|---|
| PostHog | Adapter | Has opt_in_capturing() / opt_out_capturing() API |
| Matomo | Adapter | Has requireConsent / setConsentGiven commands |
| Google Analytics 4 | Adapter | Google Consent Mode v2 (gtag('consent', 'update', ...)) |
| Google Ads | Adapter | Shares Google Consent Mode v2 with GA4 |
| Meta Pixel | Adapter | Has fbq('consent', 'grant') / fbq('consent', 'revoke') |
| Mixpanel | Adapter | Has opt_in_tracking() / opt_out_tracking() API |
| HubSpot | Adapter | Has _hsp.push(['setHubSpotConsent', ...]) queue |
| Plausible | Adapter | Uses localStorage.plausible_ignore flag |
| TikTok Pixel | Adapter | Has ttq.grantConsent() / ttq.revokeConsent() |
| Hotjar | Script Blocking | No consent API — block the script until consent |
| Google Tag Manager | Script Blocking | Load GTM only after consent, or use Consent Mode |
| Clarity (Microsoft) | Script Blocking | No consent API — block the script until consent |
| Intercom | Script Blocking | No granular consent API — block until consent |
| Crisp Chat | Script Blocking | No consent API — block until consent |
| YouTube Embeds | Script Blocking | Use data-keksmeister on the embed script |
| Google Maps | Script Blocking | Block iframe/script until consent |
Rule of thumb: If the tool has a JavaScript API to enable/disable tracking at runtime, use an adapter. If it only works by loading/not loading its script, use script blocking with data-keksmeister.
Script blocking example for Hotjar:
<script type="text/plain" data-keksmeister="analytics">
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:YOUR_ID,hjsv:6};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>
Write your own adapter for any service:
registry.register({
id: 'my-analytics',
category: 'analytics',
onConsent: () => myAnalytics.enable(),
onRevoke: () => myAnalytics.disable(),
});
keksmeister-banner {
--km-primary: #0066cc;
--km-primary-text: #ffffff;
--km-bg: #1a1a1a;
--km-text: #ffffff;
--km-text-secondary: #aaaaaa;
--km-border: #333333;
--km-radius: 12px;
--km-font-family: 'Inter', sans-serif;
}
By default, the banner's "Accept all" (--km-primary) and "Reject all"
(--km-secondary) buttons use different fill colours. Most DPAs accept
this, but the strictest CNIL/Garante readings expect identical colour, not
just identical size — see
Layer-1 button parity
in the compliance guide for how to equalize them with --km-secondary /
--km-secondary-text.
<button onclick="document.querySelector('keksmeister-banner').openSettings()">
Cookie-Einstellungen
</button>
Use the consent engine without the UI:
import { ConsentManager, ScriptBlocker } from 'keksmeister/core';
const manager = new ConsentManager({
categories: [
{ id: 'essential', label: 'Essential', required: true },
{ id: 'analytics', label: 'Analytics' },
],
privacyUrl: '/privacy',
});
const blocker = new ScriptBlocker(manager);
blocker.start();
// Programmatic consent
manager.acceptAll();
manager.isAccepted('analytics'); // true
src/
├── core/ # Headless consent engine (no UI)
│ ├── consent-manager.ts # Consent state machine + EventTarget
│ ├── cookie-store.ts # Cookie read/write with base64 encoding
│ ├── script-blocker.ts # MutationObserver-based script activation
│ ├── service-adapter.ts # ServiceAdapter interface + ServiceRegistry
│ └── types.ts # All TypeScript interfaces
│
├── adapters/ # Built-in service adapters
│ ├── posthog.ts # PostHog opt-in/opt-out
│ ├── matomo.ts # Matomo requireConsent/setCookieConsentGiven
│ ├── google-analytics.ts # GA4 Consent Mode v2 (analytics + ads)
│ ├── meta-pixel.ts # Meta Pixel consent grant/revoke
│ ├── mixpanel.ts # Mixpanel opt-in/opt-out tracking
│ ├── hubspot.ts # HubSpot setHubSpotConsent
│ ├── plausible.ts # Plausible localStorage flag
│ └── tiktok-pixel.ts # TikTok Pixel grantConsent/revokeConsent
│
├── ui/ # Web Component layer
│ ├── keksmeister-banner.ts # <keksmeister-banner> Custom Element
│ └── styles.ts # Shadow DOM CSS with Custom Properties
│
└── i18n/ # Translations
├── de.ts # German (default)
└── en.ts # English
::part() or ::slotted().ConsentManager) is usable headless. Build your own UI if needed.onConsent callback or the built-in logging transport. We keep the library focused but ship an optional, database-free logging server in server/ for those who want a turnkey option.data-keksmeister attribute — Simple, declarative script blocking inspired by Klaro's data-name approach.<script> tags, service adapters for programmatic APIs (PostHog, GA4, etc.). Most real-world setups need both.{ onConsent, onRevoke } interface. Built-in adapters for 9 popular services, easy to extend with custom adapters. Tools without a consent API (Hotjar, Clarity, etc.) should use script blocking instead.(All browsers with Custom Elements v1 + Shadow DOM v1 support)
MIT — footage.one
| Custom Scripts | Script Blocking | Any <script> without its own consent API |