---
name: set-up-product-catalog
description: >-
  Builds a Meta product catalog from zero to live and populated: inventories any catalogs that
  already exist, picks the data source (scheduled feed URL, pixel/microdata, a partner platform
  connector, or direct API upsert via mads_upsert_catalog_products), maps the required item fields
  (id/retailer_id, title, description, availability, condition, price+currency, link, image_link,
  brand, GTIN), connects the pixel so dynamic events can match, and defines at least one product
  set so ad sets have something to target. Catalog creation itself is a HUMAN STEP in Commerce
  Manager, no mads_* tool creates one. Reach for it onboarding a new ecommerce advertiser, adding
  a catalog for a new market or business unit, or whenever mads_list_catalogs comes back empty. It
  ends at a live, populated, pixel-linked catalog, it does not police ongoing feed quality
  (maintain-catalog-feed-hygiene) or build the dynamic ads themselves
  (launch-advantage-plus-catalog-ads).
---
# Set Up a Meta Product Catalog

## Purpose
A product catalog is the Business Manager asset every commerce ad format depends on, Advantage+
catalog ads, Collection ads, and dynamic retargeting all read from it. Without a populated,
correctly-fielded catalog wired to a pixel, none of those formats have anything to render. This
skill takes an account from no-catalog (or an empty one) through data-source selection, field
mapping, pixel connection, and a first product set, to a catalog that is genuinely ready for ads
to be built on top of it.

## When to run
- A new ecommerce/retail advertiser has no product catalog yet.
- `mads_list_catalogs` returns nothing, or returns a catalog with zero or stale items.
- Standing up a catalog for a new market, brand, or business unit inside the same Business Manager.
- Prepping an account for `launch-advantage-plus-catalog-ads` or `build-collection-ads-and-product-sets`
  and the catalog gate isn't met.

## When NOT to run
- A catalog exists and is populated, but items are erroring, mismatching the pixel, or getting
  disapproved → `maintain-catalog-feed-hygiene`.
- The catalog is healthy and the task is building the actual dynamic ads →
  `launch-advantage-plus-catalog-ads`.
- The task is curated/filtered product sets or a Collection ad on a catalog that already exists →
  `build-collection-ads-and-product-sets`.

## Prerequisites
- Business Manager admin access with `catalog_management` scope granted to the token, HUMAN STEP
  if it isn't.
- A decision, or a business owner able to make one, on data source: feed file, scheduled feed URL,
  pixel/microdata, a partner platform (Shopify, WooCommerce, etc.), or direct API upsert.
- Product data ready in some source (spreadsheet, platform export) with, at minimum, id, title,
  price, and availability per item.
- A pixel already created for the business, even if not yet firing catalog-matched events, `mads_list_pixels` to confirm.

## Procedure
1. **Inventory what already exists.** Call `mads_list_catalogs`. A stale or empty catalog is a
   revive, not a fresh build, reuse its ID rather than creating a duplicate.
2. **IF no catalog exists, THEN create one.** HUMAN STEP (outside VigilDog): create the catalog in
   Commerce Manager (name, vertical = ecommerce, associated Business Manager). No `mads_*` tool
   creates a catalog, `mads_list_catalogs` only inventories ones that already exist.
3. **Choose the data source with the user.** Feed URL for a catalog that changes on its own
   schedule, a partner platform connector for Shopify/WooCommerce-style stores, pixel/microdata
   only when there's no other way to describe the inventory, or direct API upsert for small or
   VigilDog-managed catalogs. See Decision rules.
4. **API-upsert path: prepare and stage the rows.** Pull source data (`sheets_get_values` when the
   catalog lives in a spreadsheet, or the platform export), map every required field, id
   (retailer_id), title, description, availability, condition, price with currency, link,
   image_link, brand, and GTIN where it exists. Screen out anything locally-illegal or
   IP-infringing before it ever reaches the batch.
5. **Preview, approve, commit the batch.** Show the user a plain-English diff (item count, sample
   rows, anything screened out), get explicit approval, then call `mads_upsert_catalog_products`.
   It's idempotent on retailer_id, so re-running the same batch corrects rather than duplicates.
6. **Feed URL / partner path: configure, then verify from the ads side.** HUMAN STEP (outside
   VigilDog): set up the data source and refresh schedule in Commerce Manager. VigilDog's job is
   verification, `mads_list_catalogs` after the first fetch to confirm items landed.
7. **Connect and confirm the pixel.** Call `mads_list_pixels`, confirm the catalog is associated
   with the same pixel that will fire ViewContent/AddToCart/Purchase. Deep content_id/content_type
   matching is `maintain-catalog-feed-hygiene`'s job, not this skill's, here you're only
   confirming the pixel exists and is attached.
8. **Define a first product set.** At minimum, an "all products" set so ad sets have something to
   target, HUMAN STEP in Commerce Manager, or via the catalog's product-set edge if the tooling
   exposes it. Purpose-built filtered sets (category, price band, margin, performance tier) are
   `build-collection-ads-and-product-sets`'s job.
9. **Verify the catalog is genuinely ready.** `mads_list_catalogs` item count > 0 and in the
   expected range; spot-check a handful of items for the required fields; confirm
   `catalog_management` scope is live.
10. **Hand off.** Record catalog ID, item count, pixel ID, and product-set ID(s) for the next
    skill. Route to `launch-advantage-plus-catalog-ads`.

## Decision rules
- **Data-source matrix:** small, stable catalog (roughly <50 SKUs) VigilDog controls directly →
  API upsert; Shopify/WooCommerce/BigCommerce-style store → partner platform connector; a catalog
  that changes on the merchant's own schedule outside any connector → scheduled feed URL;
  pixel/microdata only as a last resort when no structured export exists.
- **Scope gate:** IF `catalog_management` is not granted, THEN stop before any write, no upsert
  or product-set call will succeed without it.
- **Pixel gate:** IF no pixel exists yet, THEN still finish the catalog build, but flag that
  `launch-advantage-plus-catalog-ads` is blocked until `set-up-pixel-and-standard-events` runs.
- **Idempotency is the safety net, not a license.** `mads_upsert_catalog_products` correcting on
  retry only works if retailer_id stays stable, never regenerate IDs between batches.
- **Done means:** a catalog ID exists with item count > 0, sampled items carry all required
  fields, a pixel is attached, at least one product set is defined, and `catalog_management` scope
  is confirmed live.

## Common failure modes
- **Trying to create a catalog by API.** There is no `mads_*` create-catalog call, attempting to
  work around Commerce Manager wastes a cycle. It's a HUMAN STEP, every time.
- **Missing GTIN/brand.** Weakens matching and can trigger restricted-category rejections that a
  GTIN would have cleared automatically.
- **Price without currency, or a currency mismatch against the storefront.** Both cause silent
  disapprovals downstream.
- **Skipping the product set.** Ad-set creation in `launch-advantage-plus-catalog-ads` needs a set
  to target, leaving this step out just moves the blocker one skill later.
- **Unstable retailer_id across re-exports.** Breaks the idempotency the upsert depends on and
  erases matching history.
- **Uploading prohibited-category items** (tobacco, weapons, IP-infringing goods) without
  screening, they get rejected at the catalog level, not just the ad level.

## Related skills
- Run after: `maintain-catalog-feed-hygiene` (ongoing quality once live),
  `launch-advantage-plus-catalog-ads` (build the dynamic ads),
  `build-collection-ads-and-product-sets` (purpose-built product sets and the Collection format).
- Adjacent: `set-up-pixel-and-standard-events` (measurement) for pixel/event depth this skill only
  touches at a surface level.
