Google Shopping and AI agents
Your catalog for shopping engines, AI agents and the Meta, Pinterest and TikTok catalogues: every feed, the field mapping, feed health and rich previews.
Written 2026-09-16. Every Formahand store publishes its own catalog for shopping engines, for the Meta, Pinterest and TikTok catalogues, and for AI shopping agents, with nothing to install and no app to connect. Seven feed files, two agent files, all served by the store itself and always current.
1. What your store publishes
Replace <your store> with your storefront address (myshop.store-on-formahand.app, or your own domain once it is primary):
| Address | What it is |
|---|---|
https://<your store>/feeds/google.xml | The shopping feed: RSS 2.0 with the g: namespace, the format Merchant Center fetches |
https://<your store>/feeds/products.csv | The same rows as a spreadsheet, under Google's own column names |
https://<your store>/feeds/products.json | The same rows as JSON, for anything you or your agent build |
https://<your store>/feeds/meta.csv | The same rows for a Meta catalogue (Facebook and Instagram); see section 6 |
https://<your store>/feeds/meta.xml | The Meta rows as RSS, for a catalogue that prefers XML |
https://<your store>/feeds/pinterest.xml | The same rows for a Pinterest catalogue |
https://<your store>/feeds/tiktok.csv | The same rows for a TikTok catalogue |
https://<your store>/llms.txt | Your store written for an AI agent: what you sell, your currency, where you ship, your pages, and how to buy |
https://<your store>/.well-known/formahand-store.json | The same facts as JSON, plus a pointer to the agent tool endpoint and these docs |
All nine are public, need no key, and are cached for ten minutes. The feeds carry X-Robots-Tag: noindex — they are data for a shopping engine, not pages to index — and they are deliberately left out of your sitemap.
Every storefront page also carries one tag in its <head>: a <link rel="alternate" type="application/rss+xml"> pointing at the shopping feed, so a crawler that lands on any page can find the rest. Your store id is published in the two agent documents above, not in a meta tag on every page a shopper loads.
2. One row per buyable item
A plain product is one row. A product with options is one row per variant, and the rows share an item_group_id so a shopping engine groups them as one product with sizes or colours. A product with options but no variant cannot be bought, so it has no row. Archived and unpublished products are never in the feed.
| Feed field | Comes from |
|---|---|
id | The product id, or the variant id on a variant row |
item_group_id | The parent product id; absent on a plain product |
title | The product name, plus the variant title on a variant row (150 characters) |
description | The product description as plain text (5,000 characters, markup stripped) |
link | https://<your store>/products/<slug>, with ?variant=<variant id> on a variant row |
image_link | The variant's photo when it has one, else the product's first photo |
additional_image_link | The rest of the gallery, up to ten |
availability | in stock when stock is above zero, backorder when the product allows backorders, out of stock otherwise |
price | The price, with the currency (19.99 USD). When there is a compare-at price, price is the compare-at and sale_price is what the shopper pays |
sale_price | Only on an item with a compare-at price |
brand | The product's vendor, or your store name when it has none |
condition | new |
gtin | The barcode, when it is a real GTIN-8/12/13/14. An internal code of your own is left out rather than rejected |
mpn | Your SKU, from the variant when it has one, else the product |
identifier_exists | no when the item has neither a GTIN nor a SKU |
shipping_weight | The variant's weight, else the product's, in grams. Empty for a digital or service product |
product_type | The product type you typed, else your tags, up to three, joined with > |
google_product_category | Google taxonomy ID 4218 (False Nails) for explicit product types Press-on nails, Press on nails, False nails, Fake nails, Artificial nails, or the full Google False Nails category path. Matching ignores case and extra spaces. Other types stay empty; titles and tags are never used to guess a category. Applies to plain products and all their variants across the shopping and channel feeds. |
Money is exact: the amount is built from the stored minor units, never from a floating-point multiply, and zero-decimal currencies are written without decimals.
Your product pages carry the same facts as Product structured data — brand, GTIN, SKU, price and availability, including BackOrder — read from the same rows, so the page, the feed and the structured data can never disagree.
3. Adding the feed in Merchant Center
Dashboard → Analytics → Product feeds → Google has the feed address with a copy button and a Check feed button. Then:
- Open Merchant Center and pick your store (create an account if this is your first time).
- Go to Products → Add products and choose to add them from a file, for the country and language you sell in (menu names to verify: Merchant Center renames them often).
- Choose Scheduled fetch as the upload method, not a file upload, so the feed stays current by itself.
- Paste
https://<your store>/feeds/google.xmlas the file URL and let it fetch daily. - Verify and claim your website when asked; your storefront already serves the files that check looks for.
Check feed fetches your live feed the way a shopping engine will and reports how many items it carries, how many are in stock, and the first five problems a shopping engine would reject: no id, no title, no description, no link, no photo, no price. Most rejections are a missing photo or a missing description.
4. For AI shopping agents
https://<your store>/llms.txt follows the llms.txt convention. It names the store, the number of buyable items, the currency, the countries you ship to, every catalog API address, the feed addresses, your published pages, and how a purchase actually happens: send the shopper to the product page, or check out from your own pages with the headless checkout call and your store id. It ends with a pointer to the machine-readable version and to the agent tool endpoint.
An agent that reads it needs nothing else to browse your catalog and quote your prices correctly — the file says in as many words that prices come from the catalog and nowhere else.
Your own agent can work with the feeds through two tools on the agent endpoint: get_feeds returns every address above, the channel feeds included (channelFeeds), and a summary, and check_feed runs the same validation as the dashboard button; check_feed { channel } checks for one channel (see Feed health in section 6). Both need a token with settings:read; GET /api/feeds/check is the same check over HTTP, with ?channel= for one channel.
5. Hidden stores
A store with Hide store from search switched on (Online Store → Search & sharing) serves 404 on all nine addresses. A store that asked not to be indexed is not handed to a shopping engine either, and the head tags are left off its pages. Turn the setting off and the feeds come back at once.
With Let AI assistants read my store switched off (same page), /llms.txt answers 404 and the JSON file no longer points to it; the feeds are unchanged.
The sandbox publishes its own feeds at the sandbox address, and every sandbox page is noindex anyway, so a test catalog never reaches a shopping engine.
While your store is closed behind its password page, every feed and both agent files stay readable, so a shopping engine can fetch them before you open.
6. Channel feeds
The same rows, written the way Meta, Pinterest and TikTok catalogues read them. Paste the address into the channel's catalogue as a scheduled feed.
| Channel | Address | Format |
|---|---|---|
| Meta (Facebook and Instagram) | https://<your store>/feeds/meta.csv | CSV |
| Meta, as XML | https://<your store>/feeds/meta.xml | RSS 2.0 with g: tags, the same rows as the CSV |
https://<your store>/feeds/pinterest.xml | RSS 2.0 with g: tags | |
| TikTok | https://<your store>/feeds/tiktok.csv | CSV |
A channel feed follows the rules of sections 1, 2 and 5: the same rows, the same cache, X-Robots-Tag: noindex, and 404 on a hidden store. A row is never left out here: what a channel would reject is reported by the feed check. Text is cut to the channel's limits without splitting a character.
In the dashboard, Analytics → Product feeds shows a tile per channel: Google, Meta, Pinterest and TikTok. A channel's page (#product-feeds/<channel>) has its Feed address with a Copy button, How to add it in three steps, and Feed health with a Check feed button. All four pages share one layout.
Details marked "to verify" come from each channel's public feed specification as we know it. Check them against the channel's own help pages before relying on them.
Tracking
Every link in a channel feed carries utm_source=<channel>&utm_medium=feed, where the channel is meta, pinterest or tiktok. A variant link keeps its ?variant= and gains the two parameters after it. A parameter the link already has is never added twice. The shopping feed at /feeds/google.xml is unchanged and carries no tracking parameters.
Variants
As in section 2, a product with options is one row per active variant. Each row has the variant id as its id (sku_id on TikTok), the product id as item_group_id, the variant title in its title ("Tee - Red / M"), and the variant's own price, sale price, stock and photo (the product's photo when the variant has none). A plain product has an empty item_group_id and no ?variant= in its link.
The link is https://<your store>/products/<slug>?variant=<variant id> plus the tracking. The product page opens with that variant chosen.
When a product has an option named Colour (or Color) or Size, its value (up to 100 characters) goes in the channel's color or size field. Other option names are not sent. The two CSV columns appear at the end only when some row has a value, so a catalogue without them keeps exactly its columns. /feeds/products.json carries every option of a variant row as options: [{ "name": "Size", "value": "M" }]; the shopping feed and its CSV do not change.
Availability
| Our stock state | Meta | TikTok | |
|---|---|---|---|
| In stock | in stock | in stock | in stock |
| Out of stock | out of stock | out of stock | out of stock |
| Backorder allowed | available for order (to verify) | preorder (to verify) | available for order (to verify) |
Meta
| Column | Required | Limit or rule |
|---|---|---|
id | yes | 100 characters |
title | yes | 150 characters (newer docs say 200, to verify) |
description | yes | 9,999 characters, plain text |
availability | yes | in stock or out of stock; see the table above |
condition | yes | new |
price | yes | Amount, a space, the ISO currency: 12.00 USD, 1200 JPY, 1.250 KWD |
link | yes | The product page, with tracking |
image_link | yes | At least 500 x 500 px (we cannot measure this in the feed) |
brand | yes | 100 characters |
sale_price | no | Same format as price |
additional_image_link | no | Up to 20, comma separated in the CSV, one tag each in the XML |
item_group_id | no | The product id on a variant row |
gtin, mpn, product_type, google_product_category | no | As in the shopping feed |
color, size | no | From a Colour or Size option, 100 characters (to verify); only when some row has one |
The CSV columns, and the XML tags, come in the order above.
Pinterest reads the same RSS shopping format as /feeds/google.xml, with g: prefixed tags, in this order: id, title, description, link, image_link, additional_image_link, availability, price, sale_price, condition, brand, gtin, mpn, product_type, google_product_category, item_group_id, color, size. How it differs from the shopping feed:
| Field | Shopping feed | |
|---|---|---|
availability | in stock, out of stock, preorder; no backorder, so a backorder is written preorder (to verify) | also backorder |
title | Up to 500 characters, but Pinterest shows far fewer | 150 |
description | Up to 10,000 characters | 5,000 |
additional_image_link | Up to 10 (to verify), one tag each | Up to 10 |
price | Must carry the ISO currency code | Same |
identifier_exists | Not used, left out | Written as no when there is no GTIN or SKU |
shipping_weight | Left out | Written for a physical product |
link | Must be on the website you claimed in your Pinterest business account; carries tracking | No tracking |
id | Up to 127 characters (to verify) | No cap |
color, size | From a Colour or Size option | Not written |
Images: at least 500 x 500 px (to verify); Pinterest recommends tall images.
TikTok
| Column | Required | Limit or rule |
|---|---|---|
sku_id | yes | The product id, or the variant id on a variant row |
title | yes | 255 characters (to verify) |
description | yes | 10,000 characters (to verify), plain text |
availability | yes | in stock, available for order, preorder, out of stock (to verify) |
condition | yes | new |
price | yes | Amount, a space, the ISO currency |
link | yes | The product page, with tracking |
image_link | yes | At least 500 x 500 px |
brand | yes | The vendor, or your store name |
sale_price | no | Same format as price |
item_group_id | no | The product id on a variant row |
additional_image_link | no | Up to 10, comma separated (to verify) |
gtin, mpn, product_type, google_product_category | no | As in the shopping feed |
color, size | no | From a Colour or Size option (to verify); only when some row has one |
The CSV columns come in the order above.
Feed health
The feed check for one channel (Check feed on the channel's page, GET /api/feeds/check?channel=google|meta|pinterest|tiktok, or the check_feed tool with channel) reads /feeds/products.json once and lists, per row, what that channel would reject or warn about. Each issue carries a one-sentence fix and a link to the product in the dashboard. A reject means the channel drops the item; a warning means it shows the item, but worse.
| Check | Meta | TikTok | ||
|---|---|---|---|---|
| No id | reject | reject | reject | reject |
| No title | reject | reject | reject | reject |
| Title longer than the channel shows (150, 150, 500, 255) | warn | warn | warn | warn |
| Empty description | reject | reject | reject | reject |
| No product link | reject | reject | reject | reject |
Variant row whose link does not pick the variant (?variant=) | reject | reject | reject | reject |
| No price, or a zero price | reject | reject (zero: to verify) | reject (zero: to verify) | reject (zero: to verify) |
| No photo | reject | reject | reject | reject |
| Photo smaller than the channel wants (100, 500, 500, 500 px; to verify) | warn | warn | warn | warn |
| No brand, no barcode and no SKU | warn | warn | warn | warn |
The check is ok only when the feed has rows and no row is rejected. rejected and warned count rows; the first 50 issues are listed and issueCount has the total.
Photo sizes: the store does not record them, so the check reads the size of the main photos of the first 20 rows with a distinct photo, only photos on your store's own address, reading just the first 64 KiB of each. A photo it cannot read that way is skipped, and other photos are not checked. imagesMeasured says how many were read.
Known limits:
- The feed already cuts titles to 150 and descriptions to 5,000 characters, so a title warning shows up only where a channel's limit is lower than that, and no channel feed carries a longer description.
- The feed carries at most ten extra photos per row, though Meta accepts 20.
- The feed uses your store name as the brand when a product has no vendor, so the brand warning is rare.
7. Rich previews
When someone shares or pins a product page, Meta and Pinterest read the page itself: its Open Graph tags and its product structured data (JSON-LD). Pinterest calls a pin that shows the live price and stock a rich pin.
The product page's Open Graph product tags:
| Tag | Value |
|---|---|
product:price:amount, product:price:currency | The list price, as in the feeds: the compare-at price when the product is on sale, else the price. "12.00", "1200" for JPY, "1.250" for KWD |
product:sale_price:amount, product:sale_price:currency | Only on sale: the price the shopper pays |
product:availability | in stock, out of stock or available for order (a backorder; to verify) |
product:condition | new |
product:brand | The vendor, else the store name; no tag when both are empty |
product:retailer_item_id | The product id, the feed row id of a plain product |
product:item_group_id | Only for a product with variants: the product id, the feeds' item_group_id (to verify that Meta matches on it) |
og:price:amount, og:price:currency | For Pinterest: the price the shopper pays now (to verify) |
og:price:standard_amount | For Pinterest, only on sale: the list price (to verify) |
og:availability | For Pinterest: instock, out of stock or backorder (to verify) |
A product with variants shows its lowest variant price and is in stock when any variant is, the same as its structured data. A gift card is always in stock.
Rich pin readiness
What Pinterest reads (to verify against Pinterest's current rich pin help) and whether the product page has it:
| Field | On the page | Where |
|---|---|---|
Product name | yes | JSON-LD Product |
Product description | yes | JSON-LD Product |
Product image | yes | JSON-LD Product, every product photo |
Product url | yes | JSON-LD Product, the page's own address |
Product brand | yes | JSON-LD Product: the vendor, else the store name |
Product sku | yes, when the product has one | JSON-LD Product |
Product gtin | yes, when the barcode is a real one | JSON-LD Product |
Offer price, priceCurrency | yes | JSON-LD Offer (AggregateOffer with low and high price for variants) |
Offer availability | yes | JSON-LD Offer |
Offer url | yes | JSON-LD Offer |
aggregateRating | no | Reviews are not read while the page is built |
og:type product | yes | Open Graph |
og:title, og:description, og:site_name | yes | Open Graph |
og:url | yes, when the page has a canonical address | Open Graph |
og:image | yes | The first product photo, or the page's own share image |
og:image:width, og:image:height | no | Photo sizes are not recorded |
| Price amount and currency | yes | Open Graph product tags above |
| Availability | yes | Open Graph product tags above |
The structured data and the Open Graph tags both carry what a product rich pin needs.
Share image
The share image is the product's first photo. The page would prefer the first photo at least 1200 px wide, but the store does not record photo sizes, so it keeps the first photo. Upload your best wide photo first.
See also
- Build your own site or plugin — the same catalog as a JSON API for a front end you own
- Agents and API — tokens, the agent endpoint and every tool
- Content and SEO — titles, descriptions, redirects and your blog's own feed
Connect an existing Google Merchant Center account
In Analytics → Product feeds → Google, connect your Google account with Merchant Center permission, then choose Find my Merchant Center accounts. Select the existing account for this store and confirm the connection. Formahand checks that its HTTPS homepage matches the store’s current primary domain. It does not change or take over website claims. Only signed-in store owners/admins can link accounts or register a feed; Test mode cannot submit products.
Choose a sales country you can fulfill orders to, the actual two-letter language of the product content and the feed label. Review feed setup checks the current public Google feed and existing primary sources without submitting products. Confirm the displayed account, market and fulfillment readiness to register a daily scheduled fetch of /feeds/google.xml. A matching existing source is reused with its existing schedule. Overlapping primary/API/automatic sources and duplicate exact sources block creation for reconciliation; there is no automatic replacement or product deletion. Uncertain create responses remain held across restarts until a matching source can be confirmed.
Refresh Google diagnostics reads the account’s homepage claim, product sources, account-level issues and latest registered feed processing. Failed/unavailable checks remain distinct from success. Processing success is not proof of individual product approval; per-product eligibility, shipping, returns, business information and free-listing setup remain in Merchant Center. The manual feed instructions remain available when a direct connection cannot be completed. Keep a single primary source for the same product identity and market.
Disconnect this store’s link removes Formahand’s local connection only. It does not delete the merchant’s account, products or scheduled Google feed, and does not disconnect the shared Google login. Pause ingestion in Merchant Center when needed. Removing the authorizing person’s store role, switching their Google identity, revoking Google access or changing the primary domain stops delegated operations until reauthorization/reconciliation.
The connection is stored as merchant_owned with the existing Merchant Center ID and source name. Later approved platform account-management relationships can attach to that same account; MCA approval does not automatically migrate merchants. This release does not create MCA subaccounts, establish provider relationships or switch hosted feeds to API product uploads. Those changes need a separately reviewed flow that preserves account/product identity and avoids competing writers.
Agents can call get_google_shopping { refresh: false } for the selected store’s saved link or { refresh: true } for Google diagnostics, with settings:read and current owner/admin membership for the token creator. There are no agent tools for granting account access or enabling ingestion; those actions stay with the signed-in owner/admin.
Platform prerequisites: configure Google authorization, enable Merchant API in its Google Cloud project, complete the one-time Merchant API developer registration and configure Google OAuth consent for the https://www.googleapis.com/auth/content permission. Developer registration is distinct from advanced-account/MCA approval. It applies to the Cloud project once, not to each connected merchant. Google can require OAuth application verification or testing-user restrictions before general merchant access is available.
Official references: account discovery, data sources, file processing, developer registration, future account-management relationships.