> ## 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.

# Visitor Recommendations

> Personalized recommendations for anonymous visitors based on browsing behavior

## 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

```typescript theme={null}
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

<ParamField body="configId" type="string" required>
  Recommendation configuration ID from the dashboard. Defines the algorithm and business rules.
</ParamField>

<ParamField body="topK" type="number" required>
  Number of recommendations to return. Recommended: 8-24.
</ParamField>

<ParamField body="filters" type="Filter[]">
  Additional filters to apply. See [Filters](/sdk/search/filters).
</ParamField>

## 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

```typescript theme={null}
// Check the current visitor ID
const visitorId = refine.getVisitorId();
console.log('Visitor:', visitorId);  // e.g., "v_a1b2c3d4e5"
```

<Note>
  Visitor IDs persist across sessions but not across devices or browsers. Use [User Recommendations](/sdk/recommendations/user-recommendations) for cross-device personalization.
</Note>

## Creating Configurations

Visitor recommendation configurations are created in the dashboard:

**Dashboard → Recommendations → Configurations → New Configuration**

Configuration options include:

| Setting          | Description                                       |
| ---------------- | ------------------------------------------------- |
| **Strategy**     | Collaborative filtering, content-based, or hybrid |
| **Fallback**     | What to show for new visitors with no history     |
| **Diversity**    | How much to vary recommended categories           |
| **Recency Bias** | Weight recent behavior more heavily               |
| **Filters**      | Default filters (e.g., in-stock only)             |

## Tracking Visitor Recommendations

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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

```typescript theme={null}
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

<CardGroup cols={2}>
  <Card title="User Recommendations" icon="user-check" href="/sdk/recommendations/user-recommendations">
    Personalization for logged-in users
  </Card>

  <Card title="Similar Items" icon="clone" href="/sdk/recommendations/similar-items">
    Product-based recommendations
  </Card>
</CardGroup>
