Skip to main content
Build product comparison tools that help users make informed purchasing decisions. Catalog’s product endpoints provide detailed, normalized product data that makes comparing products across different vendors straightforward.

Overview

Product comparison helps users:
  • Evaluate alternatives side-by-side
  • Compare key attributes like price, materials, features, and specifications
  • Make informed decisions based on normalized data

Core Concepts

Normalized Product Data

Catalog provides normalized product data with consistent structure across different vendors:
  • Pricing: Normalized price amounts and currency
  • Attributes: Standardized attribute structure (color, material, style, etc.)
  • Variants: Consistent variant information
  • Availability: Standardized availability status

Comparison Dimensions

Compare products across multiple dimensions:
  • Price: Current price, price ranges, sale status
  • Specifications: Materials, dimensions, care instructions
  • Attributes: Style, color, aesthetic, features
  • Availability: Stock status, variant availability

Building Your Comparison Tool

Step 1: Retrieve Products

Retrieve products you want to compare using the Get Products endpoint:
import requests
import time
import os

def retrieve_products_for_comparison(urls):
    """Retrieve products for comparison"""
    # Start async batch processing
    response = requests.post(
        'https://api.getcatalog.ai/v1/products',
        headers={
            'Content-Type': 'application/json',
            'x-api-key': os.getenv('CATALOG_API_KEY')
        },
        json={
            'urls': urls,
            'enable_enrichment': True,  # Enable enrichment for better attributes
            'country_code': 'us'
        }
    )
    
    data = response.json()
    execution_id = data['execution_id']
    print(f"Processing started: {execution_id}")
    
    # Poll for results
    return poll_for_results(execution_id)

def poll_for_results(execution_id):
    """Poll for execution results"""
    while True:
        response = requests.get(
            f'https://api.getcatalog.ai/v1/products/{execution_id}',
            headers={'x-api-key': os.getenv('CATALOG_API_KEY')}
        )
        
        data = response.json()
        
        if data['status'] == 'completed':
            # Extract successful products
            return [
                item['product']
                for item in data['data']
                if item['success'] and item.get('product')
            ]
        elif data['status'] == 'failed':
            raise Exception(f"Processing failed: {data.get('error', 'Unknown error')}")
        
        # Wait before next poll
        time.sleep(2)

# Usage
product_urls = [
    'https://www.nike.com/t/air-force-1-07-mens-shoes-5QFp5Z/CW2288-111',
    'https://www.adidas.com/us/gazelle-shoes/BB5476.html'
]

products = retrieve_products_for_comparison(product_urls)
print(f"Retrieved {len(products)} products for comparison")

Step 2: Extract Comparison Attributes

Extract and normalize comparison attributes from product data:
def extract_comparison_attributes(product):
    """Extract comparison attributes from product data"""
    attrs = product.get('attributes', {})
    
    return {
        # Basic info
        'title': product.get('title'),
        'brand': product.get('brand'),
        'vendor': product.get('vendor'),
        'url': product.get('url'),
        
        # Pricing
        'price': product.get('price_amount'),
        'currency': product.get('price_currency'),
        'min_price': product.get('min_price'),
        'max_price': product.get('max_price'),
        'on_sale': product.get('min_price', 0) < product.get('max_price', 0),
        
        # Availability
        'available': product.get('is_available', False),
        'available_variants': len([v for v in product.get('variants', []) if v.get('isAvailable')]),
        'total_variants': len(product.get('variants', [])),
        
        # Attributes
        'color': attrs.get('color', {}).get('merchant_label') or attrs.get('color') or 'N/A',
        'material': attrs.get('material', {}).get('primary') or attrs.get('material') or 'N/A',
        'style': attrs.get('style', []),
        
        # Media
        'image_count': len(product.get('images', [])),
        'primary_image': product.get('images', [{}])[0].get('url') if product.get('images') else None,
        
        # Description
        'summary': attrs.get('summary') or product.get('description', '')[:200] or ''
    }

# Extract attributes for all products
comparison_data = [extract_comparison_attributes(p) for p in products]
print('Comparison attributes extracted')

Step 3: Create Comparison

Build a comparison class to organize and display products side-by-side:
class ProductComparison:
    def __init__(self, products):
        self.products = [extract_comparison_attributes(p) for p in products]
    
    def generate_comparison_table(self):
        """Generate comparison table data"""
        rows = [
            {
                'label': 'Product',
                'values': [
                    {
                        'title': p['title'],
                        'brand': p['brand'],
                        'image': p['primary_image']
                    }
                    for p in self.products
                ]
            },
            {
                'label': 'Price',
                'values': [f"${p['price']} {p['currency']}" for p in self.products]
            },
            {
                'label': 'Price Range',
                'values': [
                    f"${p['min_price']}" if p['min_price'] == p['max_price']
                    else f"${p['min_price']} - ${p['max_price']}"
                    for p in self.products
                ]
            },
            {
                'label': 'Availability',
                'values': [
                    f"In Stock ({p['available_variants']}/{p['total_variants']} variants)"
                    if p['available']
                    else 'Out of Stock'
                    for p in self.products
                ]
            },
            {
                'label': 'Color',
                'values': [p['color'] for p in self.products]
            },
            {
                'label': 'Material',
                'values': [p['material'] for p in self.products]
            },
            {
                'label': 'Style',
                'values': [', '.join(p['style']) if p['style'] else 'N/A' for p in self.products]
            }
        ]
        return rows
    
    def find_best_value(self):
        """Find best value (lowest price among available products)"""
        available = [p for p in self.products if p['available']]
        if not available:
            return None
        
        return min(available, key=lambda p: p['price'])
    
    def get_summary(self):
        """Get comparison summary"""
        best_value = self.find_best_value()
        all_available = all(p['available'] for p in self.products)
        prices = [p['min_price'] for p in self.products]
        
        return {
            'total_products': len(self.products),
            'all_available': all_available,
            'best_value': {
                'title': best_value['title'],
                'price': best_value['price'],
                'currency': best_value['currency']
            } if best_value else None,
            'price_range': {
                'min': min(prices),
                'max': max(prices)
            }
        }

# Usage
comparison = ProductComparison(products)
table = comparison.generate_comparison_table()
summary = comparison.get_summary()

print('Comparison Summary:', summary)
for row in table:
    print(f"{row['label']}: {row['values']}")

Step 4: Error Handling

Handle cases where some products fail to retrieve:
def retrieve_products_with_errors(urls):
    """Retrieve products with error handling"""
    response = requests.post(
        'https://api.getcatalog.ai/v1/products',
        headers={
            'Content-Type': 'application/json',
            'x-api-key': os.getenv('CATALOG_API_KEY')
        },
        json={
            'urls': urls,
            'enable_enrichment': True,
            'country_code': 'us'
        }
    )
    
    data = response.json()
    execution_id = data['execution_id']
    results = poll_for_results(execution_id)
    
    successful = []
    failed = []
    
    for result in results:
        if result.get('success') and result.get('product'):
            successful.append(result['product'])
        else:
            failed.append({
                'url': result.get('url'),
                'reason': result.get('outcome', 'Unknown error')
            })
    
    return {
        'products': successful,
        'errors': failed,
        'success_rate': (len(successful) / len(urls)) * 100 if urls else 0
    }

Best Practices

Enable Enrichment

Always enable enable_enrichment: true when retrieving products for comparison. This provides richer, normalized attributes that make comparisons more meaningful.
Enrichment provides:
  • Better attribute extraction
  • Normalized color and material information
  • Enhanced style and feature descriptions
  • Consistent data structure across vendors

Handle Missing Data

Not all products will have all attributes. Handle missing data gracefully:
function safeGetAttribute(product, path, defaultValue = 'N/A') {
  const keys = path.split('.');
  let value = product;
  
  for (const key of keys) {
    if (value && typeof value === 'object' && key in value) {
      value = value[key];
    } else {
      return defaultValue;
    }
  }
  
  return value || defaultValue;
}
def safe_get_attribute(product, path, default='N/A'):
    """Safely get nested attribute with default value"""
    keys = path.split('.')
    value = product
    
    for key in keys:
        if isinstance(value, dict) and key in value:
            value = value[key]
        else:
            return default
    
    return value or default

Batch Requests

Retrieve all products in a single batch (up to 1000 URLs) for better performance and consistency.