# Product catalog sync
Your product catalog powers personalization across User.com—abandoned cart emails display the exact products users left behind, recommendations surface relevant items, and automations trigger based on product attributes like price drops or stock changes. Without a synced catalog, these features have nothing to work with.
This guide covers the available sync methods and their trade-offs.
# Sync methods overview
User.com supports multiple ways to sync your product catalog:
| Method | Best for | Update frequency |
|---|---|---|
| XML feed (recommended) | Full catalog sync, bulk updates | Daily (automatic, at night). To sync more frequently, use the API trigger method described below. |
| REST API | Real-time updates, individual products | On-demand |
| CSV import | Bulk updates, adding custom attributes | Manual or scheduled |
| Frontend events | Supplementary updates from user browsing | Real-time |
We recommend the XML feed as your primary sync method. It handles bulk updates efficiently, integrates with existing e-commerce infrastructure (most platforms already generate Google Shopping feeds), and ensures complete catalog coverage.
The other methods serve as supplements—use REST API for real-time price or stock changes, CSV for one-time enrichment, and frontend events to fill gaps as users browse.
# XML feed (recommended)
An XML product feed synchronizes your entire catalog with User.com in bulk. If you already generate a feed for Google Shopping, you can likely use it directly—or with minor modifications for optimal User.com compatibility.
# Why XML feed is the primary method
- Complete catalog coverage — All products available for recommendations and personalization from day one
- Authoritative product data — Prices, availability, and details come from your source of truth
- Bulk updates — Change thousands of products in a single sync
- Rich attributes — Sale prices, promotional dates, stock levels, and custom fields for segmentation and dynamic content
- E-commerce platform compatibility — Most platforms already generate Google Shopping feeds
# Feed format
User.com accepts XML feeds compatible with the Google Merchant Center specification. If you already generate a feed for Google Shopping, you can likely use it directly—or with minor modifications for optimal User.com compatibility.
# Basic structure
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
<channel>
<title>Your Store Product Feed</title>
<link>https://yourstore.com</link>
<description>Product catalog</description>
<item>
<g:id>SKU-12345</g:id>
<g:title>Wireless Bluetooth Headphones</g:title>
<g:description>Premium noise-canceling headphones with 30-hour battery life</g:description>
<g:link>https://yourstore.com/products/wireless-headphones</g:link>
<g:image_link>https://yourstore.com/images/headphones-main.jpg</g:image_link>
<g:price>149.99</g:price>
<g:availability>in stock</g:availability>
<g:brand>AudioTech</g:brand>
<g:product_type>Electronics > Audio > Headphones</g:product_type>
</item>
<!-- More items... -->
</channel>
</rss>
# Required attributes
Every product in your feed should include these core attributes:
| Attribute | Data Type | Description |
|---|---|---|
g:id | string | Your unique product identifier (SKU or internal ID). Must match the product_id you use in frontend product events. |
g:title | string | Product name as displayed to customers |
g:description | string | Short product description |
g:link | string | Full URL to the product page |
g:image_link | string | URL to the primary product image |
g:price | number | Product price (see Price formatting below) |
g:availability | string | Stock status: in stock, out of stock, preorder, or backorder |
g:product_type | string | Product category path (e.g., Clothing > Women > Dresses) |
# Additional image links
For products with multiple images, add numbered additional image attributes:
<g:additional_image_link_1>https://yourstore.com/images/headphones-side.jpg</g:additional_image_link_1>
<g:additional_image_link_2>https://yourstore.com/images/headphones-case.jpg</g:additional_image_link_2>
<g:additional_image_link_3>https://yourstore.com/images/headphones-worn.jpg</g:additional_image_link_3>
# Recommended additional attributes
These attributes enable richer segmentation and personalization:
# Sale and promotional pricing
| Attribute | Data Type | Description |
|---|---|---|
g:sale_price | number | Discounted price when product is on sale |
g:omnibus_price | number | Lowest price from 30 days before discount (EU Omnibus Directive compliance) |
g:sale_price_effective_date | string | Promotion date range in ISO 8601 format (see below) |
g:sale_price_active | boolean | Whether the sale price is currently active |
The sale_price_effective_date follows the Google format with start and end dates separated by a slash:
<g:sale_price_effective_date>2025-02-05T00:00:00+01:00/2025-06-01T23:59:59+02:00</g:sale_price_effective_date>
User.com automatically parses this into separate start and end date attributes.
Important: Either
sale_price_effective_dateorsale_price_activecan be used to determine if a sale price is currently active. See Understanding sync behavior for details.
# Product flags and inventory
| Attribute | Data Type | Description |
|---|---|---|
g:bestseller | boolean | Flag products as bestsellers |
g:new | boolean | Flag products as new arrivals |
g:quantity | integer | Stock quantity |
g:gtin | string | Global Trade Item Number (EAN/UPC/ISBN) |
# Price formatting
This is a common point of confusion. Google Merchant Center feeds typically include a currency suffix:
<!-- Google format - NOT recommended for User.com -->
<g:price>129.99 PLN</g:price>
User.com interprets this as a string, not a number. This breaks:
- Segmentation: You can't create segments like "products over $50" because text values don't support numeric comparisons (
<,>,>=) - Dynamic calculations: Snippet Tags and dynamic content can't perform math on text values
- Price range filters: Any filter requiring numeric operations will fail
Use numeric values without currency:
<!-- Recommended for User.com -->
<g:price>129.99</g:price>
<g:sale_price>99.99</g:sale_price>
<g:omnibus_price>119.99</g:omnibus_price>
Apply this to all price-related attributes: price, sale_price, omnibus_price, and any custom price fields.
# Understanding sync behavior
Product feed synchronization in User.com is append-only. This has important implications:
# What sync does
- ✅ Adds new products that don't exist yet
- ✅ Adds new attributes to existing products
- ✅ Updates the value of existing attributes
# What sync does NOT do
- ❌ Does not remove attributes if they disappear from the feed
- ❌ Does not remove products that are no longer in the feed
# Why this matters: The sale price problem
Consider this scenario:
- Monday: Product sync runs. Product has
sale_price: 79.99 - Wednesday: Promotion ends. You remove
sale_pricefrom the feed entirely - Thursday: Sync runs. In User.com, the product still has
sale_price: 79.99
The sync saw no sale_price attribute, but absence doesn't mean "delete." The old value persists.
Solution: Use explicit signals instead of attribute presence:
<!-- During promotion -->
<g:sale_price>79.99</g:sale_price>
<g:sale_price_active>true</g:sale_price_active>
<g:sale_price_effective_date>2025-01-01T00:00:00+00:00/2025-01-15T23:59:59+00:00</g:sale_price_effective_date>
<!-- After promotion ends -->
<g:sale_price>79.99</g:sale_price>
<g:sale_price_active>false</g:sale_price_active>
Now your automations and segments can filter on sale_price_active = true instead of checking whether sale_price exists.
# The discontinued product problem
Similar logic applies to product availability:
- Monday: Product syncs with
availability: in stock - Tuesday: Product is discontinued and removed from your feed entirely
- Wednesday: Sync runs. In User.com, product still shows
availability: in stock
Solution: Never remove products from the feed. Instead, update their status:
<!-- Mark as unavailable instead of removing -->
<g:availability>out of stock</g:availability>
Or add a dedicated attribute:
<g:active_product>false</g:active_product>
Once a product is marked unavailable in User.com, you can safely remove it from future feed exports.
# Setting up attributes before sync
When a product contains an attribute that doesn't exist in your User.com app, the system creates it automatically with a string data type. This can cause problems for attributes that should be numeric or boolean.
Before your first sync, manually create attributes with the correct data type:
- Go to Settings → Workspace Settings → Products → Product attributes
- Create each custom attribute with the appropriate type:
| Attribute | Recommended Type |
|---|---|
price, sale_price, omnibus_price etc. | Float |
sale_price_active, bestseller, new | Boolean |
sale_price_effective_date | Datetime |
Standard Google Merchant attributes (id, title, description, link, image_link, availability, brand, product_type) are handled automatically with correct types.
# Configuring your feed
To add a product feed in User.com:
- Go to Settings → Workspace settings → Products → Product feeds
- Click Add new feed
- Enter your feed URL (must be publicly accessible)
- Save and run an initial sync
Once configured, the feed will automatically sync once per day at night. To sync more frequently, use the API trigger method described below.
# Feed URL requirements
- Must be accessible via HTTPS without authentication
- Should return valid XML with UTF-8 encoding
- For large catalogs (50,000+ products), consider compressing with gzip
# Triggering feed sync via API
By default, product feeds sync automatically once per day at night. To sync more frequently (e.g., hourly after inventory updates), you can trigger a feed sync programmatically:
curl -X POST \
"https://YOUR_SUBDOMAIN.user.com/api/public/products/feed_synchronization/FEED_ID/" \
-H "Authorization: Token YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: */*; version=2"
Replace FEED_ID with the numeric ID of your feed (visible in feed settings).
Response:
{"success": "Product feed import has started!"}
This is useful for triggering syncs after bulk inventory updates or price changes in your e-commerce platform. You can set up a scheduled job (e.g., via cron) to call this endpoint hourly or on-demand when your catalog changes.
# Verification
After your first sync:
- Go to Data → Products and verify products appear with correct data
- Check a few products to confirm:
- Prices are numeric (not showing currency suffix)
- Boolean attributes show as true/false toggles
- Images and links load correctly
- Create a test segment using a numeric price filter to confirm comparisons work
# REST API (real-time sync)
Products can be created and updated in real-time using the User.com REST API. Use this method when you need immediate updates—for example, when a product price changes or stock runs out.
# Create a product
Full API reference → (opens new window)
POST /products/
headers = {
'authorization': "Token <your_64_char_api_key>",
'Accept': "*/*; version=2",
'content-type': "application/json"
}
body = {
'custom_id': product_id,
'attribute': value
}
# Update a product
Full API reference → (opens new window)
PUT /products-by-id/:product_id/
headers = {
'authorization': "Token <your_64_char_api_key>",
'Accept': "*/*; version=2",
'content-type': "application/json"
}
body = {
'attribute': value
}
# CSV import (bulk)
User.com importers allow bulk data imports. Use them for basic synchronization or enriching your product data with additional attributes.
# Manual import via UI
Agents can update the product database by importing CSV files through the User.com interface. While not reliable for maintaining an up-to-date product database, it's useful for:
- Adding additional custom dimensions (product attributes)
- One-shot actions and segmentations (e.g., adding a tag to a product group)
# Automated import via REST API
Full API reference → (opens new window)
The same CSV import method is available through the REST API. This can serve as an alternative to the XML product feed or act as a supplementary data source.
# Frontend updates (client-side)
You can use customers browsing your site as a source of product data updates. When a user visits a product page, the frontend event can update product attributes in User.com.
userengage('product_event', {
product_id: product_id,
event_type: event_type,
attribute: value
});
Adding attributes in the payload updates the product with those values.
WARNING
Product attributes are updated with the latest values sent. Historical values aren't stored—each new event overwrites the product's profile with the latest information.
# Next steps
With your catalog synced, you're ready to:
- Track product events to capture user interactions
- Set up product recommendations using your synced catalog
- Build abandoned cart automations that display product images and details