Overview
User recommendations provide the deepest level of personalization by leveraging a user’s full purchase and browsing history across sessions and devices. Requires calling refine.identify() with your user ID.
Basic Usage
import { Refine } from '@refine-ai/sdk';
const refine = new Refine({
apiKey: process.env.REFINE_API_KEY,
organizationId: 'org_abc123',
catalogId: 'cat_xyz789'
});
// Identify the logged-in user
refine.identify('user_12345');
// Get personalized recommendations
const recs = await refine.recs.forUser({
configId: 'personalized_picks',
topK: 12
});
recs.results.forEach(product => {
console.log(`${product.title} - $${product.price}`);
});
Parameters
Recommendation configuration ID from the dashboard.
Number of recommendations to return.
Additional filters to apply. See Filters.
User Identification
Before requesting user recommendations, you must identify the user:
// Call this when user logs in
refine.identify('user_12345');
// Now user recommendations will work
const recs = await refine.recs.forUser({ configId: 'picks', topK: 12 });
If you call forUser() without first calling identify(), the request will fail with a validation error.
Identity Flow
// 1. User arrives (anonymous)
const visitorId = refine.getVisitorId(); // Auto-generated
// 2. User browses products
await refine.search.text({ query: 'shoes', topK: 20 });
// Browsing tracked under visitorId
// 3. User logs in
refine.identify('user_12345');
// Previous visitor behavior now linked to user
// 4. Get personalized recommendations
const recs = await refine.recs.forUser({
configId: 'personalized_picks',
topK: 12
});
// Uses full user history including current session
Check Current Identity
const userId = refine.getUserId(); // Returns 'user_12345' or null
const visitorId = refine.getVisitorId(); // Always returns a value
const sessionId = refine.getSessionId(); // Current session ID
User vs Visitor Recommendations
| Aspect | Visitor Recs | User Recs |
|---|
| Data source | Current device only | All devices, full history |
| Login required | No | Yes |
| Purchase history | Current session | All time |
| Cross-device | No | Yes |
| Cold start | More common | Less common |
Tracking User Recommendations
refine.identify('user_12345');
const recs = await refine.recs.forUser({
configId: 'personalized_picks',
topK: 12
});
const recsContext = refine.events.trackRecommendations(
recs.serveId,
recs.results,
'home_page',
'user-recs'
);
// Track interactions
recsContext.trackClick(productId, position);
recsContext.trackAddToCart(productId);
With Filters
const recs = await refine.recs.forUser({
configId: 'personalized_picks',
topK: 12,
filters: [
{ field: 'price', operator: 'lte', value: 200 },
{ field: 'stock', operator: 'gt', value: 0 }
]
});
Complete Implementation
import { Refine, RefineValidationError } from '@refine-ai/sdk';
const refine = new Refine({
apiKey: process.env.REFINE_API_KEY,
organizationId: 'org_abc123',
catalogId: 'cat_xyz789'
});
class PersonalizedRecommendations {
private isLoggedIn: boolean = false;
async init(userId?: string) {
if (userId) {
refine.identify(userId);
this.isLoggedIn = true;
}
}
async getRecommendations(topK: number = 12) {
if (this.isLoggedIn) {
return this.getUserRecommendations(topK);
}
return this.getVisitorRecommendations(topK);
}
private async getUserRecommendations(topK: number) {
try {
const recs = await refine.recs.forUser({
configId: 'user_personalized',
topK
});
return {
type: 'user',
title: 'Picked for You',
products: recs.results,
context: refine.events.trackRecommendations(
recs.serveId,
recs.results,
'home_page',
'user-recs'
)
};
} catch (error) {
if (error instanceof RefineValidationError) {
// User not properly identified, fall back to visitor
console.warn('User recs failed, falling back to visitor');
return this.getVisitorRecommendations(topK);
}
throw error;
}
}
private async getVisitorRecommendations(topK: number) {
const recs = await refine.recs.forVisitor({
configId: 'visitor_homepage',
topK
});
return {
type: 'visitor',
title: 'Recommended for You',
products: recs.results,
context: refine.events.trackRecommendations(
recs.serveId,
recs.results,
'home_page',
'visitor-recs'
)
};
}
async handleLogout() {
refine.reset();
this.isLoggedIn = false;
}
}
// Usage
const personalization = new PersonalizedRecommendations();
// On page load
const currentUser = getCurrentUserFromSession(); // Your auth logic
await personalization.init(currentUser?.id);
// Get recommendations
const { title, products, context } = await personalization.getRecommendations(12);
// Render
renderProductGrid(title, products, {
onClick: (productId, position) => context.trackClick(productId, position),
onAddToCart: (productId) => context.trackAddToCart(productId)
});
Handling Logout
When a user logs out, reset the identity:
function handleLogout() {
// Clear user identity
refine.reset();
// A new visitor ID will be generated for the next request
// Previous behavior is no longer linked to this session
}
Email/Marketing Recommendations
Generate recommendations for email campaigns:
// Server-side (e.g., email service integration)
import { Refine } from '@refine-ai/sdk';
const refine = new Refine({
apiKey: process.env.REFINE_API_KEY,
organizationId: 'org_abc123',
catalogId: 'cat_xyz789',
applicationType: 'server'
});
async function getEmailRecommendations(userId: string) {
refine.identify(userId);
const recs = await refine.recs.forUser({
configId: 'email_personalized',
topK: 6,
filters: [
{ field: 'stock', operator: 'gt', value: 0 }
]
});
return recs.results.map(product => ({
title: product.title,
price: product.price,
imageUrl: product.imageUrl,
productUrl: `https://store.com/products/${product.productId}`
}));
}
Fallback Strategy
Handle new users with minimal history:
async function getSmartRecommendations(userId: string | null) {
if (!userId) {
// Anonymous: visitor recommendations
return refine.recs.forVisitor({ configId: 'popular', topK: 12 });
}
refine.identify(userId);
try {
const userRecs = await refine.recs.forUser({
configId: 'personalized',
topK: 12
});
if (userRecs.results.length >= 8) {
return userRecs;
}
// Not enough personalized results, supplement with popular
const popular = await refine.recs.forVisitor({
configId: 'popular',
topK: 12 - userRecs.results.length
});
return {
...userRecs,
results: [...userRecs.results, ...popular.results]
};
} catch {
return refine.recs.forVisitor({ configId: 'popular', topK: 12 });
}
}
Next Steps