skills/marketing-growth/google-shopping-feed/SKILL.md
Generate and optimize a product feed for Google Merchant Center so your products appear in Google Shopping ads with correct attributes
npx skillsauth add finsilabs/awesome-ecommerce-skills google-shopping-feedInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Google Merchant Center requires a product data feed with specific attributes to serve Shopping ads. Shopify, WooCommerce, and BigCommerce all have official Google integrations that handle feed generation automatically. This skill covers setting up the integration, optimizing feed quality (the primary Shopping ranking factor), and fixing common disapproval issues.
Improving feed quality on Shopify:
For more control: install WooCommerce Product Feed Pro ($70/yr) — it gives you full control over feed attributes, custom labels, and supplemental feeds for promotions.
Add Google product category to WooCommerce products:
yourstore.com/xmlfeed.xmlFor enhanced feed optimization: install GoDataFeed or Feedonomics from the BigCommerce App Marketplace.
Generate a standards-compliant XML feed endpoint that Google can crawl:
import { create } from 'xmlbuilder2';
export async function generateGoogleShoppingFeed(req: Request, res: Response) {
const products = await db.products.findAll({
where: { status: 'active' },
include: ['variants', 'images'],
});
const root = create({ version: '1.0', encoding: 'UTF-8' })
.ele('rss', { version: '2.0', 'xmlns:g': 'http://base.google.com/ns/1.0' })
.ele('channel')
.ele('title').txt(process.env.STORE_NAME!).up()
.ele('link').txt(process.env.STORE_URL!).up();
for (const product of products) {
for (const variant of product.variants) {
const item = root.ele('item');
item.ele('g:id').txt(variant.sku).up();
// Title format: Brand + Product Name + Key Attribute (Color/Size)
item.ele('g:title').txt(
[product.brand, product.name, variant.color, variant.size].filter(Boolean).join(' ').slice(0, 150)
).up();
item.ele('g:description').txt(product.description.slice(0, 5000)).up();
item.ele('g:link').txt(`${process.env.STORE_URL}/products/${product.slug}?variant=${variant.id}`).up();
item.ele('g:image_link').txt(product.images[0]?.url ?? '').up();
item.ele('g:condition').txt('new').up();
item.ele('g:availability').txt(variant.inventory > 0 ? 'in_stock' : 'out_of_stock').up();
item.ele('g:price').txt(`${(variant.priceInCents / 100).toFixed(2)} USD`).up();
item.ele('g:brand').txt(product.brand ?? process.env.STORE_NAME!).up();
item.ele('g:google_product_category').txt(product.googleProductCategory).up();
item.ele('g:item_group_id').txt(product.id).up(); // groups variants together
if (variant.color) item.ele('g:color').txt(variant.color).up();
if (variant.size) item.ele('g:size').txt(variant.size).up();
if (product.gtin) item.ele('g:gtin').txt(product.gtin).up();
item.ele('g:identifier_exists').txt(product.gtin ? 'yes' : 'no').up();
}
}
res.setHeader('Content-Type', 'application/xml; charset=utf-8');
res.setHeader('Cache-Control', 'public, max-age=3600');
res.send(root.end({ prettyPrint: false }));
}
Register this feed URL in Merchant Center under Products → Feeds → Add a Primary Feed.
Use the Content API to push real-time price/inventory updates instead of waiting for Google's scheduled crawl:
import { google } from 'googleapis';
const content = google.content({ version: 'v2.1', auth: await new google.auth.GoogleAuth({
keyFile: process.env.GOOGLE_SERVICE_ACCOUNT_KEY_PATH,
scopes: ['https://www.googleapis.com/auth/content'],
}).getClient() });
// Push updated product when inventory or price changes
await content.products.insert({
merchantId: process.env.GOOGLE_MERCHANT_ID,
requestBody: {
offerId: variant.sku,
availability: variant.inventory > 0 ? 'in_stock' : 'out_of_stock',
price: { value: (variant.priceInCents / 100).toFixed(2), currency: 'USD' },
contentLanguage: 'en',
targetCountry: 'US',
channel: 'online',
},
});
Feed quality is the primary Shopping ranking factor. Fix these in order of impact:
Optimize product titles — put brand and key attributes first (Google truncates after ~70 characters):
Add GTINs/barcodes — missing GTINs is the most common cause of reduced impression share; add barcodes to every product that has one
Set Google product category — use Google's taxonomy (search "Google Product Taxonomy") and map each product type; use numeric IDs for exact matching
Ensure landing page price matches feed price — even $0.01 discrepancy causes price-mismatch disapproval; check Merchant Center → Diagnostics weekly
Add multiple product images — products with 3+ images get higher quality scores; lifestyle images + white background images both help
In Merchant Center, go to Products → Diagnostics to see all issues:
| Disapproval Reason | Fix |
|-------------------|-----|
| Price mismatch | Ensure feed price exactly matches schema.org price on the product page |
| Missing required attribute | Add missing fields: typically brand, gtin, or google_product_category |
| Image too small | Use images at least 500×500px; 1000×1000px recommended |
| Landing page error | Verify the product URL in the feed returns a 200 status code |
| Policy violation | Read the specific policy — common issues: drug claims, copyright images, counterfeit products |
identifier_exists: no only for truly private-label products without any GTIN/MPN — misusing it causes disapproval for products that do have identifiers| Problem | Solution |
|---------|----------|
| Products missing from Shopping ads despite being approved | Check that targetCountry and contentLanguage match the linked Google Ads campaign targeting |
| Feed fetch returns 404 after deployment | The feed URL is registered in Merchant Center — ensure your route still exists after deploys |
| GTIN required errors for private-label products | Set identifier_exists: no and provide a brand + MPN instead |
| Variants showing as separate products | Ensure all variants share the same item_group_id and differ only by color, size, or pattern |
| Shopify feed sync stuck | In Shopify, go to Google & YouTube → disconnect and reconnect the integration; or use a third-party feed app like Simprosys |
tools
Let shoppers save products to a wishlist, share it with friends, and get notified when saved items come back in stock or drop in price
development
Build a themeable storefront with design tokens and CSS custom properties that supports white-labeling, multi-brand variants, and dark mode
development
Speed up product discovery with instant search suggestions, fuzzy typo matching, and category-aware results powered by Algolia or Elasticsearch
development
Build a mobile-first storefront with thumb-friendly navigation, sticky add-to-cart buttons, and touch-optimized components for high mobile conversion