Skip to main content

Overview

Refine tracks three levels of identity to power personalization and analytics:
LevelPersistenceIdentifier
VisitorBrowser (localStorage)Auto-generated
SessionTab lifetime + timeoutAuto-generated
UserCross-deviceYour user ID

Identity Hierarchy

                    ┌─────────────┐
                    │   User ID   │  ← Your identifier (login)
                    │ (optional)  │
                    └──────┬──────┘

                    ┌──────▼──────┐
                    │ Visitor ID  │  ← Auto-generated, persisted
                    │ (required)  │     in localStorage
                    └──────┬──────┘

                    ┌──────▼──────┐
                    │ Session ID  │  ← Auto-generated per session
                    │ (required)  │     30 min timeout
                    └─────────────┘

Visitor ID

Automatically generated on first SDK use and stored in localStorage.
// Get current visitor ID
const visitorId = refine.getVisitorId();
console.log(visitorId);  // e.g., "v_a1b2c3d4e5f6"
Characteristics:
  • Generated once per browser/device
  • Persists across sessions (survives page refresh, browser close)
  • Does not persist across devices or browsers
  • Used for visitor-based recommendations
In incognito/private mode, visitor IDs are cleared when the browser closes.

Session ID

Automatically generated for each browsing session.
// Get current session ID
const sessionId = refine.getSessionId();
console.log(sessionId);  // e.g., "s_x9y8z7w6v5"
Characteristics:
  • Generated when SDK initializes
  • Expires after 30 minutes of inactivity (configurable)
  • New session created after timeout
  • Used to group interactions within a visit

Configure Session Timeout

const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789',
  events: {
    sessionTimeout: 60 * 60 * 1000  // 1 hour instead of 30 minutes
  }
});

User ID

Your application’s identifier for logged-in users. Set via identify().
// When user logs in
refine.identify('user_12345');

// Get current user ID
const userId = refine.getUserId();
console.log(userId);  // "user_12345"
Characteristics:
  • Set by your application
  • Links visitor behavior to a known user
  • Enables cross-device personalization
  • Required for user-based recommendations

The identify() Method

Call identify() when a user logs in:
// After successful login
async function handleLogin(credentials: Credentials) {
  const user = await authenticateUser(credentials);
  
  // Link visitor to user
  refine.identify(user.id);
  
  // Now user recommendations are available
  const recs = await refine.recs.forUser({
    configId: 'personalized',
    topK: 12
  });
}

Identity Merging

When you call identify(), Refine links the current visitor’s browsing history to the user account:
// Anonymous visitor browses products
await refine.search.text({ query: 'running shoes', topK: 20 });
// Interactions tracked under visitor_abc123

// User logs in
refine.identify('user_789');
// Previous visitor_abc123 interactions now linked to user_789

// Future interactions tracked under user_789
await refine.search.text({ query: 'trail shoes', topK: 20 });

The reset() Method

Call reset() when a user logs out:
function handleLogout() {
  // Clear user identity
  refine.reset();
  
  // User is now back to anonymous visitor
  // A new visitor ID will be generated
}
What reset() does:
  • Clears the user ID
  • Generates a new visitor ID
  • Generates a new session ID
  • Clears any cached personalization
After reset(), previous browsing behavior is no longer linked to subsequent sessions. Call this on logout to preserve user privacy.

Identity in Events

All events automatically include identity information:
// Event payload (internal)
{
  visitorId: "v_abc123",
  sessionId: "s_xyz789",
  userId: "user_12345",  // null if not identified
  event: "click",
  ...
}

Complete Authentication Flow

import { Refine } from '@refine-ai/sdk';

const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789'
});

class AuthManager {
  async init() {
    // Check for existing auth
    const user = await this.getStoredUser();
    if (user) {
      refine.identify(user.id);
    }
  }

  async login(email: string, password: string) {
    const user = await api.login(email, password);
    
    // Link visitor to user
    refine.identify(user.id);
    
    // Store auth
    this.storeUser(user);
    
    return user;
  }

  async logout() {
    await api.logout();
    
    // Clear Refine identity
    refine.reset();
    
    // Clear stored auth
    this.clearStoredUser();
  }

  private async getStoredUser() {
    // Your auth storage logic
  }

  private storeUser(user: User) {
    // Your auth storage logic
  }

  private clearStoredUser() {
    // Your auth storage logic
  }
}

// Usage
const auth = new AuthManager();
await auth.init();

// Get appropriate recommendations
async function getRecommendations() {
  if (refine.getUserId()) {
    // Logged in - use user recommendations
    return refine.recs.forUser({ configId: 'user_picks', topK: 12 });
  } else {
    // Anonymous - use visitor recommendations
    return refine.recs.forVisitor({ configId: 'visitor_picks', topK: 12 });
  }
}

Server-Side Identity

For server-side rendering or API routes, pass identity explicitly:
// Server-side (e.g., Next.js API route)
import { Refine } from '@refine-ai/sdk';

const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789',
  applicationType: 'server'
});

export async function getServerSideProps(context) {
  const userId = context.req.session?.userId;
  
  if (userId) {
    refine.identify(userId);
    const recs = await refine.recs.forUser({
      configId: 'personalized',
      topK: 12
    });
    return { props: { recommendations: recs.results } };
  }
  
  // For anonymous users, use visitor recommendations on client
  return { props: { recommendations: [] } };
}

Privacy Considerations

GDPR Compliance

const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789',
  privacy: {
    respectDoNotTrack: true,  // Honor browser DNT setting
    anonymizeIp: true,        // Anonymize IP addresses
    requireConsent: true      // Wait for consent before tracking
  }
});

Data Deletion

When a user requests data deletion:
  1. Call refine.reset() on their device
  2. Contact Refine support for server-side deletion

Debugging Identity

const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789',
  debug: true
});

// Check current identity
console.log('Visitor:', refine.getVisitorId());
console.log('Session:', refine.getSessionId());
console.log('User:', refine.getUserId());

// After identify
refine.identify('user_123');
console.log('User after identify:', refine.getUserId()); // 'user_123'

// After reset
refine.reset();
console.log('User after reset:', refine.getUserId()); // null
console.log('Visitor after reset:', refine.getVisitorId()); // New ID

Next Steps