Skip to main content

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

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

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

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:
app/layout.tsx
'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

1

Use Separate API Keys

Use different API keys for client-side and server-side tracking:
.env.local
# Public key (limited permissions)
NEXT_PUBLIC_MENTIQ_API_KEY=pk_live_...

# Private key (full permissions)
MENTIQ_API_KEY=sk_live_...
2

Never Log Sensitive Data

Disable debug mode in production:
const analytics = new Analytics({
  debug: process.env.NODE_ENV === "development", // Only in dev
  // ...
});
3

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));
4

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
Never store CVV codes
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

Build docs developers (and LLMs) love