Clarity
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,10 +49,13 @@ 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=
|
||||||
TIKTOK_REDIRECT_URI=https://qrmaster.net/api/tiktok/callback
|
TIKTOK_REDIRECT_URI=https://qrmaster.net/api/tiktok/callback
|
||||||
# Optional: protects /api/tiktok/connect from being triggered by strangers
|
# Optional: protects /api/tiktok/connect from being triggered by strangers
|
||||||
TIKTOK_ADMIN_KEY=
|
TIKTOK_ADMIN_KEY=
|
||||||
TIKTOK_EXPECTED_OPEN_ID=
|
TIKTOK_EXPECTED_OPEN_ID=
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export default function PrivacyPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 className="text-4xl font-bold text-gray-900 mb-4">Privacy Policy</h1>
|
<h1 className="text-4xl font-bold text-gray-900 mb-4">Privacy Policy</h1>
|
||||||
<p className="text-gray-600 mb-8">Last updated: August 2026</p>
|
<p className="text-gray-600 mb-8">Last updated: August 2026</p>
|
||||||
|
|
||||||
<div className="prose prose-lg max-w-none">
|
<div className="prose prose-lg max-w-none">
|
||||||
<section className="mb-8">
|
<section className="mb-8">
|
||||||
@@ -38,20 +38,20 @@ export default function PrivacyPage() {
|
|||||||
We implement appropriate security measures including secure HTTPS transmission, password hashing, database access controls,
|
We implement appropriate security measures including secure HTTPS transmission, password hashing, database access controls,
|
||||||
and CSRF protection to keep your data safe.
|
and CSRF protection to keep your data safe.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-4">2. Chrome Extension</h2>
|
|
||||||
<p className="text-gray-700 mb-4">
|
|
||||||
The QR Master: QR Code for Current Tab Chrome extension processes the active tab URL and the URL, text, Wi-Fi, or vCard details you enter only to create a QR code in the extension popup. This information is processed locally in your browser, is not stored by the extension, and is not transmitted to QR Master or third parties.
|
|
||||||
</p>
|
|
||||||
<p className="text-gray-700 mb-4">
|
|
||||||
The extension uses clipboard access only after you select Copy Image, so that it can copy the generated QR code image to your device clipboard. We do not sell, share, or use extension input data for advertising, analytics, profiling, or creditworthiness decisions.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
<section className="mb-8">
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-4">3. Information We Collect</h2>
|
<h2 className="text-2xl font-bold text-gray-900 mb-4">2. Chrome Extension</h2>
|
||||||
|
<p className="text-gray-700 mb-4">
|
||||||
|
The QR Master: QR Code for Current Tab Chrome extension processes the active tab URL and the URL, text, Wi-Fi, or vCard details you enter only to create a QR code in the extension popup. This information is processed locally in your browser, is not stored by the extension, and is not transmitted to QR Master or third parties.
|
||||||
|
</p>
|
||||||
|
<p className="text-gray-700 mb-4">
|
||||||
|
The extension uses clipboard access only after you select Copy Image, so that it can copy the generated QR code image to your device clipboard. We do not sell, share, or use extension input data for advertising, analytics, profiling, or creditworthiness decisions.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-4">3. Information We Collect</h2>
|
||||||
|
|
||||||
<h3 className="text-xl font-semibold text-gray-900 mb-3">Information You Provide</h3>
|
<h3 className="text-xl font-semibold text-gray-900 mb-3">Information You Provide</h3>
|
||||||
<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">
|
||||||
@@ -64,12 +64,12 @@ 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>
|
||||||
|
|
||||||
<section className="mb-8">
|
<section className="mb-8">
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-4">4. How We Use Your Information</h2>
|
<h2 className="text-2xl font-bold text-gray-900 mb-4">4. How We Use Your Information</h2>
|
||||||
<p className="text-gray-700 mb-4">We use your data to:</p>
|
<p className="text-gray-700 mb-4">We use your data to:</p>
|
||||||
<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>Provide and maintain our QR code services</li>
|
<li>Provide and maintain our QR code services</li>
|
||||||
@@ -85,11 +85,12 @@ export default function PrivacyPage() {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mb-8">
|
<section className="mb-8">
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-4">5. Data Sharing</h2>
|
<h2 className="text-2xl font-bold text-gray-900 mb-4">5. Data Sharing</h2>
|
||||||
<p className="text-gray-700 mb-4">We may share your data with:</p>
|
<p className="text-gray-700 mb-4">We may share your data with:</p>
|
||||||
<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>
|
||||||
@@ -99,7 +100,7 @@ export default function PrivacyPage() {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mb-8">
|
<section className="mb-8">
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-4">6. Your Rights (GDPR)</h2>
|
<h2 className="text-2xl font-bold text-gray-900 mb-4">6. Your Rights (GDPR)</h2>
|
||||||
<p className="text-gray-700 mb-4">You have the right to:</p>
|
<p className="text-gray-700 mb-4">You have the right to:</p>
|
||||||
<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>Access:</strong> Request a copy of your personal data</li>
|
<li><strong>Access:</strong> Request a copy of your personal data</li>
|
||||||
@@ -122,7 +123,7 @@ export default function PrivacyPage() {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mb-8">
|
<section className="mb-8">
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-4">7. Contact Us</h2>
|
<h2 className="text-2xl font-bold text-gray-900 mb-4">7. Contact Us</h2>
|
||||||
<p className="text-gray-700 mb-4">
|
<p className="text-gray-700 mb-4">
|
||||||
If you have questions about this privacy policy, please contact us:
|
If you have questions about this privacy policy, please contact us:
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()) }}
|
||||||
|
|||||||
@@ -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()) }}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
27
src/components/analytics/MicrosoftClarity.tsx
Normal file
27
src/components/analytics/MicrosoftClarity.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user