Генерація каталогів товарів для Facebook/Instagram Catalog
Meta вимагає каталог у форматі CSV, TSV або XML (RSS/Atom). Каталог використовується в динамічній рекламі (Dynamic Ads), Instagram Shopping та Shops — три різні розміщення з частково перетинаючимися вимогами до полів. Одна помилка у форматі поля price або availability призводить до відхилення всієї партії товарів при завантаженні.
Обов'язкові поля каталогу
| Поле | Формат | Приклад |
|---|---|---|
id |
рядок до 100 символів | SKU-44231 |
title |
рядок до 150 символів | Чоловіча синя зимова куртка L |
description |
рядок до 9999 символів | — |
availability |
enum | in stock / out of stock / preorder |
condition |
enum | new / refurbished / used |
price |
число + код валюти | 4990.00 RUB |
link |
URL | HTTPS обов'язково |
image_link |
URL | мін. 500×500 px, HTTPS |
brand |
рядок | — |
Додаткові поля для одягу та взуття
Для категорії Apparel & Accessories Meta вимагає:
-
google_product_category— числовий ID з таксономії Google (Meta використовує саме її) -
size— розмір (XL,44,42/34) -
color— колір мовою цільової аудиторії -
gender—male/female/unisex -
age_group—adult/kids/newborn -
material— матеріал (опціонально, але підвищує relevance score)
Генератор CSV-каталогу
CSV простіший у генерації та налагодженні, ніж XML. Meta приймає обидва формати однаково.
class MetaCatalogFeedGenerator
{
private const HEADERS = [
'id', 'title', 'description', 'availability', 'condition',
'price', 'link', 'image_link', 'additional_image_link',
'brand', 'google_product_category', 'color', 'size',
'gender', 'age_group', 'sale_price', 'sale_price_effective_date',
];
public function generate(string $outputPath): void
{
$file = fopen($outputPath, 'w');
// BOM не додаємо — Meta не вимагає, може сломати парсер
fputcsv($file, self::HEADERS, "\t"); // TSV надійніше за CSV через коми в описі
Product::with(['images', 'category', 'brand', 'variants'])
->where('is_active', true)
->chunk(200, function ($products) use ($file) {
foreach ($products as $product) {
foreach ($this->expandVariants($product) as $row) {
fputcsv($file, $row, "\t");
}
}
});
fclose($file);
}
private function expandVariants(Product $product): array
{
if ($product->variants->isEmpty()) {
return [$this->buildRow($product, null)];
}
return $product->variants->map(
fn($variant) => $this->buildRow($product, $variant)
)->toArray();
}
private function buildRow(Product $product, ?ProductVariant $variant): array
{
$id = $variant ? $product->sku . '-' . $variant->sku : $product->sku;
$price = $variant?->price ?? $product->price;
$stock = $variant?->stock ?? $product->stock;
$additionalImages = $product->images->skip(1)
->pluck('cdn_url')
->take(9) // Meta дозволяє до 10 зображень
->implode(',');
$salePrice = '';
$salePriceDate = '';
if ($product->sale_price && $product->sale_ends_at > now()) {
$salePrice = number_format($product->sale_price, 2, '.', '') . ' RUB';
$salePriceDate = $product->sale_starts_at->toIso8601String()
. '/' . $product->sale_ends_at->toIso8601String();
}
return [
$id,
mb_substr($product->name . ($variant ? ' ' . $variant->name : ''), 0, 150),
strip_tags($product->description),
$stock > 0 ? 'in stock' : 'out of stock',
'new',
number_format($price, 2, '.', '') . ' RUB',
route('products.show', $product->slug) . ($variant ? '?variant=' . $variant->id : ''),
$product->mainImage()?->cdn_url ?? '',
$additionalImages,
$product->brand?->name ?? '',
$product->google_category_id ?? '',
$variant?->color ?? $product->color ?? '',
$variant?->size ?? '',
$product->gender ?? '',
$product->age_group ?? 'adult',
$salePrice,
$salePriceDate,
];
}
}
Налаштування в Business Manager
Після генерації каталогу:
- Commerce Manager → Catalog → Data Sources → Add Data Feed
- Вказати URL каталогу або завантажити файл вручну
- Вибрати розклад оновлення: щогодини, щодня або вручну
- Призначити каталог рекламним акаунтам
Meta надає діагностику помилок у розділі Catalog → Issues — кожна позиція з проблемою помічена з описом причини.
Pixel + Catalog для динамічного ретаргетингу
Для Dynamic Ads недостатньо тільки каталогу — потрібно налаштувати Meta Pixel з подіями:
// Сторінка товару
fbq('track', 'ViewContent', {
content_ids: ['SKU-44231'],
content_type: 'product',
value: 4990.00,
currency: 'RUB',
});
// Додавання у кошик
fbq('track', 'AddToCart', {
content_ids: ['SKU-44231'],
content_type: 'product',
value: 4990.00,
currency: 'RUB',
});
content_ids мають точно збігатися з полем id у каталозі — інакше матчинг не працює.







