Skip to main content
Build AI-powered shopping assistants that understand natural language queries and personalize recommendations. Catalog’s POST /v1/agentic-search provides the intelligence you need to create conversational shopping experiences.

Overview

AI shopping assistants help users find products through natural language. They:
  • Understand context from conversational queries
  • Learn preferences from user interactions
  • Provide personalized recommendations
  • Guide discovery with clarifying questions

Core Concepts

Natural Language Queries

Catalog’s Agentic Search understands complex, conversational queries without requiring structured filters:
// Examples of natural language queries
const queries = [
  "I need a jacket for my office job that's not too formal",
  "Show me sustainable dresses for a summer wedding",
  "I want sneakers for daily walks that are comfortable and stylish"
];

Customer Profiles

Build customer profiles to improve personalization. Profiles can include:
  • Style preferences: fit, color, aesthetic, silhouettes
  • Usage context: activities, environment, travel needs
  • Purchase behavior: value priorities, buying frequency
  • Avoids: things the customer doesn’t like

Building Your Assistant

Start with a simple search using natural language queries:
import requests
import os

def search_products(query, customer_profile=None):
    """Search for products using natural language query"""
    payload = {'query': query}
    
    if customer_profile:
        payload['customer_profile'] = customer_profile
    
    response = requests.post(
        'https://api.getcatalog.ai/v1/agentic-search',
        headers={
            'Content-Type': 'application/json',
            'x-api-key': os.getenv('CATALOG_API_KEY')
        },
        json=payload
    )
    
    data = response.json()
    return data['products']  # Array of products

# Example usage
products = search_products(
    "I need a versatile blazer for work and casual outings"
)
print(f"Found {len(products)} products")

Step 2: Customer Profiles

Create and use customer profiles to personalize search results:
def build_profile(form_data):
    """Build a customer profile from user preferences"""
    return {
        'style': {
            'fit': form_data.get('fit'),
            'color': form_data.get('color_preference'),
            'aesthetic': form_data.get('aesthetics', []),
            'silhouette': form_data.get('silhouettes', []),
            'avoid': form_data.get('avoid_items', [])
        },
        'preferences': {
            'in_stock_only': form_data.get('in_stock_only', True),
            'comfort_priority': form_data.get('comfort_priority', False)
        },
        'usage_context': {
            'activities': form_data.get('activities', []),
            'environment': form_data.get('environment'),
            'travel_friendly': form_data.get('travel_friendly')
        },
        'purchase_behavior': {
            'value': form_data.get('value_proposition'),
            'buying_frequency': form_data.get('buying_frequency')
        }
    }

# Example profile
profile = build_profile({
    'fit': 'relaxed',
    'color_preference': 'earth tones, neutrals',
    'aesthetics': ['minimal', 'understated'],
    'activities': ['office', 'coffee runs'],
    'comfort_priority': True,
    'in_stock_only': True
})

# Use profile in search
products = search_products(
    "A jacket suitable for the office",
    profile
)

Step 3: Simple Assistant

Build a basic assistant that handles queries and returns formatted results:
class ShoppingAssistant:
    def __init__(self, api_key):
        self.api_key = api_key
        self.profiles = {}  # In production, store in database
    
    def get_profile(self, user_id):
        """Get or create customer profile"""
        if user_id not in self.profiles:
            self.profiles[user_id] = {}
        return self.profiles[user_id]
    
    def search(self, user_id, query):
        """Search for products with user profile"""
        profile = self.get_profile(user_id)
        
        response = requests.post(
            'https://api.getcatalog.ai/v1/agentic-search',
            headers={
                'Content-Type': 'application/json',
                'x-api-key': self.api_key
            },
            json={
                'query': query,
                'customer_profile': profile if profile else None
            }
        )
        
        data = response.json()
        return data['products']
    
    def format_response(self, products, query):
        """Format search results for display"""
        if len(products) == 0:
            return {
                'message': "I couldn't find products matching your search. Try rephrasing or being more specific.",
                'products': []
            }
        
        formatted_products = []
        for product in products:
            formatted_products.append({
                'title': product.get('title'),
                'brand': product.get('brand'),
                'price': f"${product.get('price_amount', 0)}",
                'url': product.get('url'),
                'image': product.get('images', [{}])[0].get('url') if product.get('images') else ''
            })
        
        return {
            'message': f"I found {len(products)} products matching '{query}':",
            'products': formatted_products
        }

# Usage
assistant = ShoppingAssistant(os.getenv('CATALOG_API_KEY'))

response = assistant.search('user123', 'I need a jacket for work')
result = assistant.format_response(response, 'I need a jacket for work')

print(result['message'])
for product in result['products']:
    print(f"- {product['title']} by {product['brand']} - {product['price']}")

Step 4: Error Handling

Always handle errors gracefully:
def search_with_error_handling(query, profile=None):
    """Search with comprehensive error handling"""
    try:
        response = requests.post(
            'https://api.getcatalog.ai/v1/agentic-search',
            headers={
                'Content-Type': 'application/json',
                'x-api-key': os.getenv('CATALOG_API_KEY')
            },
            json={
                'query': query,
                'customer_profile': profile
            }
        )
        
        if response.status_code == 429:
            raise Exception('Rate limit exceeded. Please try again in a moment.')
        elif response.status_code == 401:
            raise Exception('Authentication failed. Please check your API key.')
        elif not response.ok:
            raise Exception(f'API error: {response.status_code}')
        
        data = response.json()
        
        if not data.get('products') or len(data['products']) == 0:
            return {
                'success': False,
                'message': "I couldn't find products matching your search.",
                'products': []
            }
        
        return {
            'success': True,
            'products': data['products'],
            'message': f"Found {len(data['products'])} products."
        }
    
    except Exception as error:
        return {
            'success': False,
            'message': f'An error occurred: {str(error)}',
            'products': []
        }

Best Practices

Profile Building

Build customer profiles incrementally through conversation rather than requiring lengthy onboarding forms. Extract preferences naturally from user queries.
  • Start with minimal profiles and enrich over time
  • Extract preferences from natural language queries
  • Store profiles securely and update them with each interaction

Response Formatting

Format product responses to be user-friendly:
  • Include key product details: title, brand, price, image
  • Provide direct links to purchase
  • Show relevant attributes (color, material, style)

Monetization

Monetize your shopping assistant by converting product URLs into affiliate tracking links. Use POST /v1/affiliate to create trackable affiliate links for products returned in search results. This allows you to earn commissions when users make purchases through your assistant.

Rate Limiting

Respect API rate limits and implement appropriate retry logic:
  • Default: 50 requests per 4-second sliding window
  • Implement exponential backoff for retries
  • Use POST /v1/agentic-search-mini for high-frequency preview features
See Rate Limits for detailed information.