ADSX
JULY 1, 2026 // UPDATED JUL 1, 2026

Generate Channel Feeds with Shopify ProductFeed API

Build channel product feeds with Shopify's ProductFeed API: productFeedCreate, productFullSync, incremental sync, and the bridge to ad channels.

AUTHOR
AE
AdsX Engineering
SHOPIFY API & COMMERCE ENGINEERING
READ TIME
7 MIN
SUMMARY

Build channel product feeds with Shopify's ProductFeed API: productFeedCreate, productFullSync, incremental sync, and the bridge to ad channels.

The Shopify ProductFeed API (productFeedCreate plus productFullSync) turns your catalog into a live, channel-scoped feed that Shopify keeps in sync automatically. You create one ProductFeed per channel, run a full sync to load it, and then let incremental sync webhooks keep it current as products change. This is the build guide: real Admin GraphQL, the full-vs-incremental model, and why this feed is the bridge into Google, Meta, and AI ad channels.

Already know you want the API over a hand-rolled export? Good — this is that build. If you are still deciding, read Product Feed API vs CSV feeds first; this post does not re-argue that choice, it implements the winner. For the full catalog model and every related surface, start with the pillar Shopify Product Catalog API guide. Everything below uses the GraphQL Admin API at version 2026-01.

What a ProductFeed maps to

A ProductFeed is not a file — it is a live view of your catalog bound to a publication. A publication is Shopify's model for a sales or marketing channel: the Google & YouTube channel, the Facebook & Instagram channel, or your own custom app registered as a channel. One feed per channel, per country and language.

ConceptWhat it isWhy it matters
ProductFeedA channel-scoped, localized view of eligible productsThe unit an ad channel consumes
PublicationThe channel the feed is attached toDetermines which products are eligible
Full syncOne-time emit of the entire eligible catalogInitial load or full rebuild
Incremental syncAutomatic per-change deltas via webhookKeeps the channel current cheaply

Because the feed is tied to a publication, it only ever contains products published to that channel. That is a feature: you can list a subset to Google and a different subset to Meta without maintaining two export pipelines (Shopify: ProductFeed).

Step 1: create the feed

productFeedCreate registers the feed for a country and language and returns its id and status. Run this once per channel/locale.

mutation CreateFeed {
  productFeedCreate(input: { country: US, language: EN }) {
    productFeed {
      id
      country
      language
      status
    }
    userErrors {
      field
      message
    }
  }
}

A freshly created feed comes back with status: INACTIVE and no products in it yet — creating the feed and populating it are two separate steps. Always read userErrors: the most common failure is that your app is not set up as a channel or lacks access to the target publication (Shopify: productFeedCreate). You need the read_product_listings scope to work with feeds, plus read_products.

Step 2: run the full sync

productFullSync tells Shopify to walk every eligible product and emit it into the feed. This is asynchronous — the mutation returns immediately, and Shopify processes the catalog in the background.

mutation FullSync($id: ID!) {
  productFullSync(id: $id) {
    userErrors {
      field
      message
    }
  }
}

Pass the id you got from productFeedCreate. Do not treat the mutation's success as "the feed is ready" — success only means the job was accepted. For a large catalog the actual emit takes minutes, and the only reliable completion signal is a webhook (Step 4).

async function createAndSyncFeed(shop, token) {
  const created = await gql(shop, token, CREATE_FEED);
  const errs = created.data.productFeedCreate.userErrors;
  if (errs.length) throw new Error(JSON.stringify(errs));

  const feed = created.data.productFeedCreate.productFeed;
  await gql(shop, token, FULL_SYNC, { id: feed.id });
  // Do NOT poll here. Wait for product_feeds/full_sync_finish (Step 4).
  return feed.id;
}

Step 3: read feed state

productFeeds (connection) and productFeed(id:) let you inspect what exists. Use them to reconcile on boot — never create a duplicate feed for a channel you already registered.

query ListFeeds {
  productFeeds(first: 10) {
    nodes {
      id
      country
      language
      status
    }
  }
}

A status of ACTIVE means the feed is populated and syncing; INACTIVE means it exists but has not completed a full sync. Reconciling against this on startup is what makes your integration idempotent across restarts and re-installs (Shopify: productFeeds).

Step 4: full sync vs incremental sync

This is the heart of the model. A full sync is the expensive, complete load you trigger explicitly. Incremental syncs are automatic afterward — Shopify emits only what changed.

Full syncIncremental sync
TriggerYou call productFullSyncAutomatic on product change
ScopeEntire eligible catalogOnly added/updated/removed items
Completion signalproduct_feeds/full_sync_finish webhookproduct_feeds/incremental_sync webhook
When you run itFirst load, full rebuildContinuously, forever
CostHigh (whole catalog)Low (deltas only)

Subscribe to both webhooks. product_feeds/full_sync_finish fires once when your Step 2 job completes and is your green light to expose the channel or hand off to a downstream platform. product_feeds/incremental_sync fires on every subsequent create, update, or unpublish, carrying just the changed products so you never re-process the whole catalog.

// Webhook handler (Express-style). Verify the HMAC before this runs.
app.post("/webhooks/product-feeds", (req, res) => {
  const topic = req.get("X-Shopify-Topic");
  const payload = req.body;

  if (topic === "product_feeds/full_sync_finish") {
    markChannelReady(payload.product_feed_id); // hand off to Google/Meta
  } else if (topic === "product_feeds/incremental_sync") {
    pushDelta(payload.product_feed_id, payload.products); // update channel
  }
  res.sendStatus(200);
});

The mistake teams make is calling productFullSync on a timer to "refresh" the feed. You almost never need to — incremental sync already keeps it current. Reserve a full sync for genuine rebuilds: a schema change, a botched initial load, or re-registering a channel (Shopify: webhook topics).

From feed to ad channel: the bridge

Here is why this API matters beyond plumbing. The feed is the exact data your ad platforms bid on. When you attach a ProductFeed to the Google & YouTube publication, its items become the products Google Shopping and Performance Max match against search queries. Attach it to the Facebook & Instagram channel and those items populate the Meta product catalog that Advantage+ builds audiences from. Point an AI shopping integration at the same catalog and those fields are what ChatGPT and Perplexity surface.

That means every gap in the feed is a gap in campaign performance:

  • A truncated title limits which queries Google can match — no keyword bid recovers a word that is not in the feed.
  • A missing GTIN or barcode blocks a product from competitive Shopping auctions entirely.
  • Stale inventory in a slow feed serves ads for items that are sold out, burning spend and hurting account quality.

The ProductFeed API's automatic incremental sync is what keeps inventory and price honest in near real time, which is precisely the reliability that manual feeds cannot match — the case made in Product Feed API vs CSV. Once your feed is syncing, the channel-specific work continues in Google Merchant Center sync, Meta product catalog sync, and AI shopping feeds.

For the AI channels specifically, the feed's structured completeness is even more decisive — LLM shopping surfaces read attributes literally. See preparing your product feed for AI agents and the ChatGPT product feed and shopping ads setup guide for how those fields get consumed.

The completeness ceiling

The through-line: your feed data quality is the ceiling on ad performance and AI shopping visibility, no matter how good the campaigns are. A perfectly tuned Performance Max campaign on a feed of half-empty titles will always lose to an average campaign on a complete one. If your Shopify feeds are underperforming, the fix usually starts in the catalog and the sync pipeline, not the ad account — which is exactly the work AdsX does for Shopify brands.

Next steps

ABOUT THE AUTHOR
AE
AdsX Engineering
SHOPIFY API & COMMERCE ENGINEERING

The AdsX engineering team builds the data pipelines that turn a Shopify product catalog into high-performing ad feeds across Google, Meta, and AI shopping agents. We work hands-on with the Shopify Admin GraphQL API, the Product Feed and Catalog APIs, metafields, and bulk operations every day, and these guides document the patterns we use in production.

MORE BY ADSX ENGINEERING

Ready to Dominate AI Search?

Get your free AI visibility audit and see how your brand appears across ChatGPT, Claude, and more.

Get Your Free Audit