Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.joinrefine.io/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Visitor recommendations personalize the shopping experience for anonymous users based on their current session behavior. No login required — Refine tracks visitors using automatically generated IDs stored in localStorage.

Basic Usage

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

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

const recs = await refine.recs.forVisitor({
  configId: 'homepage_personalized',
  topK: 12
});

recs.results.forEach(product => {
  console.log(`${product.title} - $${product.price}`);
});

Parameters

configId
string
required
Recommendation configuration ID from the dashboard. Defines the algorithm and business rules.
topK
number
required
Number of recommendations to return. Recommended: 8-24.
filters
Filter[]
Additional filters to apply. See Filters.

How Visitor Tracking Works

The SDK automatically manages visitor identity:
  1. First Visit: A unique visitorId is generated and stored in localStorage
  2. Subsequent Visits: The same visitorId is reused
  3. Behavior Tracking: Product views, clicks, and searches are associated with the visitor
  4. Recommendations: The algorithm uses this history to personalize results
// Check the current visitor ID
const visitorId = refine.getVisitorId();
console.log('Visitor:', visitorId);  // e.g., "v_a1b2c3d4e5"
Visitor IDs persist across sessions but not across devices or browsers. Use User Recommendations for cross-device personalization.

Creating Configurations

Visitor recommendation configurations are created in the dashboard: Dashboard → Recommendations → Configurations → New Configuration Configuration options include:
SettingDescription
StrategyCollaborative filtering, content-based, or hybrid
FallbackWhat to show for new visitors with no history
DiversityHow much to vary recommended categories
Recency BiasWeight recent behavior more heavily
FiltersDefault filters (e.g., in-stock only)

Tracking Visitor Recommendations

const recs = await refine.recs.forVisitor({
  configId: 'homepage_recs',
  topK: 12
});

const recsContext = refine.events.trackRecommendations(
  recs.serveId,
  recs.results,
  'home_page',
  'visitor-recs'
);

// Track interactions
recsContext.trackClick(productId, position);
recsContext.trackView(productId, position);
recsContext.trackAddToCart(productId);

With Filters

Apply runtime filters on top of configuration defaults:
const recs = await refine.recs.forVisitor({
  configId: 'homepage_recs',
  topK: 12,
  filters: [
    { field: 'price', operator: 'lte', value: 100 },
    { field: 'metadata.category', operator: 'in', value: ['womens', 'accessories'] }
  ]
});

Use Cases

Homepage Hero

Show personalized picks based on browsing history:
async function loadHomepageRecs() {
  const recs = await refine.recs.forVisitor({
    configId: 'homepage_hero',
    topK: 8
  });
  
  return recs.results;
}

Category Page Enhancement

Mix algorithmic recommendations with category products:
async function loadCategoryPageRecs(category: string) {
  const recs = await refine.recs.forVisitor({
    configId: 'category_page_recs',
    topK: 8,
    filters: [
      { field: 'metadata.category', operator: 'eq', value: category }
    ]
  });
  
  return recs.results;
}

Search Fallback

When search returns no results, show personalized alternatives:
async function handleEmptySearch(query: string) {
  const recs = await refine.recs.forVisitor({
    configId: 'search_fallback',
    topK: 12
  });
  
  return {
    message: `No results for "${query}". You might like these:`,
    products: recs.results
  };
}

Exit Intent

Show personalized recommendations in exit-intent popups:
document.addEventListener('mouseleave', async (e) => {
  if (e.clientY < 0) {  // Mouse leaving viewport at top
    const recs = await refine.recs.forVisitor({
      configId: 'exit_intent',
      topK: 4
    });
    
    showExitPopup(recs.results);
  }
});

Complete Implementation

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

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

class HomepageRecommendations {
  private container: HTMLElement;
  private recsContext: any;

  constructor(containerId: string) {
    this.container = document.getElementById(containerId)!;
    this.load();
  }

  private async load() {
    this.container.innerHTML = '<p>Loading recommendations...</p>';

    try {
      const recs = await refine.recs.forVisitor({
        configId: 'homepage_personalized',
        topK: 12
      });

      this.recsContext = refine.events.trackRecommendations(
        recs.serveId,
        recs.results,
        'home_page',
        'visitor-recs'
      );

      this.render(recs.results);
      this.setupViewabilityTracking();
    } catch (error) {
      this.container.innerHTML = '<p>Unable to load recommendations.</p>';
      console.error('Recommendations error:', error);
    }
  }

  private render(products: any[]) {
    this.container.innerHTML = `
      <h2>Recommended for You</h2>
      <div class="product-grid">
        ${products.map((product, index) => `
          <div class="product-card" 
               data-id="${product.productId}" 
               data-position="${index}">
            <img src="${product.imageUrl}" alt="${product.title}" />
            <h3>${product.title}</h3>
            <p class="price">$${product.price.toFixed(2)}</p>
            <button class="add-to-cart">Add to Cart</button>
          </div>
        `).join('')}
      </div>
    `;

    // Click handlers
    this.container.querySelectorAll('.product-card').forEach(card => {
      const productId = (card as HTMLElement).dataset.id!;
      const position = parseInt((card as HTMLElement).dataset.position!);

      card.addEventListener('click', (e) => {
        if ((e.target as HTMLElement).classList.contains('add-to-cart')) {
          this.recsContext?.trackAddToCart(productId);
        } else {
          this.recsContext?.trackClick(productId, position);
          window.location.href = `/products/${productId}`;
        }
      });
    });
  }

  private setupViewabilityTracking() {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const card = entry.target as HTMLElement;
          const productId = card.dataset.id!;
          const position = parseInt(card.dataset.position!);
          this.recsContext?.trackView(productId, position);
          observer.unobserve(card);
        }
      });
    }, { threshold: 0.5 });

    this.container.querySelectorAll('.product-card').forEach(card => {
      observer.observe(card);
    });
  }
}

// Initialize
new HomepageRecommendations('homepage-recs');

New Visitor Handling

For first-time visitors with no history, the configuration’s fallback strategy kicks in:
  • Popular Items: Show best-sellers
  • New Arrivals: Show recently added products
  • Editorial Picks: Show curated selections
Configure fallback behavior in the dashboard.

Next Steps

User Recommendations

Personalization for logged-in users

Similar Items

Product-based recommendations