Privacy & Compliance
MentiQ Analytics is designed with privacy in mind, providing built-in features to help you comply with GDPR, CCPA, and other privacy regulations while still collecting valuable analytics data.
Privacy Features Overview
MentiQ provides multiple layers of privacy protection:
Session Recording Privacy - CSS class-based masking for sensitive content
PCI Compliance - Automatic sanitization of payment data
Subscription Data Validation - Removes sensitive payment information
User Data Control - Easy user identification and reset
No Automatic PII Collection - You control what data is tracked
Session Recording Privacy
When using session recording, protect sensitive data with CSS classes:
Privacy CSS Classes
.mentiq-block
.mentiq-mask
.mentiq-ignore
Completely block elements from recording < input
type = "password"
className = "mentiq-block"
placeholder = "Password"
/>
Element and all children are not recorded at all - appears as blank space in replays. Use for:
Password inputs
Credit card fields
SSN or sensitive ID numbers
Private user data
Mask text content while preserving layout < div className = "mentiq-mask" >
User's private information
</ div >
Text is replaced with asterisks (*****) but layout/structure is preserved. Use for:
Email addresses
Phone numbers
Personal names in certain contexts
Account numbers
Ignore element and children from recording < section className = "mentiq-ignore" >
< h2 > Private Section </ h2 >
< p > This entire section won't be recorded </ p >
</ section >
Similar to .mentiq-block but may have different behavior in some recording libraries. Use for:
Admin panels
Private messaging
Internal tools
Confidential reports
Complete Privacy Example
components/PaymentForm.tsx
'use client' ;
import { useState } from "react" ;
import { useAnalytics } from "mentiq-sdk" ;
export function PaymentForm () {
const { track } = useAnalytics ();
const [ cardNumber , setCardNumber ] = useState ( "" );
const handleSubmit = ( e : React . FormEvent ) => {
e . preventDefault ();
// Track payment initiation (no sensitive data)
track ( "payment_submitted" , {
payment_method: "card" ,
card_brand: detectCardBrand ( cardNumber ), // Generic info only
// Never include full card number!
});
};
return (
< form onSubmit = { handleSubmit } >
< div >
< label htmlFor = "name" > Name on Card </ label >
< input
id = "name"
type = "text"
className = "mentiq-mask" // Mask the name
/>
</ div >
< div >
< label htmlFor = "card" > Card Number </ label >
< input
id = "card"
type = "text"
className = "mentiq-block" // Block completely
value = { cardNumber }
onChange = { ( e ) => setCardNumber ( e . target . value ) }
/>
</ div >
< div >
< label htmlFor = "cvv" > CVV </ label >
< input
id = "cvv"
type = "text"
className = "mentiq-block" // Block completely
maxLength = { 4 }
/>
</ div >
< button type = "submit" > Pay Now </ button >
</ form >
);
}
Custom Recording Configuration
For more control, configure session recording options:
import { Analytics , SessionRecorder } from "mentiq-sdk" ;
const analytics = new Analytics ({
apiKey: "your-api-key" ,
projectId: "your-project-id" ,
enableSessionRecording: true ,
});
// Custom recorder with privacy settings
const recorder = new SessionRecorder (
analytics . config ,
analytics . getSessionId (),
{
// Block elements by class
blockClass: "sensitive" ,
// Mask all input values by default
maskAllInputs: true ,
// Don't record specific input types
maskInputOptions: {
password: true ,
email: true ,
tel: true ,
},
// Ignore certain elements
ignoreClass: "private" ,
// Sampling rates (lower = less data)
sampling: {
mousemove: 100 , // Sample every 100ms
scroll: 200 , // Sample every 200ms
input: "last" , // Only record final value
},
}
);
Payment Data Compliance
MentiQ automatically sanitizes payment data to maintain PCI compliance:
Automatic Sanitization
import { useAnalytics } from "mentiq-sdk" ;
import type { SubscriptionProperties } from "mentiq-sdk" ;
function SubscriptionManager () {
const { identify } = useAnalytics ();
const saveSubscription = ( userId : string ) => {
const subscription : SubscriptionProperties = {
status: "active" ,
plan_name: "Premium" ,
mrr: 2900 ,
payment_method_type: "card" ,
payment_method_last4: "4242" , // ✅ Last 4 digits only
payment_method_brand: "visa" ,
provider: "stripe" ,
};
// SDK validates and stores safely
identify ( userId , { subscription });
};
}
What Gets Removed
The SDK automatically removes:
// ❌ These fields are NEVER stored or sent
const dangerous = {
card_number: "4242424242424242" , // Full card number - REMOVED
cvv: "123" , // CVV - REMOVED
card_cvv: "123" , // CVV variant - REMOVED
};
// ✅ These are safe and allowed
const safe = {
payment_method_last4: "4242" , // Last 4 digits only
payment_method_brand: "visa" , // Card brand
payment_method_type: "card" , // Payment type
};
Validation Logic
The SDK’s validation code (from analytics.ts:510-538):
private validateSubscriptionData (
subscription : SubscriptionProperties
): SubscriptionProperties {
const validated = { ... subscription };
// PCI compliance - truncate to last 4 digits only
if ( validated . payment_method_last4 && validated . payment_method_last4 . length > 4 ) {
validated . payment_method_last4 = validated . payment_method_last4 . slice ( - 4 );
if ( this . config . debug ) {
console . warn (
"MentiQ: Truncated payment_method_last4 to last 4 digits for PCI compliance"
);
}
}
// Remove any card data (PCI compliance)
delete ( validated as any )[ "card_number" ];
delete ( validated as any )[ "cvv" ];
delete ( validated as any )[ "card_cvv" ];
// Calculate derived fields
if ( validated . mrr && validated . billing_interval === "year" ) {
validated . arr = validated . mrr * 12 ;
} else if ( validated . arr && validated . billing_interval === "month" ) {
validated . mrr = Math . round ( validated . arr / 12 );
}
return validated ;
}
User Data Management
User Identification
import { useAnalytics } from "mentiq-sdk" ;
function AuthManager () {
const { identify , reset } = useAnalytics ();
const handleLogin = async ( email : string , password : string ) => {
const user = await loginUser ( email , password );
// Identify user with safe data only
identify ( user . id , {
email: user . email ,
name: user . name ,
plan: user . planTier ,
created_at: user . createdAt ,
});
};
const handleLogout = () => {
// Clear all user data from analytics
reset ();
// Your logout logic...
logoutUser ();
};
return null ;
}
Reset User Data
The reset() method clears:
User ID from localStorage
Event queue
Session data (starts new session)
Any cached user traits
const { reset } = useAnalytics ();
// On user logout
reset ();
// On user requesting data deletion
await deleteUserData ( userId );
reset (); // Clear local analytics data
GDPR Compliance
Consent Management
Implement consent before tracking:
components/CookieConsent.tsx
'use client' ;
import { useState , useEffect } from "react" ;
import { useAnalytics } from "mentiq-sdk" ;
export function CookieConsent () {
const [ consent , setConsent ] = useState < boolean | null >( null );
const { track , startRecording , stopRecording } = useAnalytics ();
useEffect (() => {
// Check existing consent
const stored = localStorage . getItem ( "analytics_consent" );
if ( stored ) {
setConsent ( stored === "true" );
}
}, []);
useEffect (() => {
if ( consent === true ) {
// User consented - enable full tracking
track ( "consent_granted" );
startRecording ();
} else if ( consent === false ) {
// User declined - stop tracking
stopRecording ();
}
}, [ consent , track , startRecording , stopRecording ]);
const handleAccept = () => {
localStorage . setItem ( "analytics_consent" , "true" );
setConsent ( true );
};
const handleDecline = () => {
localStorage . setItem ( "analytics_consent" , "false" );
setConsent ( false );
};
if ( consent !== null ) return null ;
return (
< div className = "cookie-banner" >
< p >
We use cookies and analytics to improve your experience.
< a href = "/privacy" > Learn more </ a >
</ p >
< button onClick = { handleAccept } > Accept </ button >
< button onClick = { handleDecline } > Decline </ button >
</ div >
);
}
Conditional Analytics Provider
Only initialize analytics after consent:
'use client' ;
import { useState , useEffect } from "react" ;
import { AnalyticsProvider } from "mentiq-sdk" ;
function ConditionalAnalytics ({ children } : { children : React . ReactNode }) {
const [ hasConsent , setHasConsent ] = useState ( false );
useEffect (() => {
const consent = localStorage . getItem ( "analytics_consent" );
setHasConsent ( consent === "true" );
}, []);
if ( ! hasConsent ) {
return <> { children } </> ; // No analytics
}
return (
< AnalyticsProvider
config = { {
apiKey: process . env . NEXT_PUBLIC_MENTIQ_API_KEY ! ,
projectId: process . env . NEXT_PUBLIC_MENTIQ_PROJECT_ID ! ,
enableSessionRecording: true ,
enableErrorTracking: true ,
} }
>
{ children }
</ AnalyticsProvider >
);
}
Data Minimization
Only Track What You Need
Don’t track sensitive or unnecessary data. Every data point should have a clear business purpose.
// ❌ Bad - Tracking sensitive PII
analytics . track ( "form_submitted" , {
ssn: "123-45-6789" , // Never!
full_card_number: "4242..." , // Never!
password: "user_password" , // Never!
});
// ✅ Good - Tracking aggregated, non-sensitive data
analytics . track ( "form_submitted" , {
form_name: "contact" ,
fields_filled: 5 ,
validation_errors: 0 ,
time_to_complete: 45 , // seconds
});
Anonymous vs Identified Users
// Anonymous tracking (no identify call)
analytics . track ( "product_viewed" , {
product_id: "prod_123" ,
category: "electronics" ,
});
// Only identify after user creates account
const handleSignup = ( userId : string , email : string ) => {
identify ( userId , { email }); // Now events tied to user
};
Right to Be Forgotten
Implement GDPR Article 17 (Right to Erasure):
app/api/delete-user-data/route.ts
import { NextRequest , NextResponse } from "next/server" ;
export async function POST ( request : NextRequest ) {
const { userId } = await request . json ();
// 1. Delete from MentiQ Analytics backend
await fetch (
` ${ process . env . MENTIQ_ENDPOINT } /api/v1/users/ ${ userId } ` ,
{
method: "DELETE" ,
headers: {
Authorization: `ApiKey ${ process . env . MENTIQ_API_KEY } ` ,
"X-Project-ID" : process . env . MENTIQ_PROJECT_ID ! ,
},
}
);
// 2. Delete from your database
await db . user . delete ({ where: { id: userId } });
// 3. Clear any cached data
await redis . del ( `user: ${ userId } ` );
return NextResponse . json ({ success: true });
}
IP Address Handling
MentiQ can anonymize IP addresses server-side:
Server-Side Events
import { trackServerEvent } from "mentiq-sdk/nextjs" ;
// Don't send IP if not needed
await trackServerEvent (
config ,
"api_request" ,
{ endpoint: "/api/users" },
{
userId: "user_123" ,
userAgent: req . headers [ "user-agent" ],
// ip: undefined - Don't send IP at all
}
);
The MentiQ backend can automatically anonymize IP addresses by masking the last octet (e.g., 192.168.1.xxx). Contact support to enable this feature.
Opt-Out Implementation
components/PrivacySettings.tsx
'use client' ;
import { useState } from "react" ;
import { useAnalytics } from "mentiq-sdk" ;
export function PrivacySettings () {
const { stopRecording , startRecording } = useAnalytics ();
const [ recordingEnabled , setRecordingEnabled ] = useState ( true );
const toggleRecording = ( enabled : boolean ) => {
if ( enabled ) {
startRecording ();
localStorage . setItem ( "mentiq_recording_enabled" , "true" );
} else {
stopRecording ();
localStorage . setItem ( "mentiq_recording_enabled" , "false" );
}
setRecordingEnabled ( enabled );
};
return (
< div >
< h2 > Privacy Settings </ h2 >
< label >
< input
type = "checkbox"
checked = { recordingEnabled }
onChange = { ( e ) => toggleRecording ( e . target . checked ) }
/>
Enable session recording
</ label >
< p className = "text-sm text-gray-600" >
Session recording helps us improve the product.
Your sensitive data is always masked.
</ p >
</ div >
);
}
Security Best Practices
Use Separate API Keys
Use different API keys for client-side and server-side tracking: # Public key (limited permissions)
NEXT_PUBLIC_MENTIQ_API_KEY = pk_live_...
# Private key (full permissions)
MENTIQ_API_KEY = sk_live_...
Never Log Sensitive Data
Disable debug mode in production: const analytics = new Analytics ({
debug: process . env . NODE_ENV === "development" , // Only in dev
// ...
});
Sanitize Event Properties
Create a utility to sanitize properties: function sanitizeProperties ( props : Record < string , any >) {
const sanitized = { ... props };
// Remove sensitive fields
delete sanitized . password ;
delete sanitized . ssn ;
delete sanitized . credit_card ;
// Mask email domains
if ( sanitized . email ) {
const [ local , domain ] = sanitized . email . split ( "@" );
sanitized . email_domain = domain ;
delete sanitized . email ;
}
return sanitized ;
}
analytics . track ( "form_submitted" , sanitizeProperties ( formData ));
Use HTTPS Only
Always use HTTPS for your analytics endpoint: const analytics = new Analytics ({
endpoint: "https://analytics.myapp.com" , // ✅ HTTPS
// endpoint: "http://...", // ❌ Never use HTTP
});
Compliance Checklist
Implement cookie consent banner
Provide clear privacy policy
Allow users to opt-out of tracking
Implement right to be forgotten (data deletion)
Use privacy CSS classes for session recording
Minimize data collection to necessary only
Anonymize or don’t collect IP addresses
Secure data transmission (HTTPS only)
Provide “Do Not Sell My Data” option
Allow users to delete their data
Disclose data collection practices
Provide opt-out before data sale
Never store full card numbers
Only store last 4 digits of cards
Use SDK’s automatic sanitization
Encrypt data in transit (HTTPS)
Next Steps
Next.js Integration Set up privacy-compliant analytics in Next.js
TypeScript Types Learn about SubscriptionProperties and validation