Overview
Refine tracks three levels of identity to power personalization and analytics:
| Level | Persistence | Identifier |
|---|
| Visitor | Browser (localStorage) | Auto-generated |
| Session | Tab lifetime + timeout | Auto-generated |
| User | Cross-device | Your 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
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:
- Call
refine.reset() on their device
- 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