The production-ready Medusa DTC Starter is outRead the announcement
G

Google merchant center plugin

Google Merchant Center XML product feed for Medusa v2

npm install @weareseeed/medusa-google-merchant-center-plugin
Category
Built by
Version
0.0.2
Last updated
1 month ago
Monthly downloads
Loading downloads

Medusa Google Merchant Center Feed

Google Merchant Center XML product feed for Medusa v2. Serves a token-protected feed URL with your catalog: region prices, sales channel stock, admin settings, and a hook to customize every item.

Compatibility

Medusa >= 2.11.0.

Setup

  1. Register the plugin in :

  2. Run the migrations (they ship with the plugin):

    npx medusa db:migrate
  3. In the admin, open Google Merchant and set:

    • Frontend URL: your storefront, e.g. . Product links are . If your storefront prefixes a country code (like the Medusa Next.js starter), include it: .
    • Public backend URL: where this Medusa backend is reachable from the internet, e.g. . Google fetches the feed from there, so don't use or an internal address. Use current fills in the address the admin is using.
    • Pricing region: prices are Medusa's calculated price for this region, in its currency.
    • Sales channel (optional): only its products are included, and stock counts only its stock locations. "All sales channels" includes every published product and counts all locations.
    • Feed token: type one or click Generate (UUID). It is required in the URL.

    Save. The page shows the feed URL, built from the public backend URL: . The endpoint is public; the token is what protects it.

  4. In Merchant Center: Products → Data sources → Add product source → Add products from a file. Enter the feed URL and choose a daily schedule. Then use Fetch now to test.

What goes in the feed

One per variant of every published product (in the selected sales channel, if any):

AttributeValue
Variant SKU, or the variant id when it has no SKU
Product id, when the product has more than one variant
Product title plus the variant title, which holds its option values, e.g.. A variant title that already contains the product name is used as-is. Single-variant products use the product title. Cut to 150 characters at a word boundary
Product description (falls back to the product title), cut to 5000 characters at a word boundary
Variant thumbnail, else the product thumbnail, else the first product image (by gallery order)
Up to 10 other product images, in gallery order
Calculated price in the pricing region, e.g. (price lists included)
if inventory isn't managed or stock > 0; otherwise if allowed, else
/ / From variant options with those names ( wins)

A variant is left out when it has no image or no price in the region, or when its final item (after ) has an longer than 50 characters or a price of zero or less. Google rejects those items. With , the reason is logged. Other limits are left for Merchant Center to report. The feed ends with a comment .

Tax: the price is sent exactly as Medusa calculates it. Whether it includes tax follows the region's price settings. Google expects tax-exclusive prices for the US and Canada (configure tax in Merchant Center) and tax-inclusive prices for VAT countries (EU, UK, AU…).

Customizing items

runs for every item. It receives a copy of the default item and returns the item to include, modified or not. Returning , or leaves it out. Items use Google's attribute names: arrays become repeated elements, objects become nested elements (e.g. ), and / are written as /.

contains (with , , , , , ), (with , , , , , , , ), (without the feed token), , , and . The hook may be .

The returned item is final; text you return is not truncated. It is only left out (and logged) if it lacks , , , or , if its is longer than 50 characters, if its price is zero or less, or if the hook throws.

Extra product fields

and only contain the fields the feed needs. To read more in , list them in . They are added to the default fields (the defaults can't be removed) and fetched in the same batched query, so there's no per-item lookup. Use Query field syntax; fields from linked modules (e.g. ) need the link to exist in your app.

Extra fields are typed as , so cast them when you read them. A field that doesn't exist makes the query fail, which leaves the feed incomplete (see below) and logs the error. With the added fields are logged on every feed request.

Endpoint behaviour

is public (outside and , so Google can fetch it without headers):

  • 401 if the token is missing or wrong.
  • 503 if the feed isn't configured (no frontend URL or region, or the selected region/channel was deleted), with the reason in the body.
  • 200 otherwise: the feed is generated live from the database and streamed.

If an error happens while streaming, the document is left incomplete on purpose. Merchant Center then reports a fetch error and keeps your products, instead of deleting everything missing from a truncated file.

The token is part of the URL, so it can appear in proxy and access logs. If the backend sits behind nginx, disable response buffering for . The endpoint sends .