Skip to main content

Overview

The MentiQ Analytics SDK provides comprehensive user identification capabilities, allowing you to track both anonymous and identified users, merge user profiles, and enrich user data with custom traits.

User Identity Types

The SDK manages three types of user identifiers:
  1. User ID: Unique identifier for logged-in users
  2. Anonymous ID: Automatically generated for all users
  3. Session ID: Unique identifier for each session

Anonymous Tracking

Anonymous tracking is automatic - no configuration needed:
import { Analytics } from 'mentiq-sdk';

const analytics = new Analytics({
  apiKey: 'your-api-key',
  projectId: 'your-project-id',
});

// Anonymous ID is automatically generated and persisted
const anonymousId = analytics.getAnonymousId();
console.log('Anonymous ID:', anonymousId);
The anonymous ID is:
  • Generated on first visit
  • Stored in localStorage as mentiq_anonymous_id
  • Persists across sessions and page reloads
  • Included automatically with all events

Identifying Users

Basic User Identification

Call identify() when a user logs in or signs up:
analytics.identify('user-123');
userId
string
required
Unique identifier for the user (e.g., database ID, UUID)

Identification with User Traits

Enrich user profiles with additional information:
analytics.identify('user-123', {
  email: '[email protected]',
  name: 'John Doe',
  plan: 'premium',
  created_at: '2024-01-15',
  company: 'Acme Corp',
});
userId
string
required
Unique identifier for the user
traits
UserProperties
Object containing user traits. Can include:
  • email: User email address (automatically detected from auth if not provided)
  • name: User full name
  • subscription: Subscription properties (see Subscription Tracking)
  • Custom properties: Any additional user attributes

Managing User IDs

Set User ID

Set or update the user ID without sending an identify event:
analytics.setUserId('user-123');

Get User ID

Retrieve the current user ID:
const userId = analytics.getUserId();
if (userId) {
  console.log('User is logged in:', userId);
} else {
  console.log('User is anonymous');
}

Initialize with User ID

Set user ID during initialization:
const analytics = new Analytics({
  apiKey: 'your-api-key',
  projectId: 'your-project-id',
  userId: 'user-123',
});

User Aliasing

Alias allows you to merge user identities, typically when transitioning from anonymous to identified:
// User was anonymous
const anonymousId = analytics.getAnonymousId();

// User signs up
analytics.identify('user-123', {
  email: '[email protected]',
});

// Link the anonymous and identified user
analytics.alias('user-123', anonymousId);
newId
string
required
The new user ID (typically the logged-in user ID)
previousId
string
The previous user ID or anonymous ID. If omitted, uses the current user ID.

Automatic Aliasing Flow

// 1. User arrives (anonymous)
const analytics = new Analytics({
  apiKey: 'your-api-key',
  projectId: 'your-project-id',
});

// 2. User browses (anonymous events tracked)
analytics.track('page_viewed', { page: 'pricing' });
analytics.track('button_clicked', { button: 'start_trial' });

// 3. User signs up
const newUserId = 'user-789';
const previousAnonymousId = analytics.getAnonymousId();

analytics.identify(newUserId, {
  email: '[email protected]',
  signup_method: 'email',
});

// 4. Link identities
analytics.alias(newUserId, previousAnonymousId);

Resetting User Identity

Reset user identity when logging out:
analytics.reset();
This:
  • Clears the user ID
  • Clears event queue
  • Generates a new anonymous ID
  • Starts a new session
  • Preserves stored anonymous tracking
Always call reset() when a user logs out to prevent attribution errors.

Automatic Email Detection

The SDK automatically detects user email from popular authentication providers:
  • NextAuth / Auth.js
  • Supabase Auth
  • Firebase Auth
  • Clerk
  • Auth0
No additional configuration needed:
// Email is automatically detected and included with events
const analytics = new Analytics({
  apiKey: 'your-api-key',
  projectId: 'your-project-id',
});

// Later, when user logs in via Supabase/Firebase/etc.
// Email is automatically detected and enriched in events
Detected email is:
  • Stored in localStorage as mentiq_user_email
  • Automatically included with all events
  • Used for user attribution and segmentation

Manual Email Override

Manually set email to override auto-detection:
analytics.identify('user-123', {
  email: '[email protected]',
});

Subscription Tracking

Track user subscription status for SaaS metrics:
analytics.identify('user-123', {
  email: '[email protected]',
  subscription: {
    status: 'active',
    plan_id: 'plan_premium',
    plan_name: 'Premium Plan',
    plan_tier: 'pro',
    mrr: 2900, // $29.00 in cents
    currency: 'usd',
    billing_interval: 'month',
    provider: 'stripe',
    provider_customer_id: 'cus_123',
  },
});

Subscription Properties

status
string
required
Subscription status: "active", "trialing", "past_due", "canceled", "paused", "incomplete", "incomplete_expired", or "unpaid"
plan_id
string
Unique plan identifier
plan_name
string
Human-readable plan name
plan_tier
string
Plan tier: "free", "starter", "pro", "enterprise", etc.
mrr
number
Monthly Recurring Revenue in cents (e.g., 2900 for $29.00)
arr
number
Annual Recurring Revenue in cents
currency
string
Currency code (e.g., "usd", "eur")
billing_interval
string
Billing cycle: "day", "week", "month", or "year"
provider
string
Payment provider: "stripe", "paddle", "chargebee", "manual", or custom

Automatic Subscription Detection

The SDK automatically detects subscriptions from:
  • Stripe.js
  • Paddle.js
  • Chargebee.js
// Automatic detection runs on initialization
const analytics = new Analytics({
  apiKey: 'your-api-key',
  projectId: 'your-project-id',
});

// Subscription data is automatically detected and stored
// Retrieve it with:
const subscription = analytics.getSubscriptionData();
if (subscription) {
  console.log('Plan:', subscription.plan_name);
  console.log('Status:', subscription.status);
  console.log('MRR:', subscription.mrr);
}

PCI Compliance

The SDK automatically ensures PCI compliance:
Never include full card numbers or CVV codes. The SDK automatically removes these fields and truncates card numbers to last 4 digits only.
analytics.identify('user-123', {
  subscription: {
    status: 'active',
    payment_method_type: 'card',
    payment_method_last4: '4242', // Only last 4 digits
    payment_method_brand: 'visa',
    // card_number: NEVER include full card numbers
    // cvv: NEVER include CVV
  },
});

User Trait Enrichment

All events automatically include user traits:
analytics.identify('user-123', {
  email: '[email protected]',
  subscription: {
    status: 'active',
    plan_name: 'Premium',
    mrr: 2900,
  },
});

// Subsequent events automatically enriched
analytics.track('feature_used', {
  feature: 'export_data',
});
// This event includes:
// - email: '[email protected]'
// - subscription_status: 'active'
// - subscription_plan: 'Premium'
// - subscription_mrr: 2900
// - is_paid_user: true

User Persistence

Storage Locations

User data is persisted in browser storage:
// User ID
localStorage.getItem('mentiq_user_id')

// Anonymous ID
localStorage.getItem('mentiq_anonymous_id')

// Email
localStorage.getItem('mentiq_user_email')

// Subscription Data
localStorage.getItem('mentiq_user_subscription')

// Session ID (per-tab)
sessionStorage.getItem('mentiq_session_id')

Cross-Domain Tracking

For cross-domain tracking, manually pass user identifiers:
// On domain A
const userId = analytics.getUserId();
const anonymousId = analytics.getAnonymousId();

// Pass to domain B via URL
window.location.href = `https://domainb.com?uid=${userId}&aid=${anonymousId}`;

// On domain B
const urlParams = new URLSearchParams(window.location.search);
const userId = urlParams.get('uid');
const anonymousId = urlParams.get('aid');

if (userId) {
  analytics.identify(userId);
}

Best Practices

Call identify() immediately after successful login or signup to ensure all subsequent events are attributed correctly.
Always call reset() on logout to prevent cross-user contamination.
Use database IDs (not emails) as user IDs for stability - emails can change.
Anonymous and identified user data is automatically merged when you call alias(), preserving the complete user journey.

Common Implementation Patterns

Next.js with NextAuth

import { useSession } from 'next-auth/react';
import { useEffect } from 'react';

function MyApp() {
  const { data: session } = useSession();
  
  useEffect(() => {
    if (session?.user) {
      analytics.identify(session.user.id, {
        email: session.user.email,
        name: session.user.name,
      });
    } else {
      analytics.reset();
    }
  }, [session]);
  
  return <div>App Content</div>;
}

React with Supabase

import { useEffect } from 'react';
import { supabase } from './supabaseClient';

function App() {
  useEffect(() => {
    // Listen for auth changes
    const { data: authListener } = supabase.auth.onAuthStateChange(
      (event, session) => {
        if (event === 'SIGNED_IN' && session?.user) {
          analytics.identify(session.user.id, {
            email: session.user.email,
          });
        } else if (event === 'SIGNED_OUT') {
          analytics.reset();
        }
      }
    );
    
    return () => {
      authListener?.subscription.unsubscribe();
    };
  }, []);
  
  return <div>App Content</div>;
}

SaaS with Stripe Integration

// After successful Stripe checkout
stripe.redirectToCheckout({ sessionId }).then((result) => {
  if (result.error) {
    // Handle error
  } else {
    // Update subscription in analytics
    analytics.identify(userId, {
      subscription: {
        status: 'active',
        plan_id: selectedPlan.id,
        plan_name: selectedPlan.name,
        mrr: selectedPlan.price,
        currency: 'usd',
        billing_interval: 'month',
        provider: 'stripe',
      },
    });
  }
});

Build docs developers (and LLMs) love