Generate product feeds for advertising platforms like Google, Meta, and Amazon.
Product feeds export your catalog in formats required by advertising platforms:
Start with a Vendure Query extractor to get product data:
.extract('get-products', {
adapterCode: 'vendureQuery',
entity: 'PRODUCT',
relations: 'variants,featuredAsset,collections,translations',
languageCode: 'en',
batchSize: 1000,
})
Map fields to feed format:
.transform('prepare-feed', {
operators: [
{ op: 'template', args: {
template: 'https://mystore.com/products/${slug}',
target: 'link',
}},
{ op: 'template', args: {
template: 'https://mystore.com${featuredAsset.preview}',
target: 'image_link',
}},
{ op: 'set', args: { path: 'condition', value: 'new' }},
{ op: 'copy', args: { source: 'variants.0.stockLevel', target: 'stockStatus' }},
{ op: 'lookup', args: {
source: 'stockStatus',
map: {
'IN_STOCK': 'in_stock',
'OUT_OF_STOCK': 'out_of_stock',
'LOW_STOCK': 'in_stock',
},
target: 'availability',
default: 'out_of_stock',
}},
],
})
Use the feed step to output the final file:
.feed('generate-google-feed', {
adapterCode: 'googleMerchant',
format: 'XML',
outputPath: '/feeds/google-shopping.xml',
targetCountry: 'US',
contentLanguage: 'en',
currency: 'USD',
storeUrl: 'https://mystore.com',
})
| Field | Source | Notes |
|---|---|---|
| id | product.id or variant.sku | Unique identifier |
| title | name | Product title |
| description | description | Product description |
| link | Generated URL | Product page URL |
| image_link | featuredAsset.preview | Main product image |
| price | variant.price | Format: “29.99 USD” |
| availability | stock status | in_stock, out_of_stock |
| condition | Usually “new” | new, used, refurbished |
| Field | Source |
|---|---|
| brand | customFields.brand |
| gtin | customFields.gtin |
| mpn | variant.sku |
| google_product_category | Google taxonomy ID |
| product_type | collection path |
| item_group_id | product.id (for variants) |
| color, size, material | option values |
| shipping | shipping configuration |
| custom_label_0-4 | Custom segmentation |
.feed('google-feed', {
adapterCode: 'googleMerchant',
format: 'XML',
outputPath: '/feeds/google.xml',
// Required settings
targetCountry: 'US',
contentLanguage: 'en',
currency: 'USD',
storeUrl: 'https://mystore.com',
// Field mappings
titleField: 'name',
descriptionField: 'description',
priceField: 'variants.0.price',
imageField: 'featuredAsset.preview',
brandField: 'customFields.brand',
gtinField: 'customFields.gtin',
// Options
includeOutOfStock: false,
})
| Field | Source |
|---|---|
| id | unique identifier |
| title | product name |
| description | product description |
| availability | in stock, out of stock |
| condition | new, refurbished, used |
| price | formatted price |
| link | product URL |
| image_link | product image URL |
.feed('meta-catalog', {
adapterCode: 'metaCatalog',
format: 'CSV', // or 'xml'
outputPath: '/feeds/meta-catalog.csv',
currency: 'USD',
// Field mappings
titleField: 'name',
descriptionField: 'description',
priceField: 'variants.0.price',
imageField: 'featuredAsset.preview',
brandField: 'customFields.brand',
// Options
includeVariants: true,
})
Meta accepts CSV with these headers:
id,title,description,availability,condition,price,link,image_link,brand
.feed('amazon-feed', {
adapterCode: 'amazonFeed',
outputPath: '/feeds/amazon.txt',
currency: 'USD',
// Field mappings
titleField: 'name',
descriptionField: 'description',
priceField: 'variants.0.price',
imageField: 'featuredAsset.preview',
brandField: 'customFields.brand',
gtinField: 'customFields.gtin',
})
Create feeds in any format for any platform.
.feed('custom-csv', {
adapterCode: 'customFeed',
format: 'CSV',
outputPath: '/feeds/products.csv',
fieldMapping: {
'Product ID': 'id',
'Product Name': 'name',
'Price': 'variants.0.price',
'Category': 'collections.0.name',
},
})
.feed('custom-json', {
adapterCode: 'customFeed',
format: 'JSON',
outputPath: '/feeds/products.json',
})
.feed('custom-xml', {
adapterCode: 'customFeed',
format: 'XML',
outputPath: '/feeds/products.xml',
rootElement: 'products',
itemElement: 'product',
})
Save to the file system:
outputPath: '/feeds/google.xml'
Files are saved to the Vendure assets directory.
Upload directly to S3:
bucket: 'my-feeds-bucket',
prefix: 'google/',
connectionCode: 'aws-s3',
POST the feed to an API:
outputUrl: 'https://api.platform.com/feeds',
bearerTokenSecretCode: 'platform-api-key',
Generate feeds on a schedule:
const feedPipeline = createPipeline()
.trigger('schedule', {
type: 'SCHEDULE',
cron: '0 4 * * *', // Daily at 4 AM
})
.extract('get-products', { ... })
.transform('prepare', { ... })
.feed('generate', { ... })
.edge('schedule', 'get-products')
.edge('get-products', 'prepare')
.edge('prepare', 'generate')
.build();
includeOutOfStock: false
Add a filter step:
.transform('filter-electronics', {
operators: [
{ op: 'when', args: {
conditions: [{ field: 'collections.0.name', cmp: 'contains', value: 'Electronics' }],
action: 'keep',
}},
],
})
.transform('custom-filter', {
operators: [
{ op: 'when', args: {
conditions: [
{ field: 'variants.0.price', cmp: 'gte', value: 10 },
{ field: 'variants.0.stockLevel', cmp: 'ne', value: 'OUT_OF_STOCK' },
],
action: 'keep',
}},
],
})