Відкритий код

Один event_id для браузера й вашого сервера

ad-events — невелика бібліотека TypeScript, яку ми виділили з власної системи вимірювання LoomaScale. Вона створює один ідентифікатор дедуплікації на конверсію й передає те саме значення до Meta Pixel, Google Ads, пікселя ChatGPT Ads і до їхніх серверних Conversions API — тому конверсія, про яку повідомили двічі, рахується один раз.

Переглянути на GitHubВстановленняnpm install ad-events
  • Жодних залежностей
  • TypeScript, ESM і CJS
  • Node, Bun, Deno і Edge

Чому конверсії рахуються двічі

Вимірювання лише в браузері втрачає від п'ятої частини до третини конверсій через блокувальники реклами та обмеження приватності в браузерах, тому звична відповідь — надсилати ті самі конверсії ще раз із сервера. Зробіть це без спільного ідентифікатора, і про кожну покупку буде повідомлено двічі: ваш дохід у звітах завищений, вартість конверсії виглядає кращою, ніж вона є, а автоматичні стратегії ставок оптимізуються під число, якого ніколи не існувало.

Кожна платформа підтримує це рішення — і кожна називає його по-своєму. Meta очікує eventID у четвертому аргументі виклику пікселя й event_id усередині серверної події. Піксель ChatGPT Ads очікує event_id в аргументі опцій, а суму — цілим числом у центах, а не десятковим дробом. У Google Ads пари «браузер плюс сервер» немає взагалі: він дедуплікує за transaction_id. Помилитеся в одному з них — і ніщо не зламається: ви дізнаєтеся про це за кілька тижнів, із витрат.

Як працює бібліотека

Один виклик повідомляє про конверсію всім налаштованим платформам і повертає використаний ідентифікатор, щоб ви могли передати його на власний бекенд у тому самому обробнику кліку.

  1. 1Ідентифікатор створює браузер

    Саме браузер, бо це та сторона, яка може не повідомити зовсім. Створіть ідентифікатор там, де відбувається клік, і серверна подія залишиться придатною до дедуплікації навіть тоді, коли блокувальник з'їв піксель — а це і є той випадок, для якого ви додавали серверну подію.

  2. 2Кожен адаптер отримує те саме значення

    Адаптери Meta, Google Ads і ChatGPT Ads кладуть його туди, де його очікує їхня платформа, і переводять суму в потрібну одиницю. Адаптер, чий піксель не завантажився, просто нічого не робить і не кидає винятку — тому невдале повідомлення ніколи не зламає оформлення замовлення.

  3. 3Сервер повторює його

    Коли надходить вебхук про оплату — єдине справжнє підтвердження, що гроші прийшли, — сервер надсилає ту саму назву події й той самий ідентифікатор. Платформа розпізнає пару й залишає одну конверсію.

У браузері, в обробнику кліку
import {
  createTracker,
  metaAdapter,
  googleAdsAdapter,
  openAiAdapter,
} from "ad-events/browser";

const tracker = createTracker({
  adapters: [
    metaAdapter({ eventNames: { checkout_started: "InitiateCheckout" } }),
    googleAdsAdapter({
      conversionId: "AW-123456789",
      labels: { checkout_started: "abcDEF_ghi" },
    }),
    openAiAdapter(),
  ],
});

// One id, every platform — and it is the return value, so you
// cannot forget to send it to your own backend.
const eventId = tracker.track({
  name: "checkout_started",
  value: 49,
  currency: "USD",
});

await fetch("/api/checkout", {
  method: "POST",
  body: JSON.stringify({ plan, price, eventId }),
});
На сервері, у вебхуку про оплату
import { createMetaConversionsApi } from "ad-events/server";

const meta = createMetaConversionsApi({
  pixelId: process.env.META_PIXEL_ID,
  accessToken: process.env.META_ACCESS_TOKEN,
});

await meta.send({
  eventName: "InitiateCheckout", // identical to the browser event
  eventId,                       // the id the browser minted
  email: order.email,            // normalized and hashed for you
  fbp, fbc,                      // the cookies the browser read
  customData: { value: order.price, currency: "USD" },
});

Що вона охоплює

  • Meta Pixel і Conversions API

    Спільний event_id, куки _fbp і _fbc, прочитані в браузері, щоб їх несла серверна подія, а також поля ідентичності, нормалізовані та захешовані SHA-256 так само, як їх хешує Meta під час зіставлення. Ваш власний ідентифікатор користувача хешується перед надсиланням і ніколи не йде у відкритому вигляді.

  • Google Ads

    Конверсії через gtag із дедуплікацією за transaction_id, синхронний незворотний ключ, щоб та сама реєстрація, про яку повідомили дві сторінки повернення, рахувалася один раз, і клік-ідентифікатори gclid, gbraid і wbraid як одне значення замість трьох порожніх стовпців.

  • ChatGPT Ads (OpenAI)

    Піксель oaiq і Conversions API від OpenAI, разом із двома речами, у яких легко помилитися: сума цілим числом у центах і тип корисного навантаження, який не випливає з назви події. Публічних інструментів для цієї платформи поки майже немає.

Атрибуція за першим дотиком, бо воронка живе довше за URL

Реклама приводить людину на URL із параметрами utm і клік-ідентифікатором. Далі відвідувач робить три переходи й платить через два дні — на той момент цих параметрів давно немає, а URL повернення від платіжного сервісу охоче перезапише їх своїми.

Бібліотека знімає їх один раз, зберігає перший дотик і читає їх назад, коли конверсія нарешті настає. Вона також відповідає на питання, яке насправді ставить воронка холодного трафіку: цей відвідувач прийшов із платної реклами? Для платних соцмереж мають збігтися і джерело, і канал; клік-ідентифікатор Google є доказом сам собою, бо Google додає його лише до кліку, за який взяв плату.

Питання

Чи замінює ad-events Google Tag Manager?

Ні. Вона замінює написаний руками зв'язувальний код, який ви інакше поклали б у менеджер тегів або у свій застосунок, щоб ідентифікатори збігалися між платформами. Власні фрагменти пікселів ви завантажуєте самі.

Чому ідентифікатор має створювати браузер, а не сервер?

Бо браузер — це та сторона, яка може не повідомити зовсім. Якщо ідентифікатор створює сервер, то заблокований піксель означає, що браузерна подія не надійде й дедуплікувати буде нічого. Створення ідентифікатора в обробнику кліку та його передавання зберігають пару саме в тому випадку, через який серверне вимірювання й з'явилося.

Мої події в Meta все одно не дедуплікуються. Що перевірити?

Чотири речі, у такому порядку: назва події однакова з обох боків, ідентифікатор події саме однаковий, а не просто присутній з обох боків, дві події відстоять одна від одної на секунди, і обидві оголошують джерело дії website. У Events Manager є вкладка Test Events, яка показує, яка половина надійшла.

Чи працює це на Cloudflare Workers або Vercel Edge?

Так. Серверна точка входу використовує лише fetch і WebCrypto, без вбудованих модулів Node, тому вона працює без змін на Node, Bun, Deno і в середовищах edge.

Чи надсилає бібліотека дані ще кудись, окрім рекламних платформ?

Ні. Немає ні телеметрії, ні власного сервісу. Єдині мережеві виклики, які вона робить, — ті, що ви налаштували, до вибраних вами платформ.

Спершу зроблено для власної воронки

LoomaScale керує Google Ads і Meta Ads із ChatGPT та Claude. Ця бібліотека — шар вимірювання під тим продуктом, і ми опублікували її, бо проблема дедуплікації, яку вона вирішує, трапляється в кожного рекламодавця.

Подивитися, що робить LoomaScale