Перший live банер у DV360. v2 (300x250+300x600) запущено після фіксу tracking-gap 2026-04-30. Реальні дані: 6.9% engaged / 75.5% passive у форматі 300x600.
Status: Live в DV360. v2 після фіксу 2026-04-30. Перший проект де реалізовано engaged/passive/interrupt-класифікацію.
KPIs (Fluvir 300x600, 2026-04-30):
https://europe-central2-banner-analytics-fluvir.cloudfunctions.net/trackbanner-analytics-fluvir.banner_analytics.eventsbanner-analytics-fluvir| Версія | DV360 ID | Формати | Метод tracking | Статус |
|---|---|---|---|---|
| v1 | xbid.716177674 | 300x250 | GET-pixel | LIVE, працює |
| v2 | xbid.721925137 | 300x250 + 300x600 | GET-pixel (після фіксу) | LIVE з 2026-04-30 |
Симптом: 32 events у BQ vs 31,185 impressions у DV360 за 29.04 → gap 99.9%.
Корінь: новий v2 банер використовував navigator.sendBeacon(Blob, application/json) + fetch(POST json). Обидва падають у SafeFrame/sandbox-iframe з CSP connect-src 'self'.
Чому старий банер працював: він використовував new Image().src = ENDPOINT?... (GET-pixel) — проходить через CSP img-src (ширша) і не потребує CORS preflight.
Фікс (клієнт) — index.html:
function send(name, extra) {
var data = { sid:ctx.sid, name:name, product:ctx.product, size:ctx.size, ver:ctx.ver,
cid:ctx.cid, crid:ctx.crid, site:ctx.site, device:ctx.device, _t: Date.now() };
if (extra) {
if (extra.step != null) data.step = extra.step;
if (extra.dur != null) data.dur = extra.dur;
if (extra.payload != null) data.payload = (typeof extra.payload === 'string') ? extra.payload : JSON.stringify(extra.payload);
}
var qs = [];
for (var k in data) {
if (data[k] == null) continue;
qs.push(encodeURIComponent(k) + '=' + encodeURIComponent(data[k]));
}
try { new Image().src = ENDPOINT + '/pixel?' + qs.join('&'); } catch(_) {}
}
Фікс (Cloud Function) — track:
exports.track = async (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
if (req.method === 'GET' || req.path === '/pixel') {
data = req.query || {};
} else if (req.method === 'POST') {
data = (typeof req.body === 'string') ? JSON.parse(req.body) : (req.body || {});
}
// ... insert у BQ ... повернути 1×1 GIF якщо GET
};
Деплой:
gcloud functions deploy track --gen2 --runtime=nodejs20 \
--region=europe-central2 --trigger-http --allow-unauthenticated \
--project=banner-analytics-fluvir --entry-point=track
| Timer | Запуск | Коли | Що робить |
|---|---|---|---|
fluvir-v2-check-4h.timer |
one-shot | 2026-04-30 15:44 UTC ✅ FIRED | BQ-запит за 4h, recap у Telegram |
fluvir-v2-check-morning.timer |
one-shot | 2026-05-01 06:00 UTC ✅ FIRED | BQ-запит за 24h, recap у Telegram |
Скрипт: /usr/local/bin/fluvir-v2-check.sh <hours_window> [<label>]
💡 Обидва one-shot вже відстріляли. Вирішити: вимкнути cleanup чи залишити як історія.
fluvir-v2-check-4h.timer + fluvir-v2-check-morning.timerUmbrella: ../index.md (архітектура tracking, event taxonomy)
BigQuery: ../../../integrations/bigquery.md
Outbox processed: /root/.claude/projects/-/memory/outbox-to-desktop/processed/read-2026-04-30T073547Z-fluvir-banner-tracking-fix.md
Code: D:\Claude Code\banners\Інтерактивні банери\fluvir\index.html (Desktop у Сергія)