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
Recommendation configuration ID from the dashboard. Defines the algorithm and business rules.
Number of recommendations to return. Recommended: 8-24.
Additional filters to apply. See Filters .
How Visitor Tracking Works
The SDK automatically manages visitor identity:
First Visit : A unique visitorId is generated and stored in localStorage
Subsequent Visits : The same visitorId is reused
Behavior Tracking : Product views, clicks, and searches are associated with the visitor
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:
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
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