npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

google-feeder

v0.1.1

Published

Minimal-dependency TypeScript helpers for generating Google Merchant Center XML feeds.

Readme

google-feeder

Minimal-dependency TypeScript helpers for generating Google Merchant Center XML feeds.

The package currently supports:

  • RSS 2.0 feeds with the g: Merchant Center namespace
  • Atom 1.0 feeds with the g: Merchant Center namespace
  • Standalone products and explicit product variant groups
  • Validation modes for warning-only, strict, or disabled validation
  • Object-first rendering APIs and a small builder API

Install

npm install google-feeder

Quick Start

import { renderRss, type MerchantProduct } from "google-feeder";

const product: MerchantProduct = {
  id: "sku-123",
  title: "Basic Tee",
  description: "A plain cotton tee",
  link: "https://example.com/products/basic-tee",
  image_link: "https://example.com/images/basic-tee.jpg",
  availability: "in_stock",
  condition: "new",
  price: { value: 19.99, currency: "USD" },
  brand: "Acme"
};

const result = await renderRss({
  channel: {
    title: "Example Store",
    link: "https://example.com",
    description: "Main product feed"
  },
  catalog: [product],
  pretty: true
});

console.log(result.content);
console.log(result.diagnostics);

result.content is the XML document. result.diagnostics contains validation warnings or errors collected during rendering.

RSS 2.0

Use renderRss() to get the full feed as a string, or streamRss() to stream chunks for larger catalogs.

import { renderRss } from "google-feeder";

const { content, diagnostics } = await renderRss({
  channel: {
    title: "Example Store",
    link: "https://example.com",
    description: "Google Merchant Center feed"
  },
  catalog: products,
  validation: "warn",
  pretty: true
});

RSS output includes standard <item> fields like title, link, and description, plus matching g:title, g:link, and g:description fields for Merchant Center compatibility.

Atom 1.0

Use renderAtom() for a full string or streamAtom() for chunked output.

import { renderAtom } from "google-feeder";

const { content } = await renderAtom({
  feed: {
    title: "Example Store Feed",
    id: "tag:example.com,2026:/feeds/catalog",
    link: "https://example.com",
    updated: "2026-01-01T00:00:00Z",
    authorName: "Example Store"
  },
  catalog: products,
  pretty: true
});

Atom feed metadata is format-specific and requires:

  • title
  • id
  • link
  • updated
  • authorName

subtitle is optional.

Variants

Google product variants are modeled explicitly with ProductVariantGroup. Each variant is rendered as an individual item or entry, and the library injects item_group_id automatically.

import { renderAtom, type ProductVariantGroup } from "google-feeder";

const group: ProductVariantGroup = {
  itemGroupId: "shirt-1",
  variesBy: ["color", "size"],
  shared: {
    title: "Variant Tee",
    description: "Variant tee for grouped rendering",
    link: "https://example.com/products/variant-tee",
    image_link: "https://example.com/images/variant-default.jpg",
    availability: "in_stock",
    condition: "new",
    price: { value: 29.99, currency: "USD" },
    brand: "Acme"
  },
  variants: [
    {
      id: "shirt-1-red-s",
      color: "Red",
      size: "S",
      link: "https://example.com/products/variant-tee-red-s",
      image_link: "https://example.com/images/variant-tee-red-s.jpg"
    },
    {
      id: "shirt-1-blue-m",
      color: "Blue",
      size: "M",
      link: "https://example.com/products/variant-tee-blue-m",
      image_link: "https://example.com/images/variant-tee-blue-m.jpg"
    }
  ]
};

const result = await renderAtom({
  feed: {
    title: "Variants",
    id: "tag:example.com,2026:/feeds/variants",
    link: "https://example.com",
    updated: "2026-01-01T00:00:00Z",
    authorName: "Example Store"
  },
  catalog: [group]
});

Variant validation covers:

  • at least one supported variant axis
  • required values for every axis on every variant
  • unique variant-value combinations within a group
  • duplicate product ids
  • duplicate explicit item_group_id groups

Supported variant axes are:

  • color
  • size
  • material
  • pattern
  • age_group
  • gender

Builder API

If you want to incrementally assemble a catalog, use createMerchantFeed().

import { createMerchantFeed } from "google-feeder";

const feed = createMerchantFeed({
  validation: "warn",
  pretty: true
});

feed.add(product);
feed.add(group);
feed.addMany(otherProducts);

const rss = await feed.toRss({
  title: "Example Store",
  link: "https://example.com",
  description: "Main RSS feed"
});

const atom = await feed.toAtom({
  title: "Example Store",
  id: "tag:example.com,2026:/feeds/catalog",
  link: "https://example.com",
  updated: "2026-01-01T00:00:00Z",
  authorName: "Example Store"
});

Streaming is also available:

for await (const chunk of feed.toRssChunks({
  title: "Example Store",
  link: "https://example.com",
  description: "Main RSS feed"
})) {
  process.stdout.write(chunk);
}

Validation

Validation can run in three modes:

  • "warn": collect diagnostics and keep rendering
  • "strict": throw ValidationError on the first error
  • "off": skip diagnostics

Examples:

import { ValidationError, renderRss, validateCatalog, validateProduct } from "google-feeder";

const diagnostics = validateProduct(product, { validation: "warn" });

const catalogDiagnostics = await validateCatalog({
  catalog: [product, group],
  validation: "warn"
});

try {
  await renderRss({
    channel: {
      title: "Strict feed",
      link: "https://example.com",
      description: "Strict feed"
    },
    catalog: [product],
    validation: "strict"
  });
} catch (error) {
  if (error instanceof ValidationError) {
    console.error(error.diagnostics);
  }
}

Diagnostics include:

  • severity
  • code
  • message
  • attribute
  • productId
  • itemGroupId
  • specUrl

Supported Attribute Shapes

The package supports a broad typed surface for the standard Merchant Center product feed, including:

  • simple scalar attributes such as id, title, brand, condition, item_group_id
  • repeated attributes such as additional_image_link, product_highlight, included_destination
  • grouped attributes such as installment, subscription_cost, loyalty_program
  • repeated grouped attributes such as shipping, product_detail, certification, tax

Helpful input formats:

  • money values can be "19.99 USD" or { value: 19.99, currency: "USD" }
  • measures can be "2.5 kg" or { value: 2.5, unit: "kg" }
  • booleans can be true / false or "yes" / "no"

Notes

  • Runtime dependencies: none
  • Target runtime: Node.js >=18
  • Package output: ESM, CommonJS, and generated .d.ts declarations
  • Scope is the standard Merchant Center product feed only; it does not cover local inventory, promotions, reviews, or vehicle feeds

Development

npm install
npm test