Integration of 1C-Bitrix with Dynamic Yield
Dynamic Yield is an enterprise personalization platform by Mastercard, a competitor to Adobe Target and Optimizely. Used by large retailers for A/B testing, content personalization, and real-time recommendations. Integration with Bitrix is built on two layers: Data Feed for catalog synchronization and Experience OS JavaScript SDK for transmitting behavioral events.
Data Feed: Catalog Synchronization
Dynamic Yield accepts product feeds in JSON or CSV format. JSON is more flexible—allows transmitting arbitrary attributes for segmentation.
JSON feed structure:
{
"version": "1.0",
"type": "full",
"products": [
{
"sku": "PROD-001",
"name": "Product Name",
"url": "https://example.ru/catalog/product/",
"price": 1500.00,
"in_stock": true,
"image_url": "https://example.ru/upload/iblock/abc/photo.jpg",
"categories": ["Electronics", "Smartphones"],
"group_id": "GROUP-001",
"description": "Brief product description",
"brand": "Samsung",
"keywords": ["smartphone", "android"],
"custom_attributes": {
"color": "Black",
"weight": "185g",
"supplier_id": 42
}
}
]
}
Feed generator in Bitrix:
function generateDynamicYieldFeed(): string
{
$products = [];
$res = CIBlockElement::GetList(
[],
['IBLOCK_ID' => CATALOG_IBLOCK_ID, 'ACTIVE' => 'Y'],
false,
false,
['ID', 'NAME', 'DETAIL_PAGE_URL', 'DETAIL_PICTURE',
'PREVIEW_TEXT', 'IBLOCK_SECTION_ID']
);
while ($el = $res->GetNextElement()) {
$fields = $el->GetFields();
$props = $el->GetProperties();
$price = CCatalogProduct::GetOptimalPrice($fields['ID']);
$priceVal = (float)($price['PRICE']['PRICE'] ?? 0);
$quantity = (int)(CCatalogProduct::GetByIDEx($fields['ID'])['QUANTITY'] ?? 0);
$inStock = $quantity > 0;
$imgUrl = '';
if ($fields['DETAIL_PICTURE']) {
$f = CFile::GetFileArray($fields['DETAIL_PICTURE']);
if ($f) $imgUrl = 'https://' . SITE_SERVER_NAME . $f['SRC'];
}
$section = CIBlockSection::GetByID($fields['IBLOCK_SECTION_ID'])->Fetch();
$categories = $section ? [$section['NAME']] : [];
$product = [
'sku' => $props['CML2_ARTICLE']['VALUE'] ?? (string)$fields['ID'],
'name' => $fields['NAME'],
'url' => 'https://' . SITE_SERVER_NAME . $fields['DETAIL_PAGE_URL'],
'price' => $priceVal,
'in_stock' => $inStock,
'image_url' => $imgUrl,
'categories' => $categories,
'description'=> strip_tags($fields['PREVIEW_TEXT'] ?? ''),
];
// Add custom attributes from properties
$customAttrs = [];
foreach (['BRAND', 'COLOR', 'WEIGHT'] as $propCode) {
if (!empty($props[$propCode]['VALUE'])) {
$customAttrs[strtolower($propCode)] = $props[$propCode]['VALUE'];
}
}
if ($customAttrs) {
$product['custom_attributes'] = $customAttrs;
}
$products[] = $product;
}
return json_encode([
'version' => '1.0',
'type' => 'full',
'products' => $products,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
Feed is published by URL and specified in Dynamic Yield → Feeds. Recommended update frequency—daily; with frequent price changes—multiple times daily via agent.
JavaScript SDK: Behavioral Events
Dynamic Yield requires initialization on every page:
window.DY = window.DY || {};
DY.recommendationContext = { type: 'HOMEPAGE' }; // overridden on each page type
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = '//cdn.dynamicyield.com/api/<?= DY_SITE_ID ?>/api_dynamic.js';
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'DY-api-script'));
DY_SITE_ID—ID from Dynamic Yield personal account.
Page context—Dynamic Yield personalizes content by page type:
// In product page template
?>
<script>
window.DY = window.DY || {};
DY.recommendationContext = {
type: 'PRODUCT',
data: ['<?= $arResult['ID'] ?>'] // Current product SKU
};
</script>
<?php
// In category template
?>
<script>
DY.recommendationContext = {
type: 'CATEGORY',
data: ['<?= $sectionCode ?>']
};
</script>
<?php
Add to cart event:
DY.API('event', {
name: 'Add to Cart',
properties: {
dyType: 'add-to-cart-v1',
value: price * quantity,
currency: 'RUB',
productId: String(productId),
quantity: quantity,
cart: currentCartItems.map(function(item) {
return { productId: String(item.id), quantity: item.qty, itemPrice: item.price };
})
}
});
Purchase event:
DY.API('event', {
name: 'Purchase',
properties: {
dyType: 'purchase-v1',
uniqueTransactionId: String(orderId),
value: orderTotal,
currency: 'RUB',
cart: orderItems.map(function(item) {
return { productId: String(item.product_id), quantity: item.quantity, itemPrice: item.price };
})
}
});
Data for this event is transmitted through HTML data attributes or inline PHP variables on the "Thank you for your order" page.
User Identification
Dynamic Yield links anonymous and authorized sessions. On authorization, call:
DY.API('event', {
name: 'Login',
properties: {
dyType: 'login-v1',
hashedEmail: sha256(userEmail.toLowerCase().trim())
}
});
SHA-256 email hash is computed on the client. Dynamic Yield doesn't accept email in plain text.
Widgets: Recommendation Blocks
Dynamic Yield displays personalized blocks through "widgets"—configured in personal account. On Bitrix side—just HTML container with ID:
<!-- In product page template: "You might like" -->
<div class="dy-recommendations" id="dy-widget-product-page"></div>
<!-- On homepage: "Personal recommendations" -->
<div class="dy-recommendations" id="dy-widget-homepage"></div>
Dynamic Yield itself fills these containers with recommendations based on user behavior.
Implementation Timelines
| Scope | Composition | Duration |
|---|---|---|
| Feed + basic SDK (context + cart + purchase) | Feed generator + JS events | 2–4 days |
| Identification + all page types | + hashed email + contexts | +1–2 days |
| A/B tests + segments + widgets | DY setup + widget testing | separate budget line |







