This commit is contained in:
2026-08-11 21:50:42 +02:00
parent bec48ab8e1
commit ca1e432f80
9 changed files with 65 additions and 22 deletions

View File

@@ -6,6 +6,12 @@
"runtimeExecutable": "npm", "runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"], "runtimeArgs": ["run", "dev"],
"port": 3050 "port": 3050
},
{
"name": "dev-node",
"runtimeExecutable": "node",
"runtimeArgs": ["node_modules/next/dist/bin/next", "dev", "-p", "3050"],
"port": 3050
} }
] ]
} }

View File

@@ -49,6 +49,9 @@ NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
NEXT_PUBLIC_POSTHOG_KEY= NEXT_PUBLIC_POSTHOG_KEY=
NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com
# Analytics (Optional - Microsoft Clarity session recordings & heatmaps)
NEXT_PUBLIC_CLARITY_PROJECT_ID=
# TikTok Content Posting API (Hermes Agent automated posting) # TikTok Content Posting API (Hermes Agent automated posting)
TIKTOK_CLIENT_KEY= TIKTOK_CLIENT_KEY=
TIKTOK_CLIENT_SECRET= TIKTOK_CLIENT_SECRET=

View File

@@ -36,7 +36,7 @@ export default function CookiePolicyPage() {
<h2 className="text-2xl font-bold text-gray-900 mb-4">How We Use Cookies</h2> <h2 className="text-2xl font-bold text-gray-900 mb-4">How We Use Cookies</h2>
<ul className="list-disc pl-6 space-y-2"> <ul className="list-disc pl-6 space-y-2">
<li><strong>Essential Cookies:</strong> Required for the website to function (e.g., login, session management).</li> <li><strong>Essential Cookies:</strong> Required for the website to function (e.g., login, session management).</li>
<li><strong>Analytics Cookies (Optional):</strong> We use tools like PostHog to understand how you use the site and improve it. These are only set with your consent.</li> <li><strong>Analytics Cookies (Optional):</strong> We use tools like PostHog and Microsoft Clarity (session recordings, heatmaps) to understand how you use the site and improve it. These are only set with your consent.</li>
<li><strong>Functionality Cookies:</strong> To remember your preferences.</li> <li><strong>Functionality Cookies:</strong> To remember your preferences.</li>
</ul> </ul>
</section> </section>

View File

@@ -64,7 +64,7 @@ export default function PrivacyPage() {
<ul className="list-disc pl-6 mb-4 text-gray-700 space-y-2"> <ul className="list-disc pl-6 mb-4 text-gray-700 space-y-2">
<li><strong>Usage Data:</strong> QR code scans and analytics</li> <li><strong>Usage Data:</strong> QR code scans and analytics</li>
<li><strong>Technical Data:</strong> IP address, browser type, and device information</li> <li><strong>Technical Data:</strong> IP address, browser type, and device information</li>
<li><strong>Cookies:</strong> Essential cookies for authentication and optional analytics cookies (PostHog) with your consent</li> <li><strong>Cookies:</strong> Essential cookies for authentication and optional analytics cookies (PostHog, Microsoft Clarity) with your consent</li>
</ul> </ul>
</section> </section>
@@ -90,6 +90,7 @@ export default function PrivacyPage() {
<ul className="list-disc pl-6 mb-4 text-gray-700 space-y-2"> <ul className="list-disc pl-6 mb-4 text-gray-700 space-y-2">
<li><strong>Stripe:</strong> Payment processing</li> <li><strong>Stripe:</strong> Payment processing</li>
<li><strong>PostHog:</strong> Analytics (only with your consent, respects Do Not Track)</li> <li><strong>PostHog:</strong> Analytics (only with your consent, respects Do Not Track)</li>
<li><strong>Microsoft Clarity:</strong> Session recordings and heatmaps (only with your consent)</li>
<li><strong>Vercel:</strong> Cloud hosting provider</li> <li><strong>Vercel:</strong> Cloud hosting provider</li>
<li><strong>Legal Requirements:</strong> When required by law</li> <li><strong>Legal Requirements:</strong> When required by law</li>
</ul> </ul>

View File

@@ -5,6 +5,7 @@ import '@/styles/globals.css';
import { Providers } from '@/components/Providers'; import { Providers } from '@/components/Providers';
import AdSenseScript from '@/components/ads/AdSenseScript'; import AdSenseScript from '@/components/ads/AdSenseScript';
import FacebookPixel from '@/components/analytics/FacebookPixel'; import FacebookPixel from '@/components/analytics/FacebookPixel';
import MicrosoftClarity from '@/components/analytics/MicrosoftClarity';
const isIndexable = process.env.NEXT_PUBLIC_INDEXABLE === 'true'; const isIndexable = process.env.NEXT_PUBLIC_INDEXABLE === 'true';
@@ -65,6 +66,7 @@ export default function RootLayout({
<Suspense fallback={null}> <Suspense fallback={null}>
<FacebookPixel /> <FacebookPixel />
</Suspense> </Suspense>
<MicrosoftClarity />
{children} {children}
{process.env.NEXT_PUBLIC_UMAMI_SRC && process.env.NEXT_PUBLIC_UMAMI_ID && ( {process.env.NEXT_PUBLIC_UMAMI_SRC && process.env.NEXT_PUBLIC_UMAMI_ID && (
<Script <Script

View File

@@ -5,6 +5,7 @@ import { Providers } from '@/components/Providers';
import MarketingDeLayout from '@/components/marketing/MarketingDeLayout'; import MarketingDeLayout from '@/components/marketing/MarketingDeLayout';
import { organizationSchema, websiteSchema } from '@/lib/schema'; import { organizationSchema, websiteSchema } from '@/lib/schema';
import FacebookPixel from '@/components/analytics/FacebookPixel'; import FacebookPixel from '@/components/analytics/FacebookPixel';
import MicrosoftClarity from '@/components/analytics/MicrosoftClarity';
export const metadata: Metadata = { export const metadata: Metadata = {
title: { title: {
@@ -68,6 +69,7 @@ export default function MarketingDeGroupLayout({
<Suspense fallback={null}> <Suspense fallback={null}>
<Providers> <Providers>
<FacebookPixel /> <FacebookPixel />
<MicrosoftClarity />
<script <script
type="application/ld+json" type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationSchema()) }} dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationSchema()) }}

View File

@@ -5,6 +5,7 @@ import { Providers } from '@/components/Providers';
import MarketingDeLayout from '@/components/marketing/MarketingDeLayout'; import MarketingDeLayout from '@/components/marketing/MarketingDeLayout';
import { organizationSchema, websiteSchema } from '@/lib/schema'; import { organizationSchema, websiteSchema } from '@/lib/schema';
import FacebookPixel from '@/components/analytics/FacebookPixel'; import FacebookPixel from '@/components/analytics/FacebookPixel';
import MicrosoftClarity from '@/components/analytics/MicrosoftClarity';
export const metadata: Metadata = { export const metadata: Metadata = {
title: { title: {
@@ -60,6 +61,7 @@ export default function GermanRootLayout({
<Suspense fallback={null}> <Suspense fallback={null}>
<Providers> <Providers>
<FacebookPixel /> <FacebookPixel />
<MicrosoftClarity />
<script <script
type="application/ld+json" type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationSchema()) }} dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationSchema()) }}

View File

@@ -67,7 +67,7 @@ export default function CookieBanner() {
<svg className="w-3.5 h-3.5 text-primary-600 mr-1.5" fill="currentColor" viewBox="0 0 20 20"> <svg className="w-3.5 h-3.5 text-primary-600 mr-1.5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" /> <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg> </svg>
<span className="text-gray-700"><strong>Analytics:</strong> PostHog & Google Analytics</span> <span className="text-gray-700"><strong>Analytics:</strong> PostHog, Microsoft Clarity & Google Analytics</span>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,27 @@
'use client';
import { useEffect, useState } from 'react';
import Script from 'next/script';
export default function MicrosoftClarity() {
const [consented, setConsented] = useState(false);
const projectId = process.env.NEXT_PUBLIC_CLARITY_PROJECT_ID;
useEffect(() => {
// Check consent (same gate as PostHog / Facebook Pixel)
const cookieConsent = localStorage.getItem('cookieConsent');
if (cookieConsent === 'accepted') setConsented(true);
}, []);
if (!projectId || !consented) return null;
return (
<Script id="ms-clarity" strategy="afterInteractive">
{`(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "${projectId}");`}
</Script>
);
}