Skip to main content

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

configId
string
required
Recommendation configuration ID from the dashboard.
topK
number
required
Number of recommendations to return.
filters
Filter[]
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

AspectVisitor RecsUser Recs
Data sourceCurrent device onlyAll devices, full history
Login requiredNoYes
Purchase historyCurrent sessionAll time
Cross-deviceNoYes
Cold startMore commonLess 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