Sync Product Catalog to Facebook: Dynamic Ads

Sync Product Catalog to Facebook: Dynamic Ads

Sync product catalog to Facebook for Dynamic Ads in 30 minutes. Shopify or Postgres source, 15-minute inventory updates, no warehouse required.

No credit card required

Free 100k syncs every month

A Dynamic Ads campaign is only as fresh as the product feed behind it. When a SKU sells out on Saturday morning and the catalog upload runs Monday, you spend two days paying for clicks that land on a sold-out PDP. Most published guides tell you to fix this by routing your products through Snowflake or BigQuery first, then a reverse-ETL tool to Meta. For DTC and ecommerce teams under 200 people, that is two pieces of infrastructure you do not have and do not need.

This guide walks the direct path to sync product catalog to facebook: Shopify (or BigCommerce, or a Postgres products table) straight into your Meta Product Catalog, with inventory and price changes propagating every 15 minutes. No warehouse, no SQL modeling, no nightly CSV ritual.

Why a stale product catalog kills Facebook Dynamic Ads performance

Dynamic Ads work by matching a viewer's browsing or purchase signal to the right product in your catalog. The match is only useful if the catalog reflects what is actually buyable right now.

Three failure modes show up in every audit of an underperforming Dynamic Ads account:

  • Out-of-stock products keep serving. Inventory updates run nightly. A product sells out at 9am, but ads keep showing it until the next refresh. Click-through rates hold up because the creative still looks good. Conversion rates collapse.

  • Sale prices lag behind the storefront. Marketing kicks off a 24-hour flash sale at noon. The catalog feed updates the next morning. Half the campaign ran with the original price visible, undercutting the sale message.

  • New launches land in the catalog days late. A drop hits the storefront on Thursday. The product feed includes it on Saturday. Two days of organic launch buzz happen with no Dynamic Ads support behind them.

The root cause in every case is the same: the catalog sync cadence does not match the rate at which inventory and pricing actually change. A nightly batch worked when ads ran for a quarter against a static SKU list. It does not work when SKUs turn over weekly and prices move daily.

The fix is a faster facebook product catalog sync, not a smarter campaign. If your sync cadence is shorter than your inventory and pricing volatility, Dynamic Ads do their job. If it is longer, no amount of creative testing will compensate.

What product catalog fields to sync to Meta (id, title, price, availability, image_link)

Meta's product catalog feed spec defines a set of required fields and a longer list of recommended ones. Send the required fields well and you will pass diagnostics. Send the recommended ones and you will unlock more ad placements (Marketplace, Shops, Reels) and higher event match quality.

Meta field

Source value

Required

Notes

id

Shopify variant ID or SKU

Yes

Stable, unique per variant. Reuse this same id in Pixel events for matching.

title

Shopify product title

Yes

Max 150 characters, no all-caps.

description

Shopify product description

Yes

Plain text or limited HTML. Strip storefront-only markup.

availability

derived from inventory_quantity

Yes

Values: in stock, out of stock, preorder, available for order, discontinued.

condition

usually "new"

Yes

new, refurbished, or used.

price

variant price + ISO currency

Yes

Format: "19.99 USD". One row per currency for multi-market.

image_link

first product image URL

Yes

HTTPS only. At least 500 by 500 pixels.

link

Shopify storefront URL

Yes

Full HTTPS URL to the PDP, no tracking params Meta cannot strip.

brand

Shopify vendor or product type

Yes

Defaults to your store name if empty.

google_product_category

mapped from product type

Recommended

Drives Marketplace eligibility. Use Google's taxonomy.

sale_price

discounted price + currency

Recommended

Triggers strikethrough pricing in ad creative.

item_group_id

parent product handle

Recommended

Groups variants (size, color) so Meta picks the best one per viewer.

Two fields cause most of the rejected-product warnings in Meta Commerce Manager. The first is image_link — Meta requires HTTPS, rejects images under 500 by 500 pixels, and silently skips broken URLs. The second is availability — Meta accepts a fixed enum, not arbitrary inventory text. "Low stock", "backorder", "coming soon" all need to map to one of the five accepted values or the row gets thrown out.

Step-by-step: sync your product catalog from Shopify or Postgres to Meta

The setup takes about 30 minutes end to end. The longest part is verifying the first sync against Meta's diagnostics view, not the configuration itself.

1. Connect Shopify (or BigCommerce, Postgres, MySQL). In Oneprofile, add a source. For Shopify, use an Admin API token with read access to Products and Inventory. For Postgres or MySQL, use a read-only role on your products table. Oneprofile reads the schema at connect time, so you see the available columns immediately. No declaration files, no dbt project.

2. Connect Meta Ads as the destination. Add Meta Ads. Authenticate with a Meta System User access token that has the catalog_management permission. Select the Catalog ID for the Business Manager catalog Dynamic Ads will read from. If you do not have a catalog yet, create one in Commerce Manager first — Oneprofile cannot create the catalog itself, only populate it.

3. Map the source columns to the Meta product catalog feed spec. Use the table above. Most Shopify stores need three small transformations: derive availability from inventory_quantity (greater than zero is "in stock"), concatenate price and currency code into the "19.99 USD" format, and prefix image_link with HTTPS if your storefront serves protocol-relative URLs. Each transformation runs in the field mapping layer, no source-side scripts.

4. Pick a sync mode. Use "Update or Create". This adds new products on first sight and updates existing ones on subsequent runs. Reserve "Mirror" mode (which removes products from Meta when they disappear from the source) for clean migrations, not steady-state operation — you do not want a temporary outage on the source side wiping your catalog in Meta.

5. Set the schedule. Every 15 minutes is the right default for inventory and pricing. For event-driven sources like Shopify, enable webhooks on products/update and inventory_levels/update so critical changes (a SKU selling out, a price drop) push within seconds. Run a full refresh nightly to catch any drift between the incremental syncs and the source state.

6. Run the first sync and verify in Commerce Manager. The initial run backfills every product. Open Commerce Manager > Catalog > Diagnostics. Healthy feed, full item count, zero rejected items is the goal. Common first-run issues: image URLs over plain HTTP, descriptions with storefront-only HTML, missing brand on store-brand products. Fix at the source, rerun, repeat until diagnostics is green.

7. Wire the catalog to a Dynamic Ads campaign. In Ads Manager, create a Catalog Sales campaign and pick your synced catalog. Pair it with a working Meta Pixel and Conversions API setup so view, cart, and purchase signals reach the bidder. The catalog feed and the event signals are independent inputs to Dynamic Ads — both have to be healthy for the campaign to optimize.

Field mapping and Meta product catalog feed spec requirements

A few field-level rules trip up almost every first-time setup. They are the same gotchas the warehouse-first guides skip past because warehouse data is assumed to already be clean.

image_link must be HTTPS and properly sized. Shopify and BigCommerce serve HTTPS by default, so this is rarely an issue from a hosted platform. Custom Postgres setups often store relative paths or HTTP URLs from a CDN that supports both. Concatenate the HTTPS prefix during mapping. Resize at the source if your hero images are smaller than 500 by 500.

availability accepts only five values. in stock, out of stock, preorder, available for order, discontinued. Anything else gets the row rejected. The cleanest derivation: inventory_quantity > 0 becomes "in stock", = 0 becomes "out of stock", non-zero with a available_at future date becomes "preorder". For finite drops, map sold-through products to "discontinued" so they leave Dynamic Ads rotation entirely.

price needs the currency code in the same string. Meta wants "19.99 USD", not 19.99 with a separate currency column. Concatenate variant_price and currency_code during mapping. For multi-currency stores, send one row per currency variant with a suffix on id (e.g., 12345-USD, 12345-GBP).

item_group_id is what powers variant selection. A T-shirt sold in five sizes and three colors is fifteen Meta product entries grouped under one item_group_id. Without this, Meta picks one row at random when serving the ad and ignores the rest. Set item_group_id to the Shopify product handle or the parent SKU; set unique id per variant.

google_product_category opens Marketplace and Shops placements. Use the official Google taxonomy ID, not the human-readable label. Most Shopify stores already have a product_type field that can be statically mapped to a Google category through a lookup table. Add it once during setup, forget about it.

sale_price plus sale_price_effective_date drives the strikethrough creative. When a product is on sale, set sale_price to the discounted amount and sale_price_effective_date to the start and end of the promotion in ISO 8601 (e.g., 2026-05-15T00:00:00-08:00/2026-05-22T23:59:59-08:00). Meta then renders the original price struck through next to the sale price, which lifts CTR on every internal A/B we have seen.

Keeping inventory and pricing fresh: sync cadence and edge cases for Dynamic Ads

Picking the right cadence is a balance between freshness and cost. Faster is not always better — every sync run uses some Meta API quota and Oneprofile sync actions, so the schedule should match the rate at which the data actually changes.

A pattern that works for most ecommerce teams:

  • 15-minute incremental sync for inventory and pricing. Catches stock changes and price tests without burning rate limits.

  • Webhook-driven push for critical events (product create, inventory_levels/update). Bypasses the schedule entirely for changes that need to land in seconds — a flash sale starting, a hero product selling out.

  • Nightly full refresh to catch drift. Re-reads every product, compares against Meta's catalog state, fixes anything that fell out of sync (e.g., a webhook missed during a Meta API outage).

A few edge cases come up enough to plan for before they bite:

  • Multi-market stores. Sending the same SKU at different prices and locales requires either separate Meta catalogs per market or unique id per market within one catalog. We recommend separate catalogs — easier to scope Dynamic Ads campaigns by region, easier to debug.

  • Variant explosions. A configurable product with five sizes, three colors, and two materials is thirty rows in Meta. Make sure your sync action budget accounts for the variant count, not just the parent product count.

  • Currency rounding. Floating-point conversion from Shopify cents to a string with two decimals is the source of more bug reports than it should be. Round half-up at two decimals during mapping.

When this is wired up correctly, the Monday-morning CSV upload disappears. A SKU sells out at 9:07am and stops serving in Dynamic Ads by 9:22am. A price drop ships at noon and ad creative reflects it before the next bid auction round. New launches land in the catalog within seconds of going live on the storefront. Dynamic Ads stops being a maintenance burden and starts being a campaign you can actually trust to spend the budget on inventory you can fulfill.

Ready to get started?

No credit card required

Free 100k syncs every month

Ready to get started?

No credit card required

Free 100k syncs every month

Ready to get started?

No credit card required

Free 100k syncs every month

Do I need a data warehouse to sync my product catalog to Facebook?

How often does the product catalog sync to Meta refresh?

Which fields does Meta require in a product catalog feed?

What happens when a product goes out of stock in Shopify?

Can I sync multiple Shopify stores or markets to one Meta catalog?

Does this work for BigCommerce, Magento, or a custom Postgres product table?