Skip to main content

Recommend API

The Recommend API provides personalized product recommendations based on user behavior, browsing history, and purchase patterns.

Key takeaway

Use this API to build custom recommendation widgets, carousels, or integrate recommendations into your existing UI - without relying on edrone's built-in frames.

Overview

POST https://api.edrone.me/recommend
Content-Type: application/json
Naming convention

This API uses camelCase for JSON body parameters (e.g., appId, productInteractions), unlike the Trace API which uses snake_case (e.g., app_id, product_ids). This is because the Recommend API accepts JSON, while Trace API uses form-urlencoded data.

The API returns personalized product recommendations using multiple algorithms:

  • Association Rules (ARULES) - "Customers also bought"
  • Semantic Similarity (SBERT) - Similar products based on descriptions
  • Collaborative Filtering - Based on user behavior patterns
  • Checkout recommendations - Complementary products for cart

Request format

Send a JSON body with the recommendation context:

{
"appId": "YOUR_APP_ID",
"productInteractions": [
{
"productInteractionType": "product_view",
"productId": "SKU123",
"productSku": "SKU123",
"utcInteractionDate": "2024-01-15T10:30:00.000Z"
},
{
"productInteractionType": "add_to_cart",
"productId": "SKU456",
"productSku": "SKU456",
"utcInteractionDate": "2024-01-15T10:32:00.000Z"
}
],
"recommendFrameInteractions": [],
"currentProductIds": "SKU789",
"currentProductSkus": "SKU789",
"currentCategoryIds": "cat-shoes",
"cId": "unique-client-id",
"fpccid": "fingerprint-cookie-id"
}

Request parameters

ParameterTypeRequiredDescription
appIdstringYesYour edrone App ID
productInteractionsarrayYesHistory of user's product interactions
recommendFrameInteractionsarrayNoHistory of recommendation frame interactions
currentProductIdsstringNoCurrently viewed product ID(s)
currentProductSkusstringNoCurrently viewed product SKU(s)
currentCategoryIdsstringNoCurrently viewed category ID(s)
cIdstringNoClient ID from localStorage
fpccidstringNoFingerprint cookie ID
marketingMachineFrameConfigurationIdstringNoSpecific frame configuration to use
filterByGroupsstringNoFilter recommendations by product groups
externalCookieGaIdstringNoGoogle Analytics cookie for enhanced tracking

Product interaction types

TypeDescription
product_viewUser viewed a product page
add_to_cartUser added product to cart
orderUser purchased the product

Response format

{
"version": "2024011512",
"trackerProduct": {
"productId": "SKU789",
"title": "Running Shoes Pro",
"imageUrl": "https://example.com/images/sku789.jpg",
"url": "https://example.com/products/sku789",
"price": "129.99",
"categoryId": "cat-shoes"
},
"recommended": [
{
"productId": "SKU101",
"title": "Sport Socks 3-Pack",
"imageUrl": "https://example.com/images/sku101.jpg",
"url": "https://example.com/products/sku101",
"price": "19.99",
"categoryId": "cat-accessories"
},
{
"productId": "SKU102",
"title": "Running Shorts",
"imageUrl": "https://example.com/images/sku102.jpg",
"url": "https://example.com/products/sku102",
"price": "49.99",
"categoryId": "cat-clothing"
}
],
"alternative": [
{
"productId": "SKU201",
"title": "Running Shoes Lite",
"imageUrl": "https://example.com/images/sku201.jpg",
"url": "https://example.com/products/sku201",
"price": "99.99",
"categoryId": "cat-shoes"
}
]
}

Response fields

FieldTypeDescription
versionstringCurrent recommendation engine version (for cache invalidation)
trackerProductobjectThe product being viewed (context)
recommendedarrayComplementary products ("You may also like")
alternativearraySimilar/alternative products ("Similar items")

Implementation examples

class RecommendationService {
constructor(appId) {
this.appId = appId;
this.endpoint = 'https://api.edrone.me/recommend';
this.storageKey = 'recommended_data';
}

// Get current recommendation state from localStorage
getState() {
const stored = localStorage.getItem(this.storageKey);
if (stored) {
return JSON.parse(stored);
}
return {
appId: this.appId,
productInteractions: [],
recommendFrameInteractions: [],
version: null
};
}

// Save state to localStorage
saveState(state) {
state.appId = this.appId;
localStorage.setItem(this.storageKey, JSON.stringify(state));
}

// Track product interaction
trackInteraction(type, productId, productSku = null) {
const state = this.getState();

// Keep last 100 product_view and add_to_cart interactions
const filtered = state.productInteractions.filter(i => {
if (i.productInteractionType === 'product_view') return true;
if (i.productInteractionType === 'add_to_cart') return true;
if (i.productInteractionType === 'order') return true;
return false;
}).slice(-200);

state.productInteractions = filtered;
state.productInteractions.push({
productInteractionType: type,
productId: productId,
productSku: productSku || productId,
utcInteractionDate: new Date().toISOString()
});

this.saveState(state);
}

// Fetch recommendations
async getRecommendations(currentProductId, currentCategoryId = null) {
const state = this.getState();

const requestBody = {
...state,
currentProductIds: currentProductId,
currentProductSkus: currentProductId,
currentCategoryIds: currentCategoryId
};

const response = await fetch(this.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody),
credentials: 'include'
});

if (!response.ok) {
throw new Error('Failed to fetch recommendations');
}

const data = await response.json();

// Update version if changed
if (data.version && data.version !== state.version) {
state.version = data.version;
state.recommendFrameInteractions = []; // Clear on version change
this.saveState(state);
}

return data;
}
}

// Usage
const recommendations = new RecommendationService('YOUR_APP_ID');

// Track when user views a product
recommendations.trackInteraction('product_view', 'SKU123');

// Track when user adds to cart
recommendations.trackInteraction('add_to_cart', 'SKU456');

// Get recommendations for current product
const result = await recommendations.getRecommendations('SKU789', 'cat-shoes');

console.log('Recommended products:', result.recommended);
console.log('Alternative products:', result.alternative);

localStorage integration

When implementing on the frontend, maintain recommendation state in localStorage for:

  • Personalization continuity across page loads
  • Interaction history for better recommendations
  • Version tracking for cache invalidation

Storage structure

// Key: "recommended_data"
{
"appId": "YOUR_APP_ID",
"productInteractions": [
{
"productInteractionType": "product_view",
"productId": "SKU123",
"productSku": "SKU123",
"utcInteractionDate": "2024-01-15T10:30:00.000Z"
}
],
"recommendFrameInteractions": [
{
"trackerProductGroupId": "frame-123",
"utcInteractionDate": "2024-01-15T10:31:00.000Z"
}
],
"version": "2024011512"
}

Version handling

The API returns a version field. When this changes:

  1. Clear recommendFrameInteractions array
  2. Update stored version
  3. This ensures users see fresh recommendations when the recommendation engine is updated
// After receiving response
if (response.version !== storedState.version) {
storedState.version = response.version;
storedState.recommendFrameInteractions = [];
localStorage.setItem('recommended_data', JSON.stringify(storedState));
}

Best practices

1. Track meaningful interactions

// Good - track actual user intent
trackInteraction('product_view', productId); // User spent time on product page
trackInteraction('add_to_cart', productId); // User showed purchase intent

// Avoid - don't track everything
// Don't track quick scrolls, accidental clicks, or list views

2. Limit interaction history

Keep the last 100-200 interactions per type to balance personalization vs. request size:

const MAX_INTERACTIONS = 100;
state.productInteractions = state.productInteractions
.filter(i => i.productInteractionType === 'product_view')
.slice(-MAX_INTERACTIONS);

3. Handle empty responses gracefully

if (!recommendations?.recommended?.length) {
// Show fallback content: bestsellers, new arrivals, etc.
return <FallbackRecommendations />;
}

4. Cache responses appropriately

Recommendations can be cached for short periods (1-5 minutes) to reduce API calls:

const CACHE_TTL = 60000; // 1 minute
const cacheKey = `recommendations_${productId}`;
const cached = sessionStorage.getItem(cacheKey);

if (cached) {
const { data, timestamp } = JSON.parse(cached);
if (Date.now() - timestamp < CACHE_TTL) {
return data;
}
}

const fresh = await fetchRecommendations(productId);
sessionStorage.setItem(cacheKey, JSON.stringify({
data: fresh,
timestamp: Date.now()
}));

Error handling

HTTP status codes

StatusMeaning
200Success - recommendations returned
400Bad request - invalid JSON or missing required fields
500Server error - temporary issue, retry later

Error response format

When an error occurs, the API returns:

{
"error": "Service temporarily unavailable"
}

Or for internal errors:

{
"error": "Internal Server Error"
}

Handling errors in code

try {
const response = await fetch('https://api.edrone.me/recommend', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody)
});

if (!response.ok) {
// Handle HTTP errors
console.error('Recommend API error:', response.status);
return showFallbackProducts(); // Show bestsellers, etc.
}

const data = await response.json();

if (data.error) {
// Handle API-level errors
console.error('API error:', data.error);
return showFallbackProducts();
}

return data;
} catch (error) {
// Handle network errors
console.error('Network error:', error);
return showFallbackProducts();
}

Troubleshooting

No recommendations returned

  1. Check App ID - Verify you're using the correct App ID
  2. Product feed - Ensure products exist in your edrone product feed
  3. Interaction history - Send at least some product interactions
  4. Product IDs match - Verify product IDs match your product feed

Recommendations not personalized

  • Send more interaction history (minimum 3-5 interactions)
  • Include both product_view and add_to_cart events
  • Verify cId is consistent across sessions

Slow response times

  • Limit interaction history to last 100 items
  • Implement client-side caching
  • Use loading states for better UX