Skip to main content

Product catalog sync

Your product catalog powers personalization across User.com—abandoned cart emails display the exact products contacts 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:

MethodBest forUpdate frequency
XML feed (recommended)Full catalog sync, bulk updatesDaily (automatic, at night). To sync more frequently, use the API trigger method described below.
REST APIReal-time updates, individual productsOn-demand
CSV importBulk updates, adding custom attributesManual or scheduled
Frontend eventsSupplementary updates from contact browsingReal-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 contacts browse.


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:

AttributeData TypeDescription
g:idstringYour unique product identifier (SKU or internal ID). Must match the product_id you use in frontend product events.
g:titlestringProduct name as displayed to customers
g:descriptionstringShort product description
g:linkstringFull URL to the product page
g:image_linkstringURL to the primary product image
g:pricenumberProduct price (see Price formatting below)
g:availabilitystringStock status: in stock, out of stock, preorder, or backorder
g:product_typestringProduct category path (e.g., Clothing > Women > Dresses)

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>

These attributes enable richer segmentation and personalization:

Sale and promotional pricing​

AttributeData TypeDescription
g:sale_pricenumberDiscounted price when product is on sale
g:omnibus_pricenumberLowest price from 30 days before discount (EU Omnibus Directive compliance)
g:sale_price_effective_datestringPromotion date range in ISO 8601 format (see below)
g:sale_price_activebooleanWhether 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_date or sale_price_active can be used to determine if a sale price is currently active. See Understanding sync behavior for details.

Product flags and inventory​

AttributeData TypeDescription
g:bestsellerbooleanFlag products as bestsellers
g:newbooleanFlag products as new arrivals
g:quantityintegerStock quantity
g:gtinstringGlobal 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:

  1. Monday: Product sync runs. Product has sale_price: 79.99
  2. Wednesday: Promotion ends. You remove sale_price from the feed entirely
  3. 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:

  1. Monday: Product syncs with availability: in stock
  2. Tuesday: Product is discontinued and removed from your feed entirely
  3. 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 workspace, 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:

  1. Go to Settings → Workspace Settings → Products → Product attributes
  2. Create each custom attribute with the appropriate type:
AttributeRecommended Type
price, sale_price, omnibus_price etc.Float
sale_price_active, bestseller, newBoolean
sale_price_effective_dateDatetime

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:

  1. Go to Settings → Workspace Settings → Products → Product feeds
  2. Click Add new feed
  3. Enter your feed URL (must be publicly accessible)
  4. 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:

  1. Go to Data → Products and verify products appear with correct data
  2. 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
  3. 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 →

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 →

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​

Team members 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 →

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 contact 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.

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: