How to Add Inventory in Google Merchant Center
To add inventory in Google Merchant Center for your WooCommerce store, you manage it directly through your product data sources. For online products, your inventory, availability, and pricing are handled by syncing your WooCommerce catalog as a primary product feed under Product sources.
For in-store or local inventory, you will map your physical stock using a local product inventory feed under Settings → Data sources → Supplemental sources.
You can automate this inventory sync by installing a dedicated plugin like the official Google Listings & Ads extension, generating a product feed file (via XML or CSV) to upload via scheduled fetch, or using the Content API for real-time updates.
Note: A primary product feed must already be active before you can configure local in-store inventory. For standard online-only WooCommerce stores, your primary feed automatically handles all inventory updates.
How to Add Inventory in Google Merchant Center
You have several methods to Add Inventory in Google Merchant Center, depending on your setup and business needs.

Method 1: Primary Product Feed
This is the standard method for online inventory. Your product feed includes availability, price, and all required product attributes. It is submitted through Product sources and forms your main product catalog.
Supported availability values in the primary feed: in_stock, out_of_stock, preorder, backorder.
Method 2: Manual Entry (Product Editor)
For small catalogs or one-off updates:
- Go to Products → All products.
- Click Add products.
- Select “Add new products one by one.”
- Fill in the availability field and other required attributes.
- Save the product.
This method is not practical for large catalogs or frequent updates.
Method 3: Automated Platform Sync
If you use Shopify, BigCommerce, or a similar platform:
- Connect your store in Merchant Center under Settings → Data sources.
- The system automatically fetches product and inventory data.
- Changes made on your store reflect in Merchant Center within approximately 24–48 hours.
Method 4: Local Inventory Feed (Supplemental)
Required if you have physical store locations and want to show in-store availability or run Local Inventory Ads. This is covered step by step in the next section.
How to Add a Local Inventory Feed in Google Merchant Center
A local inventory feed provides per-store stock and availability details, for example: Store A has 10 units, Store B has 3 units. It supplements your primary product feed and is required for any local inventory program.
Prerequisites before you start:
- An active Merchant Center account
- A primary product feed already set up and approved
- Store locations configured in Merchant Center
- Google Business Profile linked (recommended for local programs)
Step 1: Navigate to Data Sources
- Sign in to Google Merchant Center.
- Go to Settings → Data sources.
- Select Product sources → Supplemental sources.
Step 2: Add Local Inventory
- Click Add local inventory.
- Choose how you want to submit the feed:
- Enter a URL (HTTP/HTTPS or SFTP)
- Upload a file directly
- Schedule a fetch from SFTP or Google Cloud Storage
Step 3: Set Language and Feed Label
After selecting your input method:
- Choose the language for the feed.
- Assign a feed label.
The feed label must match the language and label used in your primary product feed. This is how Google links your local inventory data to the correct products.
Step 4: Schedule the Fetch and Save
If you are using a URL, set a fetch schedule. The default is every 24 hours. Save the feed. Google will begin parsing the inventory data; initial processing can take up to 24 hours.
For high-frequency inventory changes, consider updating your feed every 4–12 hours or using the Content API for near-real-time updates. Google’s general recommendation is to refresh local inventory feeds at least once every 24 hours to keep availability data accurate.
Local Inventory Feed: Required Attributes
Every local inventory feed requires three attributes at minimum:
id: The product identifier, which must match the id in your primary product feed exactly.store_code: The unique identifier for each store location, as configured in Merchant Center.availability: The current stock status for that store. Supported values are in_stock, limited_availability, on_display_to_order, and out_of_stock.
The following attributes are commonly used in production feeds:
price: A store-specific price override (overrides the primary feed price for that location).sale_price: The discounted sale price for the product at that store.sale_price_effective_date: The date range during which the sale price applies. Format: 2026-01-01T00:00Z/2026-01-07T23:59Z. This tells Google exactly when to display the sale price, and it must be set alongsidesale_pricefor the discount to show correctly.quantity: The number of units available. If provided, Google may use the lower signal between quantity and availability to classify stock status.pickup_sla: The estimated fulfillment timeframe for store pickup. This attribute is required when store pickup is enabled. Common values are same day and next day. As of September 2024,pickup_methodis optional, andpickup_sladrives pickup eligibility.local_shipping_label: Used for local delivery programs.
Local Inventory Feed: CSV and XML Examples
CSV Schema
The minimum viable local inventory CSV feed requires these columns: id, store_code, availability.
CSV template:
id,store_code,availability,quantity,price,sale_price,sale_price_effective_date,pickup_method,pickup_sla,local_shipping_label
CSV example (one product, two stores):
id,store_code,availability,quantity,price,sale_price,sale_price_effective_date,pickup_method,pickup_sla,local_shipping_label
SKU-10001,STORE-001,in_stock,12,149.00 USD,129.00 USD,2026-01-01T00:00Z/2026-01-07T23:59Z,buy,same day,Sameday
SKU-10001,STORE-002,limited_availability,2,149.00 USD,,,reserve,next day,
XML Schema (RSS 2.0)
Merchant Center also accepts XML feeds using RSS 2.0 structure with the g: namespace.
XML example:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
<channel>
<title>Local Inventory Feed</title>
<link>https://example.com</link>
<description>Store-level inventory updates</description>
<item>
<g:id>SKU-10001</g:id>
<g:store_code>STORE-001</g:store_code>
<g:availability>in_stock</g:availability>
<g:quantity>12</g:quantity>
<g:price>149.00 USD</g:price>
<g:sale_price>129.00 USD</g:sale_price>
<g:sale_price_effective_date>2026-01-01T00:00Z/2026-01-07T23:59Z</g:sale_price_effective_date>
<g:pickup_method>buy</g:pickup_method>
<g:pickup_sla>same day</g:pickup_sla>
<g:local_shipping_label>Sameday</g:local_shipping_label>
</item>
<item>
<g:id>SKU-10001</g:id>
<g:store_code>STORE-002</g:store_code>
<g:availability>limited_availability</g:availability>
<g:quantity>2</g:quantity>
<g:price>149.00 USD</g:price>
<g:pickup_method>reserve</g:pickup_method>
<g:pickup_sla>next day</g:pickup_sla>
</item>
</channel>
</rss>
The required attributes for local inventory remain id, store_code, and availability.
Automating Inventory Updates via the Content API
For large catalogs or high-frequency changes, the Content API for Shopping (v2.1) lets you push local inventory updates programmatically using the localinventory.custombatch endpoint.
What You Can Update via API
Each batch entry requires a storeCode and productId. Optional fields include: quantity, price, salePrice, salePriceEffectiveDate, availability, pickupMethod, pickupSla, and instoreProductLocation.
Note: local_shipping_label is not available as an API field in v2.1. It must be submitted through feed uploads.
Endpoint:
POST https://shoppingcontent.googleapis.com/content/v2.1/localinventory/batch
OAuth scope required:
https://www.googleapis.com/auth/content
Python Script: CSV to custombatch
This script reads a CSV file shaped like the template above, builds batch entries, and sends them to the localinventory.custombatch endpoint. Your account must already be enrolled in a local program and have local products configured before using this.
import csv
import json
import os
import requests
from google.oauth2 import service_account
from google.auth.transport.requests import Request
# ----------------------------
# Config
# ----------------------------
SERVICE_ACCOUNT_JSON = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "service-account.json")
MERCHANT_ID = os.environ.get("GMC_MERCHANT_ID") # e.g., "123456789"
CSV_PATH = os.environ.get("LOCAL_INVENTORY_CSV", "local_inventory.csv")
SCOPE = "https://www.googleapis.com/auth/content"
BATCH_ENDPOINT = "https://shoppingcontent.googleapis.com/content/v2.1/localinventory/batch"
def get_access_token() -> str:
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_JSON,
scopes=[SCOPE],
)
creds.refresh(Request())
return creds.token
def parse_money(value: str):
if not value:
return None
parts = value.strip().split()
if len(parts) != 2:
raise ValueError(f"Invalid money format: {value!r} (expected 'NUMBER CURRENCY')")
amount, currency = parts
return {"value": amount, "currency": currency}
def build_batch_entries(csv_path: str, merchant_id: str):
entries = []
batch_id = 1
with open(csv_path, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
product_id = row["id"].strip()
store_code = row["store_code"].strip()
availability = (row.get("availability") or "").strip()
quantity_raw = (row.get("quantity") or "").strip()
price_raw = (row.get("price") or "").strip()
sale_price_raw = (row.get("sale_price") or "").strip()
sale_price_effective_date = (row.get("sale_price_effective_date") or "").strip()
pickup_method = (row.get("pickup_method") or "").strip()
pickup_sla = (row.get("pickup_sla") or "").strip()
local_inventory = {"storeCode": store_code}
if availability:
local_inventory["availability"] = availability
if quantity_raw:
local_inventory["quantity"] = int(quantity_raw)
if price_raw:
local_inventory["price"] = parse_money(price_raw)
if sale_price_raw:
local_inventory["salePrice"] = parse_money(sale_price_raw)
if sale_price_effective_date:
local_inventory["salePriceEffectiveDate"] = sale_price_effective_date
if pickup_method:
local_inventory["pickupMethod"] = pickup_method
if pickup_sla:
local_inventory["pickupSla"] = pickup_sla
entries.append(
{
"batchId": batch_id,
"merchantId": str(merchant_id),
"method": "insert",
"productId": product_id,
"localInventory": local_inventory,
}
)
batch_id += 1
return entries
def push_custombatch(access_token: str, entries):
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json",
}
payload = {"entries": entries}
resp = requests.post(BATCH_ENDPOINT, headers=headers, data=json.dumps(payload), timeout=60)
resp.raise_for_status()
return resp.json()
def main():
if not MERCHANT_ID:
raise RuntimeError("Set GMC_MERCHANT_ID env var to your Merchant Center merchantId.")
token = get_access_token()
entries = build_batch_entries(CSV_PATH, MERCHANT_ID)
result = push_custombatch(token, entries)
for entry in result.get("entries", []):
if "errors" in entry:
print("ERROR:", json.dumps(entry["errors"], indent=2))
else:
print("OK batchId:", entry.get("batchId"))
print("Done.")
if __name__ == "__main__":
main()
Why "method": "insert" for updates? The localinventory.custombatch endpoint uses "insert" for both new entries and updates. Submitting an entry for an existing product/store combination overwrites the current local inventory data for that location.
For large CSV files, chunk your batch entries before sending. Google’s APIs have practical batch-size limits; sending very large payloads in a single request can cause timeouts or errors.
Frequently Asked Questions
What is the minimum update frequency for a local inventory feed in Google Merchant Center?
Google recommends refreshing your local inventory feed at least once every 24 hours. For retailers with fast-moving stock, updating every 4–12 hours gives better accuracy. If your inventory changes frequently throughout the day, the Content API is the better option since it supports near-real-time updates without waiting for a scheduled feed fetch.
What does pickup_sla mean in a Google Merchant Center local inventory feed?
pickup_sla defines the estimated fulfillment timeframe for store pickup. It tells shoppers how quickly they can collect their order. Common values are same day and next day. This attribute became required for store pickup programs after September 1, 2024, when pickup_method became optional. Without a valid pickup_sla, store pickup options may not display correctly in Google surfaces.
How does sale_price_effective_date work in Google Merchant Center?
sale_price_effective_date sets the date range during which a sale price is active. It must be formatted as YYYY-MM-DDTHH:MMZ/YYYY-MM-DDTHH:MMZ (start/end in ISO 8601). If this attribute is missing, Google may not display the sale price even if sale_price is present. Always include both attributes together when running time-limited promotions.
What is the difference between a primary product feed and a local inventory feed?
The primary product feed contains your full product catalog, including titles, descriptions, images, prices, and base availability. It is required for all Merchant Center programs. The local inventory feed is a supplemental feed that overrides or extends the primary feed with store-specific data, such as per-store stock levels, local pricing, and pickup options. You need both active feeds for Local Inventory Ads to work.
Can I use the Content API to update online inventory?
Yes. Online inventory attributes such as availability and price can be updated through the products.update method in the Content API. The localinventory service specifically handles store-level updates for local inventory programs. For online-only merchants, updating the primary product feed, either via file upload or through the products API, is the standard approach.
Key Takeaways
- Inventory in Google Merchant Center is managed through the primary product feed for online products, a local inventory feed for in-store availability, and the Content API for programmatic updates at scale.
- A local inventory feed requires three attributes at minimum:
id,store_code, andavailabilitywith valid values (in_stock,limited_availability,on_display_to_order,out_of_stock). pickup_slais required for store pickup programs and must match the fulfillment timeframe (such assame dayornext day). As of September 2024,pickup_methodis optional.- Always include
sale_price_effective_datealongsidesale_price. Without the date range, Google may not display the promotional price. - The local inventory feed label must match the language and label in your primary product feed, or Google will not link the two feeds correctly.
- For high-frequency inventory changes, the Content API’s
localinventory.custombatchendpoint gives you near-real-time control without waiting for a scheduled feed refresh. - Google treats inventory accuracy as a policy requirement. Incorrect availability data affects product eligibility, ad delivery, and overall Merchant Center account health.
