How to Build a Shopify Product Data Feed Step by Step

Your storefront says the medium blue shirt is sold out, your feed still lists it as available, and a shopper clicks through from Google expecting to buy it. That's not a sync delay you can wave away. It's usually a Shopify product data feed built at product level instead of variant level. Fix the row, the sync, and the validation order, and most of these errors stop reaching shoppers.
Fields Every Shopify Product Data Feed Needs
Say a shirt comes in three sizes and two colors. If you export one row, you'll send one id, no size or color in the title, and stock from the parent product. Merchant Center may then flag missing identifiers and, worse, show the wrong variant as available.
The row is the variant, not the product. Six size and color combinations create six rows that share one item_group_id.
| Feed field | Shopify source | Rule to enforce |
|---|---|---|
| id | Variant ID or stable SKU | Unique per item for each country and language; never reused across sources |
| title | Product title plus option values | Include size or color when variants differ |
| description | Product description with HTML removed | Aim for about 500 to 1,000 characters; 5,000 maximum |
| link | Canonical variant URL | Must resolve to the same price and availability shown in the feed |
| image_link | Primary image of the variant | Required on every row; no shared image across variants without reason |
| price | Price in the target market's price list | Currency and amount must match the landing page |
| availability | Variant quantity at the selected location | Use in_stock or out_of_stock based on the variant, not the product |
| brand | Vendor or brand field | Generally required for new products |
| gtin | Barcode field holding the manufacturer GTIN | Required when assigned; never generate a replacement |
| item_group_id | Product ID | Groups all variants of the same product |
| google_product_category | Google category field | Use one format, taxonomy ID or breadcrumb, not both |
Where disapprovals usually start
The Google Merchant Center product data specification requires a unique id for each item and names title, description, link, and image_link as core fields. The same specification says brand is generally required for new products and gtin is required when the manufacturer assigned one.
Don't invent a GTIN to fill a blank cell. If the manufacturer didn't assign one, an empty field is safer than a fabricated identifier that later gets removed and triggers another round of warnings.
For the title, append the option values that distinguish the row, such as “Women's Cotton Shirt, Blue, Medium.” For image_link, use the blue shirt photo on the blue row, not the default white image copied everywhere.
First check: Count feed rows against sellable variants before you style titles or troubleshoot categories. If those counts differ, every later fix is guesswork.
How to Set Up and Export Your Feed in Order
A lean team can finish the first working version in an afternoon if the order is strict. Don't connect the destination until a small sample survives comparison with the storefront.

The build sequence
- Choose the route. Use Shopify's Google and YouTube channel for Merchant Center, a feed app for other destinations, or a custom export when the catalog or transformation logic demands it. The common mistake is buying an app before knowing whether the destination needs variant splitting the native route already handles.
- Audit variants. Confirm every sellable variant will become its own row and that option names stay consistent across products. Mixing “Colour” and “Color” across similar products creates messy titles and category mapping later.
- Normalize categories as separate fields. Shopify's product category guidance says the Product Category column accepts either a Shopify category ID or the complete breadcrumb, not both, and Google Shopping / Google Product Category follows a separate format. Validate each taxonomy against its own list instead of assuming readable text is a valid category.
- Assign inventory by location. Inventory data identifies stock by Handle, Location, and Option1 Value, with Option2 Value and Option3 Value required when those options exist. Skipping location makes a variant stocked in one warehouse look available everywhere.
- Confirm the market price list. Check the price and currency for each target country before export. Exporting the home market price to every destination is fast and almost always wrong.
- Run a three variant test. Export one product with three variants and compare every field with its live storefront pages. Check title, image, URL, price, and quantity at the selected location.
- Connect and record the baseline. Link the destination, set the schedule, and record the first successful timestamp. Without that timestamp, you can't tell whether tonight's stale price came from this build or an older file.
Start with one product family. Most early errors appear in variant rows, and they're far easier to spot in a small sample than across the full catalog.
Building a Sync Pipeline for Large Catalogs
The scale threshold has changed. Shopify's product variant resource documentation describes a model in which updated GraphQL product APIs support up to 2,048 variants per product, up from the historic 100. A feed built around the old ceiling can truncate highly configurable products.
The two stage pipeline
- Submit a bulk query. Select stable product and variant IDs, titles, descriptions, media, inventory, pricing, taxonomy, and publication status.
- Wait for asynchronous completion. Shopify's GraphQL bulk operations documentation says bulk query execution isn't subject to normal per request rate limits, but the operation must complete within 10 days.
- Download the JSONL file. Preserve parent and child relationships while parsing it, because a variant record loses meaning if it's detached from its product and options.
- Validate and transform. Build one destination row per variant and reject rows that fail required field checks before anything publishes.
- Apply incremental updates. Subscribe to product, variant, and inventory webhooks, then use idempotent upserts keyed by variant ID, exponential backoff, dead letter handling, and cursor based pagination for direct calls.
- Reconcile on a schedule. Run a daily delta check and a weekly full reconciliation to catch missed webhook events.
| Store plan | Restore rate |
|---|---|
| Standard Shopify | 100 points per second |
| Advanced Shopify | 200 points per second |
| Shopify Plus | 1,000 points per second |
For ordinary GraphQL sync, budget query cost, not request count. Teams connecting additional tools should also review how those tools consume the same budget, which is why a clear plan for third party app integration for Shopify AI support matters before another app starts polling the catalog.
The pitfall that breaks most builds is flattening products into single records. That mixes price, SKU, availability, and image across size and color combinations. Keep the variant as the unit of every row, upsert, and retry.
Validation Rules and Common Feed Errors
A successful API call only proves delivery. It doesn't prove Merchant Center received a purchasable, current, correctly priced variant. Validation therefore belongs inside the pipeline, before publication.
Normalize each variant into a row, check required fields, then check cross field consistency. The landing page price and currency must agree with the feed, availability must describe the actual variant, and the URL, SKU, and image must point to that same configuration.
Symptoms worth treating as system failures
| Symptom | Likely cause | Fix |
|---|---|---|
| Item disapproved for missing GTIN | Barcode field blank or a placeholder value was exported | Map the manufacturer barcode; leave the field empty if none exists |
| Price mismatch with landing page | Feed price calculated from base price times exchange rate | Pull the price from the target market's price list |
| Only one size shown for a product | Variants collapsed into one row | Output one row per variant with a unique id |
| Listed as available but out of stock | Availability read at product level | Read quantity for the variant at the selected location |
| Duplicate item ID warning | Same ID reused across sources for one country and language | Make IDs unique per source, country and language |
| Category rejected | Category ID, name and breadcrumb mixed in one field | Use one format per field and validate against its own list |
| Old promotional price still shown | Feed refreshed too rarely | Event driven updates for price and stock plus daily reconciliation |
| Variant has no image | Image not linked to the variant | Assign a variant image, with the primary product image as fallback |
Quarantine failed rows instead of publishing them with defaults. Keep the previous valid catalog version available so one bad sync can't replace good data everywhere at once.
Timestamp every source record and reject any update older than the current catalog version. A late retry shouldn't resurrect yesterday's promotional price.
Track five metrics after the fix. Watch validation pass rate, disapproval rate, stale inventory rate, update latency, and variant coverage. If variant coverage drops while the API reports success, your export is shrinking the catalog without telling you.
Keeping Prices, Stock and Markets Accurate
Real time sync isn't automatically safe. It moves good updates quickly, but it can also publish a mistyped regional price everywhere before anyone reviews it. Speed needs freshness targets and approval gates.
Shopify's enterprise guide to Google Shopping states Google requires a feed refresh at least every 30 days, while Shopify describes its Google integration as syncing titles, descriptions, images, prices, availability, and variants in real time. Treat that 30 day limit as a floor for static fields, not a schedule for price or stock.

Market pricing and governance
Don't multiply the base variant price by an exchange rate. Shopify's Markets developer documentation says integrations should load each international market's prices explicitly and treat Shopify as the source of truth, including automatic currency conversion or price lists with percentage adjustments or fixed variant prices. Preserve the market currency and destination settings so feed, landing page, and checkout agree. Those regional rules also matter to support teams, as covered in this guide to international customer service for Shopify stores.
Merchant Center also tightened promotional data. Google's Merchant Center announcements state that from July 2025, member prices are no longer allowed in standard price or sale price attributes and must use the loyalty program attribute where available.
Offer level shipping data needs the same discipline, including carrier and delivery promise fields. I would require human approval for regional pricing, member offers, and shipping promises, with a timestamped log for every approved change.
How Feed Data Powers AI Support Answers
The same rows that make a listing eligible also decide what a support assistant tells a shopper. “Is the medium blue shirt available for delivery here?” can't be answered from a parent product title and a generic in stock flag.

Map each question to its source field. Variant rows grouped by item_group_id answer size and color questions. Availability by location answers stock questions. Market price answers regional price questions. Order records, not catalog records, answer delivery and order status questions.
Teams training assistants on governed source material should keep those boundaries explicit in their knowledge base training setup. When product pages also support discovery, specialist ecommerce SEO services from AY Rank may help ensure the storefront data shoppers find matches the feed data systems reuse.
Our product descriptions and specs sync automatically from Shopify, and IllumiChat answers “Where's my order?” instantly using live Shopify data, without an agent. That separation matters. A static catalog copy would happily repeat yesterday's price long after the storefront changed it.
Conflict rule: The order system wins for order status. The catalog wins for product facts. Both answers should carry the timestamp of the record they used.
Keep the assistant's source fields identical to the synced feed fields. Search, ads, and support then answer from one catalog version instead of maintaining three competing copies.
Confirm Your Feed Before You Go Live
Don't launch on the strength of a successful upload message. Run this go or no go check first.
- Validate 20 variants. Sample 20 variants across at least two products and compare every field with the live storefront.
- Compare two markets. Check prices in two target markets against both the landing page and checkout.
- Test two timestamps. Change one price and one stock quantity, then confirm each record's last updated time moved.
- Watch seven days of metrics. Track validation pass, disapproval, and stale inventory rates for the first seven days.
- Make the decision. If the validation pass rate falls below target or any price mismatch appears, pause the feed, fix the mapping, and rerun the sample. If the sample stays clean for a week, move to scheduled reconciliation with event driven price and stock updates.
For the support side, connecting a store starts by installing IllumiChat from the Shopify App Store and connecting via OAuth, after which your product catalog, order data, and customer profiles sync automatically in about 2 minutes. Do not go live with an unexplained mismatch, even when the disapproval rate looks low.
Your next action is simple. Export the signed off sample to the destination and schedule the first full reconciliation for the following day.
Build your feed at variant level, then let your support assistant answer from that same live Shopify catalog instead of a stale copy. Visit IllumiChat to connect your store and turn accurate product, price, and order data into fast customer answers.
Ready to ship smarter support?
Install IllumiChat from the Shopify App Store and be live in under 5 minutes. Free plan, no credit card.
No credit card · Installs in 5 minutes · Cancel anytime