Product Feed Scraper: Google Merchant & XML Catalogs avatar

Product Feed Scraper: Google Merchant & XML Catalogs

Pricing

from $2.00 / 1,000 product scrapeds

Go to Apify Store
Product Feed Scraper: Google Merchant & XML Catalogs

Product Feed Scraper: Google Merchant & XML Catalogs

Parse public Google Merchant and RSS 2.0 product feeds: GTIN, MPN, brand, price split into amount and currency, sale price, availability, shipping and images. The catalogue retailers publish deliberately.

Pricing

from $2.00 / 1,000 product scrapeds

Rating

0.0

(0)

Developer

Arman Hossain

Arman Hossain

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

a day ago

Last modified

Share

Product Feed Scraper: Every product in a merchant's Google Shopping feed, price split into amount and currency, availability, brand, GTIN and shipping

Product Feed Scraper reads the product feeds retailers publish for Google Shopping and other ad platforms, and returns one clean record per product, ID, title, description, link, images, price split into an amount and a currency, sale price, availability, brand, GTIN, MPN, condition, category and shipping.

These feeds exist so machines can read them: a merchant generates one deliberately and hands the URL to Google Merchant Center. This Actor reads the same URL. No proxy setup, no browser, no credentials to manage. A 250-product catalogue comes back in under a second.

Agent skill: SKILL.md

https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/product-feed-scraper.md

What you get

Output fieldMeaning
feedUrl, feedTitleFeed that was read after redirects, and the store name from the channel
productId, itemGroupIdg:id, and the g:item_group_id that ties variants of one product together
title, descriptiong:title and g:description, description stripped to plain text
link, imageLink, additionalImageLinksProduct page and images
price, salePrice, currencyNumbers, not strings, "69.99 USD" becomes 69.99 plus "USD"
availability, inStockGoogle's enum (in_stock, out_of_stock, preorder, backorder) and a boolean
brand, gtin, mpn, conditionIdentity attributes, with g:ean / g:upc / g:isbn accepted as GTIN aliases
productType, googleProductCategoryThe merchant's own taxonomy and Google's
shippingCost, shippingCurrency, shippingCountryParsed out of the nested g:shipping group
scrapedAtRun timestamp

A RUN_SUMMARY record in the key-value store holds per-run counts, a per-feed breakdown of listed / saved / filtered, the filters used, and any feed that failed.

Common use cases

  • Competitive price monitoring. Run daily and diff on productId plus price.
  • Supplier catalogue ingest. Pull a distributor's whole feed straight into your own catalogue.
  • Comparison shopping. Normalise many merchants' feeds into one schema keyed by GTIN.
  • Stock and assortment tracking. Watch availability flip across a competitor's range.
  • Market research. Price distributions by brand, category or condition across a sector.

Quick start

A whole catalogue:

{
"feedUrls": ["https://houseofjerky.com/wp-content/uploads/woo-feed/google/xml/googlehojfeed.xml"]
}

Several suppliers, capped while you explore:

{
"feedUrls": [
"https://example-shop.com/feeds/google-shopping.xml",
"https://another-shop.com/googlebase.xml"
],
"maxProductsPerFeed": 500
}

Only what is buyable, from one brand, in a price band:

{
"feedUrls": ["https://example-shop.com/feeds/google-shopping.xml"],
"inStockOnly": true,
"brandFilter": ["Sony"],
"minPrice": 100,
"maxPrice": 900
}

Input

FieldTypeDefaultNotes
feedUrlsarray-Required. Public product feed URLs. .xml and gzipped .xml.gz both work.
maxProductsPerFeedinteger0Cap saved products per feed, applied after filtering. 0 = no limit.
inStockOnlybooleanfalseKeep only availability: in_stock. Products with no availability are dropped.
brandFilterarray[]Exact, case-insensitive match on g:brand. Empty = all brands.
minPriceinteger-Lower price bound in the feed's own currency. No conversion is done.
maxPriceinteger-Upper price bound in the feed's own currency.

Filters combine with AND. Setting either price bound drops products whose price could not be parsed, since there is no way to know whether they qualify.

Output example

{
"feedUrl": "https://houseofjerky.com/wp-content/uploads/woo-feed/google/xml/googlehojfeed.xml",
"feedTitle": "House of Jerky",
"productId": "97864",
"itemGroupId": "97864",
"title": "Teriyaki Lovers",
"description": null,
"link": "https://houseofjerky.com/shop-for-jerky/teriyaki-lovers/",
"imageLink": "https://houseofjerky.com/wp-content/uploads/2025/10/Teriyaki-Lovers-scaled.jpg",
"additionalImageLinks": [],
"price": 69.99,
"salePrice": 69.99,
"currency": "USD",
"availability": "in_stock",
"inStock": true,
"brand": "House of Jerky",
"gtin": null,
"mpn": "teriyakilovers",
"condition": "new",
"productType": "Beef > Exotic > Game > Turkey > Subscriptions",
"googleProductCategory": "423",
"shippingCost": null,
"shippingCurrency": null,
"shippingCountry": null,
"scrapedAt": "2026-08-06T11:56:59.217Z"
}

Finding a merchant's feed URL

There is no universal path, but the cart platform narrows it down:

PlatformTypical feed path
WooCommerce (CTX Feed / Product Feed PRO)/wp-content/uploads/woo-feed/google/xml/<name>.xml
Magento and custom carts/googlebase.xml, /google_shopping.xml, /feeds/google-shopping.xml
Feed services (DataFeedWatch, Channable, Feedonomics)A hosted URL on the vendor's domain

Merchants who want you to have the feed, suppliers, dropship partners, affiliate programmes, will simply send you the URL. Do not try to guess your way into one that is not published: a feed behind auth returns 403 and is recorded as a failure.

API example

curl -X POST "https://api.apify.com/v2/acts/arman-bd~product-feed-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"feedUrls": ["https://example-shop.com/feeds/google-shopping.xml"],
"inStockOnly": true,
"maxProductsPerFeed": 1000
}'

JavaScript example

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/product-feed-scraper').call({
feedUrls: ['https://example-shop.com/feeds/google-shopping.xml'],
inStockOnly: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const p of items) console.log(`${p.productId}\t${p.price} ${p.currency}\t${p.title}`);

Limits and behaviour

  • RSS 2.0 only. Google Merchant feeds are RSS 2.0 with the g: namespace, and that is what this Actor parses, along with plain RSS <title>, <link> and <description> as a fallback. Atom-based product feeds are out of scope and rejected with a clear message rather than parsed into empty records; Shopify's /collections/all.atom is the common example. CSV and TSV feeds are also out of scope. This is an XML parser.
  • The g: prefix is matched literally. Every generator in the wild emits the conventional g: prefix declared as xmlns:g="http://base.google.com/ns/1.0". A feed that rebinds the namespace to a different prefix will parse as plain RSS and lose the merchant fields; the run log warns when a feed yields no g: fields at all.
  • Compression is handled both ways. Content-Encoding: gzip is unwrapped by the HTTP layer, and a .xml.gz body is detected by its magic number and decompressed in-process. No extra dependency.
  • Non-UTF-8 feeds are decoded. The XML declaration's encoding attribute is honoured, so windows-1252 and ISO-8859-1 catalogues come through with their accents intact.
  • Prices become numbers. "69.99 USD", "USD 69.99", "1.299,00 EUR" and "£1,050" all parse correctly. A bare $ is left as currency: null because a dozen currencies share the symbol, the Actor does not guess.
  • Availability is normalised. Feeds write in stock and in_stock interchangeably; both come out as in_stock.
  • Big catalogues need memory. The feed is parsed in memory, so the default is 2 GB and 30 minutes. A feed over roughly 200 MB may need more.
  • One failure never kills the run. A 404, a private feed or an Atom feed is logged into RUN_SUMMARY.failures and the next feed is read. The Actor only errors out if every feed fails.
  • Public data only. No authentication, no access-control bypass, no personal data.

FAQ

Do I need a Google Merchant Center account? No. You supply no credentials.

Will it work on any store? Only on stores that publish a public feed. Most do, because that is how they get into Google Shopping, but the URL is not always advertised.

Does it convert currencies? No. price is the number the feed states and currency is its ISO code. A feed is single-currency; converting is your job.

Why is gtin null on so many products? Because small merchants leave it blank. g:ean, g:upc and g:isbn are read as aliases, but if none are present the field is null rather than fabricated.

Why did a product get filtered out when I set a price range? Either its price is outside the range, or the feed gave no readable price. RUN_SUMMARY.perFeed reports listed vs saved vs filtered per feed, which distinguishes the two.

Can I get only changed prices? Run on a schedule and diff on productId plus price. Combining maxProductsPerFeed: 0 with a scheduled run gives you a full daily snapshot.

Can I integrate it with something else? Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.