[{"data":1,"prerenderedAt":1552},["ShallowReactive",2],{"article-alternates":3,"article-\u002Fru\u002Fdata\u002Fserver-side-gtm-konversiya-api-production":13},{"i18nKey":4,"paths":5},"data-001-2026-05",{"de":6,"en":7,"es":8,"fr":9,"it":10,"ru":11,"tr":12},"\u002Fde\u002Fdata\u002Fserver-side-gtm-conversion-api-produktion","\u002Fen\u002Fdata\u002Fserver-side-gtm-conversion-api-production","\u002Fes\u002Fdata\u002Fserver-side-gtm-conversion-api-produccion","\u002Ffr\u002Fdata\u002Fgtm-serverside-conversion-api-production","\u002Fit\u002Fdata\u002Fserver-side-gtm-conversion-api-da-produzione","\u002Fru\u002Fdata\u002Fserver-side-gtm-konversiya-api-production","\u002Ftr\u002Fdata\u002Fserver-side-gtm-ve-conversion-api-sifirdan-productiona",{"_path":11,"_dir":14,"_draft":15,"_partial":15,"_locale":16,"title":17,"description":18,"publishedAt":19,"modifiedAt":19,"category":14,"i18nKey":4,"tags":20,"readingTime":26,"author":27,"body":28,"_type":1546,"_id":1547,"_source":1548,"_file":1549,"_stem":1550,"_extension":1551},"data",false,"","Server-Side GTM и Conversion API: От нуля к Production","Развертывание server-side tagging на Cloud Run и Workers, контейнер-шаблон, дедупликация событий и стратегии мониторинга production.","2026-05-07",[21,22,23,24,25],"server-side-gtm","conversion-api","cloud-run","event-deduplication","privacy-sandbox",9,"Roibase",{"type":29,"children":30,"toc":1538},"root",[31,39,46,51,56,102,108,129,134,245,281,454,519,525,575,580,1031,1075,1110,1131,1137,1142,1147,1199,1220,1233,1254,1260,1366,1387,1437,1513,1519,1532],{"type":32,"tag":33,"props":34,"children":35},"element","p",{},[36],{"type":37,"value":38},"text","Браузерная аналитика умерла. Third-party cookie исчезли, ITP упал до 12 часов, Consent Mode v2 стал обязательным. Маркеры, которые не отправляют события напрямую в API-endpoints Meta и Google на стороне сервера, сейчас находятся в полной тьме атрибуции. Server-side Google Tag Manager (sGTM) и Conversion API в 2026 году — это не опция, а production requirement. В этой статье мы покажем, как развернуть production-ready sGTM контейнер на Cloud Run с нуля, как настроить дедупликацию событий и какие метрики мониторить.",{"type":32,"tag":40,"props":41,"children":43},"h2",{"id":42},"почему-server-side-tagging-требует-контейнера",[44],{"type":37,"value":45},"Почему Server-Side Tagging требует контейнера",{"type":32,"tag":33,"props":47,"children":48},{},[49],{"type":37,"value":50},"Классический GTM на стороне браузера загружает JavaScript-библиотеку и собирает данные из user agent. Server-side GTM работает совершенно иначе: Node.js контейнер, запущенный на твоём сервере, принимает HTTP POST от клиента, обогащает события (парсинг IP, user-agent, first-party ID из cookie) и перенаправляет их в целевые API (Meta CAPI, Google Ads Conversion, GA4 Measurement Protocol). Эта архитектура дает три ключевых преимущества: (1) ты обходишь ограничения браузера — ITP, adblock, CORS просто не существуют; (2) ты контролируешь хеширование PII — email, телефон хешируются на сервере SHA-256, в браузер никогда не возвращаются; (3) ты отправляешь один event в несколько платформ параллельно — один POST с клиента, fan-out на 4 разных endpoint с сервера.",{"type":32,"tag":33,"props":52,"children":53},{},[54],{"type":37,"value":55},"Официальный путь Google — App Engine или Cloud Run. App Engine приносит фиксированную стоимость и auto-scaling, но не кастомизируется. Cloud Run предпочтительнее: с минимальной инстанцией 1 ты гарантируешь latency 24\u002F7, и ты полностью кастомизируешь image через Dockerfile (например, injection переменных окружения из secrets, startup scripts). Альтернатива — Cloudflare Workers, где cold-start быстрее (~5ms против 200ms), но Node.js sandbox ограничивает возможности (некоторые GTM теги не работают в custom template с native require).",{"type":32,"tag":33,"props":57,"children":58},{},[59,61,68,70,76,78,84,86,92,94,100],{"type":37,"value":60},"Процесс развертывания: (1) новый проект в Google Cloud Console, (2) ",{"type":32,"tag":62,"props":63,"children":65},"code",{"className":64},[],[66],{"type":37,"value":67},"gcloud",{"type":37,"value":69}," CLI pull'ит sGTM container image, (3) Cloud Run service создаешь с environment variable'ами (",{"type":32,"tag":62,"props":71,"children":73},{"className":72},[],[74],{"type":37,"value":75},"CONTAINER_CONFIG",{"type":37,"value":77},", ",{"type":32,"tag":62,"props":79,"children":81},{"className":80},[],[82],{"type":37,"value":83},"PREVIEW_SERVER_URL",{"type":37,"value":85},"), (4) кастомный домен привязываешь (например, ",{"type":32,"tag":62,"props":87,"children":89},{"className":88},[],[90],{"type":37,"value":91},"gtm.roibase.com.tr",{"type":37,"value":93},") — критично для first-party контекста, (5) tagging server URL добавляешь в web GTM (",{"type":32,"tag":62,"props":95,"children":97},{"className":96},[],[98],{"type":37,"value":99},"serverContainerUrl",{"type":37,"value":101}," параметр). Первое развертывание занимает ~15 минут, последующие через CI\u002FCD — 2 минуты.",{"type":32,"tag":40,"props":103,"children":105},{"id":104},"event-deduplication-связываем-клиент-сервер-одним-id",[106],{"type":37,"value":107},"Event Deduplication: связываем клиент + сервер одним ID",{"type":32,"tag":33,"props":109,"children":110},{},[111,113,119,121,127],{"type":37,"value":112},"Критическая проблема server-side GTM — дедупликация. Если одно преобразование отправится и из браузера (client-side GA4 tag), и с сервера (server-side GA4 client), платформа посчитает 2 conversion. Для Meta CAPI и Google Ads Conversion система deduplication ID обязательна. Как это работает: каждому event присваиваешь уникальный ",{"type":32,"tag":62,"props":114,"children":116},{"className":115},[],[117],{"type":37,"value":118},"event_id",{"type":37,"value":120}," (или в терминологии Meta ",{"type":32,"tag":62,"props":122,"children":124},{"className":123},[],[125],{"type":37,"value":126},"event_name + event_id",{"type":37,"value":128},"), и клиент, и сервер отправляют один и тот же ID, платформа в 24-часовом окне проверяет ID collision и drop дубликат.",{"type":32,"tag":33,"props":130,"children":131},{},[132],{"type":37,"value":133},"Стратегии Deduplication ID:",{"type":32,"tag":135,"props":136,"children":137},"table",{},[138,162],{"type":32,"tag":139,"props":140,"children":141},"thead",{},[142],{"type":32,"tag":143,"props":144,"children":145},"tr",{},[146,152,157],{"type":32,"tag":147,"props":148,"children":149},"th",{},[150],{"type":37,"value":151},"Метод",{"type":32,"tag":147,"props":153,"children":154},{},[155],{"type":37,"value":156},"Преимущество",{"type":32,"tag":147,"props":158,"children":159},{},[160],{"type":37,"value":161},"Риск",{"type":32,"tag":163,"props":164,"children":165},"tbody",{},[166,185,203,221],{"type":32,"tag":143,"props":167,"children":168},{},[169,175,180],{"type":32,"tag":170,"props":171,"children":172},"td",{},[173],{"type":37,"value":174},"UUID v4 (случайный)",{"type":32,"tag":170,"props":176,"children":177},{},[178],{"type":37,"value":179},"Коллизия невероятна",{"type":32,"tag":170,"props":181,"children":182},{},[183],{"type":37,"value":184},"Нужна синхронизация клиент-сервер (localStorage\u002Fcookie)",{"type":32,"tag":143,"props":186,"children":187},{},[188,193,198],{"type":32,"tag":170,"props":189,"children":190},{},[191],{"type":37,"value":192},"Transaction ID (e-commerce)",{"type":32,"tag":170,"props":194,"children":195},{},[196],{"type":37,"value":197},"Естественный уникум",{"type":32,"tag":170,"props":199,"children":200},{},[201],{"type":37,"value":202},"Отсутствует в non-transaction event (lead, signup)",{"type":32,"tag":143,"props":204,"children":205},{},[206,211,216],{"type":32,"tag":170,"props":207,"children":208},{},[209],{"type":37,"value":210},"Session ID + timestamp",{"type":32,"tag":170,"props":212,"children":213},{},[214],{"type":37,"value":215},"Легко генерировать",{"type":32,"tag":170,"props":217,"children":218},{},[219],{"type":37,"value":220},"Пересечение сессий может вызвать столкновение",{"type":32,"tag":143,"props":222,"children":223},{},[224,235,240],{"type":32,"tag":170,"props":225,"children":226},{},[227,233],{"type":32,"tag":62,"props":228,"children":230},{"className":229},[],[231],{"type":37,"value":232},"_ga",{"type":37,"value":234}," client ID + event timestamp",{"type":32,"tag":170,"props":236,"children":237},{},[238],{"type":37,"value":239},"Основан на first-party ID",{"type":32,"tag":170,"props":241,"children":242},{},[243],{"type":37,"value":244},"Риск clock skew (разница в часах клиент\u002Fсервер)",{"type":32,"tag":33,"props":246,"children":247},{},[248,250,256,258,263,265,271,273,279],{"type":37,"value":249},"Production setup Roibase: ",{"type":32,"tag":62,"props":251,"children":253},{"className":252},[],[254],{"type":37,"value":255},"SHA-256(_ga + event_name + unix_ms)",{"type":37,"value":257}," — при push в DataLayer на браузере заполняем ",{"type":32,"tag":62,"props":259,"children":261},{"className":260},[],[262],{"type":37,"value":118},{"type":37,"value":264}," этим хешем, server-side GA4 tag читает тот же field и отправляет его в Measurement Protocol. Для Meta CAPI дополнительно inject'им ",{"type":32,"tag":62,"props":266,"children":268},{"className":267},[],[269],{"type":37,"value":270},"event_source_url",{"type":37,"value":272}," и ",{"type":32,"tag":62,"props":274,"children":276},{"className":275},[],[277],{"type":37,"value":278},"action_source=website",{"type":37,"value":280}," параметры на сервере, потому что client-side Facebook Pixel эти field'ы не отправляет, а сервер-side валидация требует.",{"type":32,"tag":282,"props":283,"children":287},"pre",{"className":284,"code":285,"language":286,"meta":16,"style":16},"language-javascript shiki shiki-themes github-dark","\u002F\u002F Пример DataLayer push (client-side)\nwindow.dataLayer.push({\n  event: 'purchase',\n  event_id: sha256(_ga + 'purchase' + Date.now()),\n  transaction_id: 'ORD-12345',\n  value: 299.00,\n  currency: 'TRY'\n});\n","javascript",[288],{"type":32,"tag":62,"props":289,"children":290},{"__ignoreMap":16},[291,303,324,344,394,412,431,445],{"type":32,"tag":292,"props":293,"children":296},"span",{"class":294,"line":295},"line",1,[297],{"type":32,"tag":292,"props":298,"children":300},{"style":299},"--shiki-default:#6A737D",[301],{"type":37,"value":302},"\u002F\u002F Пример DataLayer push (client-side)\n",{"type":32,"tag":292,"props":304,"children":306},{"class":294,"line":305},2,[307,313,319],{"type":32,"tag":292,"props":308,"children":310},{"style":309},"--shiki-default:#E1E4E8",[311],{"type":37,"value":312},"window.dataLayer.",{"type":32,"tag":292,"props":314,"children":316},{"style":315},"--shiki-default:#B392F0",[317],{"type":37,"value":318},"push",{"type":32,"tag":292,"props":320,"children":321},{"style":309},[322],{"type":37,"value":323},"({\n",{"type":32,"tag":292,"props":325,"children":327},{"class":294,"line":326},3,[328,333,339],{"type":32,"tag":292,"props":329,"children":330},{"style":309},[331],{"type":37,"value":332},"  event: ",{"type":32,"tag":292,"props":334,"children":336},{"style":335},"--shiki-default:#9ECBFF",[337],{"type":37,"value":338},"'purchase'",{"type":32,"tag":292,"props":340,"children":341},{"style":309},[342],{"type":37,"value":343},",\n",{"type":32,"tag":292,"props":345,"children":347},{"class":294,"line":346},4,[348,353,358,363,369,374,379,384,389],{"type":32,"tag":292,"props":349,"children":350},{"style":309},[351],{"type":37,"value":352},"  event_id: ",{"type":32,"tag":292,"props":354,"children":355},{"style":315},[356],{"type":37,"value":357},"sha256",{"type":32,"tag":292,"props":359,"children":360},{"style":309},[361],{"type":37,"value":362},"(_ga ",{"type":32,"tag":292,"props":364,"children":366},{"style":365},"--shiki-default:#F97583",[367],{"type":37,"value":368},"+",{"type":32,"tag":292,"props":370,"children":371},{"style":335},[372],{"type":37,"value":373}," 'purchase'",{"type":32,"tag":292,"props":375,"children":376},{"style":365},[377],{"type":37,"value":378}," +",{"type":32,"tag":292,"props":380,"children":381},{"style":309},[382],{"type":37,"value":383}," Date.",{"type":32,"tag":292,"props":385,"children":386},{"style":315},[387],{"type":37,"value":388},"now",{"type":32,"tag":292,"props":390,"children":391},{"style":309},[392],{"type":37,"value":393},"()),\n",{"type":32,"tag":292,"props":395,"children":397},{"class":294,"line":396},5,[398,403,408],{"type":32,"tag":292,"props":399,"children":400},{"style":309},[401],{"type":37,"value":402},"  transaction_id: ",{"type":32,"tag":292,"props":404,"children":405},{"style":335},[406],{"type":37,"value":407},"'ORD-12345'",{"type":32,"tag":292,"props":409,"children":410},{"style":309},[411],{"type":37,"value":343},{"type":32,"tag":292,"props":413,"children":415},{"class":294,"line":414},6,[416,421,427],{"type":32,"tag":292,"props":417,"children":418},{"style":309},[419],{"type":37,"value":420},"  value: ",{"type":32,"tag":292,"props":422,"children":424},{"style":423},"--shiki-default:#79B8FF",[425],{"type":37,"value":426},"299.00",{"type":32,"tag":292,"props":428,"children":429},{"style":309},[430],{"type":37,"value":343},{"type":32,"tag":292,"props":432,"children":434},{"class":294,"line":433},7,[435,440],{"type":32,"tag":292,"props":436,"children":437},{"style":309},[438],{"type":37,"value":439},"  currency: ",{"type":32,"tag":292,"props":441,"children":442},{"style":335},[443],{"type":37,"value":444},"'TRY'\n",{"type":32,"tag":292,"props":446,"children":448},{"class":294,"line":447},8,[449],{"type":32,"tag":292,"props":450,"children":451},{"style":309},[452],{"type":37,"value":453},"});\n",{"type":32,"tag":33,"props":455,"children":456},{},[457,459,465,467,473,475,480,482,488,490,496,498,503,505,510,511,517],{"type":37,"value":458},"В server-side контейнере создаешь custom variable, который маппирует ",{"type":32,"tag":62,"props":460,"children":462},{"className":461},[],[463],{"type":37,"value":464},"{{Event ID}}",{"type":37,"value":466}," в GA4 и CAPI tag'и. GA4 Measurement Protocol поддерживает ",{"type":32,"tag":62,"props":468,"children":470},{"className":469},[],[471],{"type":37,"value":472},"&ep.event_id=",{"type":37,"value":474}," параметр, Meta CAPI имеет root-level ",{"type":32,"tag":62,"props":476,"children":478},{"className":477},[],[479],{"type":37,"value":118},{"type":37,"value":481}," field. Для Google Ads Conversion комбинация ",{"type":32,"tag":62,"props":483,"children":485},{"className":484},[],[486],{"type":37,"value":487},"gclid",{"type":37,"value":489}," + ",{"type":32,"tag":62,"props":491,"children":493},{"className":492},[],[494],{"type":37,"value":495},"conversion_action_id",{"type":37,"value":497}," обеспечивает дедупликацию — ",{"type":32,"tag":62,"props":499,"children":501},{"className":500},[],[502],{"type":37,"value":487},{"type":37,"value":504}," читается из cookie и POST'ится на сервер, server-side Ads tag объединяет ",{"type":32,"tag":62,"props":506,"children":508},{"className":507},[],[509],{"type":37,"value":487},{"type":37,"value":489},{"type":32,"tag":62,"props":512,"children":514},{"className":513},[],[515],{"type":37,"value":516},"conversion_value",{"type":37,"value":518}," и отправляет в Conversion Tracking API.",{"type":32,"tag":40,"props":520,"children":522},{"id":521},"container-template-и-custom-client-setup",[523],{"type":37,"value":524},"Container Template и Custom Client Setup",{"type":32,"tag":33,"props":526,"children":527},{},[528,530,536,538,543,545,550,552,558,560,566,567,573],{"type":37,"value":529},"sGTM контейнер состоит из 3 основных компонентов: ",{"type":32,"tag":531,"props":532,"children":533},"strong",{},[534],{"type":37,"value":535},"Client",{"type":37,"value":537}," (парсит входящий HTTP request, преобразует в event object), ",{"type":32,"tag":531,"props":539,"children":540},{},[541],{"type":37,"value":542},"Tag",{"type":37,"value":544}," (отправляет event во внешний API), ",{"type":32,"tag":531,"props":546,"children":547},{},[548],{"type":37,"value":549},"Variable",{"type":37,"value":551}," (обмен данными между tag'ами). Default \"GA4\" client Google'а недостаточен — он слушает только ",{"type":32,"tag":62,"props":553,"children":555},{"className":554},[],[556],{"type":37,"value":557},"\u002Fg\u002Fcollect",{"type":37,"value":559}," endpoint. Мы пишем custom client, который handle'ит и GA4, и кастомные endpoint'ы (",{"type":32,"tag":62,"props":561,"children":563},{"className":562},[],[564],{"type":37,"value":565},"\u002Fevent",{"type":37,"value":77},{"type":32,"tag":62,"props":568,"children":570},{"className":569},[],[571],{"type":37,"value":572},"\u002Fpurchase",{"type":37,"value":574},") в одном контейнере.",{"type":32,"tag":33,"props":576,"children":577},{},[578],{"type":37,"value":579},"Пример custom client template:",{"type":32,"tag":282,"props":581,"children":583},{"className":284,"code":582,"language":286,"meta":16,"style":16},"const claimRequest = require('claimRequest');\nconst getRequestBody = require('getRequestBody');\nconst JSON = require('JSON');\nconst logToConsole = require('logToConsole');\n\nclaimRequest();\n\nconst body = getRequestBody();\nconst eventData = JSON.parse(body);\n\n\u002F\u002F Нормализуем event object\nconst normalizedEvent = {\n  event_name: eventData.event || 'unknown',\n  user_data: {\n    client_id: eventData.client_id,\n    user_agent: eventData.user_agent,\n    ip_override: eventData.ip_address\n  },\n  event_id: eventData.event_id,\n  timestamp_micros: eventData.timestamp * 1000000\n};\n\nlogToConsole('Normalized event:', normalizedEvent);\nrunContainer(normalizedEvent, () => {\n  returnResponse();\n});\n",[584],{"type":32,"tag":62,"props":585,"children":586},{"__ignoreMap":16},[587,625,658,691,724,733,746,753,777,812,820,829,851,874,883,892,901,910,919,928,947,956,964,987,1010,1023],{"type":32,"tag":292,"props":588,"children":589},{"class":294,"line":295},[590,595,600,605,610,615,620],{"type":32,"tag":292,"props":591,"children":592},{"style":365},[593],{"type":37,"value":594},"const",{"type":32,"tag":292,"props":596,"children":597},{"style":423},[598],{"type":37,"value":599}," claimRequest",{"type":32,"tag":292,"props":601,"children":602},{"style":365},[603],{"type":37,"value":604}," =",{"type":32,"tag":292,"props":606,"children":607},{"style":315},[608],{"type":37,"value":609}," require",{"type":32,"tag":292,"props":611,"children":612},{"style":309},[613],{"type":37,"value":614},"(",{"type":32,"tag":292,"props":616,"children":617},{"style":335},[618],{"type":37,"value":619},"'claimRequest'",{"type":32,"tag":292,"props":621,"children":622},{"style":309},[623],{"type":37,"value":624},");\n",{"type":32,"tag":292,"props":626,"children":627},{"class":294,"line":305},[628,632,637,641,645,649,654],{"type":32,"tag":292,"props":629,"children":630},{"style":365},[631],{"type":37,"value":594},{"type":32,"tag":292,"props":633,"children":634},{"style":423},[635],{"type":37,"value":636}," getRequestBody",{"type":32,"tag":292,"props":638,"children":639},{"style":365},[640],{"type":37,"value":604},{"type":32,"tag":292,"props":642,"children":643},{"style":315},[644],{"type":37,"value":609},{"type":32,"tag":292,"props":646,"children":647},{"style":309},[648],{"type":37,"value":614},{"type":32,"tag":292,"props":650,"children":651},{"style":335},[652],{"type":37,"value":653},"'getRequestBody'",{"type":32,"tag":292,"props":655,"children":656},{"style":309},[657],{"type":37,"value":624},{"type":32,"tag":292,"props":659,"children":660},{"class":294,"line":326},[661,665,670,674,678,682,687],{"type":32,"tag":292,"props":662,"children":663},{"style":365},[664],{"type":37,"value":594},{"type":32,"tag":292,"props":666,"children":667},{"style":423},[668],{"type":37,"value":669}," JSON",{"type":32,"tag":292,"props":671,"children":672},{"style":365},[673],{"type":37,"value":604},{"type":32,"tag":292,"props":675,"children":676},{"style":315},[677],{"type":37,"value":609},{"type":32,"tag":292,"props":679,"children":680},{"style":309},[681],{"type":37,"value":614},{"type":32,"tag":292,"props":683,"children":684},{"style":335},[685],{"type":37,"value":686},"'JSON'",{"type":32,"tag":292,"props":688,"children":689},{"style":309},[690],{"type":37,"value":624},{"type":32,"tag":292,"props":692,"children":693},{"class":294,"line":346},[694,698,703,707,711,715,720],{"type":32,"tag":292,"props":695,"children":696},{"style":365},[697],{"type":37,"value":594},{"type":32,"tag":292,"props":699,"children":700},{"style":423},[701],{"type":37,"value":702}," logToConsole",{"type":32,"tag":292,"props":704,"children":705},{"style":365},[706],{"type":37,"value":604},{"type":32,"tag":292,"props":708,"children":709},{"style":315},[710],{"type":37,"value":609},{"type":32,"tag":292,"props":712,"children":713},{"style":309},[714],{"type":37,"value":614},{"type":32,"tag":292,"props":716,"children":717},{"style":335},[718],{"type":37,"value":719},"'logToConsole'",{"type":32,"tag":292,"props":721,"children":722},{"style":309},[723],{"type":37,"value":624},{"type":32,"tag":292,"props":725,"children":726},{"class":294,"line":396},[727],{"type":32,"tag":292,"props":728,"children":730},{"emptyLinePlaceholder":729},true,[731],{"type":37,"value":732},"\n",{"type":32,"tag":292,"props":734,"children":735},{"class":294,"line":414},[736,741],{"type":32,"tag":292,"props":737,"children":738},{"style":315},[739],{"type":37,"value":740},"claimRequest",{"type":32,"tag":292,"props":742,"children":743},{"style":309},[744],{"type":37,"value":745},"();\n",{"type":32,"tag":292,"props":747,"children":748},{"class":294,"line":433},[749],{"type":32,"tag":292,"props":750,"children":751},{"emptyLinePlaceholder":729},[752],{"type":37,"value":732},{"type":32,"tag":292,"props":754,"children":755},{"class":294,"line":447},[756,760,765,769,773],{"type":32,"tag":292,"props":757,"children":758},{"style":365},[759],{"type":37,"value":594},{"type":32,"tag":292,"props":761,"children":762},{"style":423},[763],{"type":37,"value":764}," body",{"type":32,"tag":292,"props":766,"children":767},{"style":365},[768],{"type":37,"value":604},{"type":32,"tag":292,"props":770,"children":771},{"style":315},[772],{"type":37,"value":636},{"type":32,"tag":292,"props":774,"children":775},{"style":309},[776],{"type":37,"value":745},{"type":32,"tag":292,"props":778,"children":779},{"class":294,"line":26},[780,784,789,793,797,802,807],{"type":32,"tag":292,"props":781,"children":782},{"style":365},[783],{"type":37,"value":594},{"type":32,"tag":292,"props":785,"children":786},{"style":423},[787],{"type":37,"value":788}," eventData",{"type":32,"tag":292,"props":790,"children":791},{"style":365},[792],{"type":37,"value":604},{"type":32,"tag":292,"props":794,"children":795},{"style":423},[796],{"type":37,"value":669},{"type":32,"tag":292,"props":798,"children":799},{"style":309},[800],{"type":37,"value":801},".",{"type":32,"tag":292,"props":803,"children":804},{"style":315},[805],{"type":37,"value":806},"parse",{"type":32,"tag":292,"props":808,"children":809},{"style":309},[810],{"type":37,"value":811},"(body);\n",{"type":32,"tag":292,"props":813,"children":815},{"class":294,"line":814},10,[816],{"type":32,"tag":292,"props":817,"children":818},{"emptyLinePlaceholder":729},[819],{"type":37,"value":732},{"type":32,"tag":292,"props":821,"children":823},{"class":294,"line":822},11,[824],{"type":32,"tag":292,"props":825,"children":826},{"style":299},[827],{"type":37,"value":828},"\u002F\u002F Нормализуем event object\n",{"type":32,"tag":292,"props":830,"children":832},{"class":294,"line":831},12,[833,837,842,846],{"type":32,"tag":292,"props":834,"children":835},{"style":365},[836],{"type":37,"value":594},{"type":32,"tag":292,"props":838,"children":839},{"style":423},[840],{"type":37,"value":841}," normalizedEvent",{"type":32,"tag":292,"props":843,"children":844},{"style":365},[845],{"type":37,"value":604},{"type":32,"tag":292,"props":847,"children":848},{"style":309},[849],{"type":37,"value":850}," {\n",{"type":32,"tag":292,"props":852,"children":854},{"class":294,"line":853},13,[855,860,865,870],{"type":32,"tag":292,"props":856,"children":857},{"style":309},[858],{"type":37,"value":859},"  event_name: eventData.event ",{"type":32,"tag":292,"props":861,"children":862},{"style":365},[863],{"type":37,"value":864},"||",{"type":32,"tag":292,"props":866,"children":867},{"style":335},[868],{"type":37,"value":869}," 'unknown'",{"type":32,"tag":292,"props":871,"children":872},{"style":309},[873],{"type":37,"value":343},{"type":32,"tag":292,"props":875,"children":877},{"class":294,"line":876},14,[878],{"type":32,"tag":292,"props":879,"children":880},{"style":309},[881],{"type":37,"value":882},"  user_data: {\n",{"type":32,"tag":292,"props":884,"children":886},{"class":294,"line":885},15,[887],{"type":32,"tag":292,"props":888,"children":889},{"style":309},[890],{"type":37,"value":891},"    client_id: eventData.client_id,\n",{"type":32,"tag":292,"props":893,"children":895},{"class":294,"line":894},16,[896],{"type":32,"tag":292,"props":897,"children":898},{"style":309},[899],{"type":37,"value":900},"    user_agent: eventData.user_agent,\n",{"type":32,"tag":292,"props":902,"children":904},{"class":294,"line":903},17,[905],{"type":32,"tag":292,"props":906,"children":907},{"style":309},[908],{"type":37,"value":909},"    ip_override: eventData.ip_address\n",{"type":32,"tag":292,"props":911,"children":913},{"class":294,"line":912},18,[914],{"type":32,"tag":292,"props":915,"children":916},{"style":309},[917],{"type":37,"value":918},"  },\n",{"type":32,"tag":292,"props":920,"children":922},{"class":294,"line":921},19,[923],{"type":32,"tag":292,"props":924,"children":925},{"style":309},[926],{"type":37,"value":927},"  event_id: eventData.event_id,\n",{"type":32,"tag":292,"props":929,"children":931},{"class":294,"line":930},20,[932,937,942],{"type":32,"tag":292,"props":933,"children":934},{"style":309},[935],{"type":37,"value":936},"  timestamp_micros: eventData.timestamp ",{"type":32,"tag":292,"props":938,"children":939},{"style":365},[940],{"type":37,"value":941},"*",{"type":32,"tag":292,"props":943,"children":944},{"style":423},[945],{"type":37,"value":946}," 1000000\n",{"type":32,"tag":292,"props":948,"children":950},{"class":294,"line":949},21,[951],{"type":32,"tag":292,"props":952,"children":953},{"style":309},[954],{"type":37,"value":955},"};\n",{"type":32,"tag":292,"props":957,"children":959},{"class":294,"line":958},22,[960],{"type":32,"tag":292,"props":961,"children":962},{"emptyLinePlaceholder":729},[963],{"type":37,"value":732},{"type":32,"tag":292,"props":965,"children":967},{"class":294,"line":966},23,[968,973,977,982],{"type":32,"tag":292,"props":969,"children":970},{"style":315},[971],{"type":37,"value":972},"logToConsole",{"type":32,"tag":292,"props":974,"children":975},{"style":309},[976],{"type":37,"value":614},{"type":32,"tag":292,"props":978,"children":979},{"style":335},[980],{"type":37,"value":981},"'Normalized event:'",{"type":32,"tag":292,"props":983,"children":984},{"style":309},[985],{"type":37,"value":986},", normalizedEvent);\n",{"type":32,"tag":292,"props":988,"children":990},{"class":294,"line":989},24,[991,996,1001,1006],{"type":32,"tag":292,"props":992,"children":993},{"style":315},[994],{"type":37,"value":995},"runContainer",{"type":32,"tag":292,"props":997,"children":998},{"style":309},[999],{"type":37,"value":1000},"(normalizedEvent, () ",{"type":32,"tag":292,"props":1002,"children":1003},{"style":365},[1004],{"type":37,"value":1005},"=>",{"type":32,"tag":292,"props":1007,"children":1008},{"style":309},[1009],{"type":37,"value":850},{"type":32,"tag":292,"props":1011,"children":1013},{"class":294,"line":1012},25,[1014,1019],{"type":32,"tag":292,"props":1015,"children":1016},{"style":315},[1017],{"type":37,"value":1018},"  returnResponse",{"type":32,"tag":292,"props":1020,"children":1021},{"style":309},[1022],{"type":37,"value":745},{"type":32,"tag":292,"props":1024,"children":1026},{"class":294,"line":1025},26,[1027],{"type":32,"tag":292,"props":1028,"children":1029},{"style":309},[1030],{"type":37,"value":453},{"type":32,"tag":33,"props":1032,"children":1033},{},[1034,1036,1041,1043,1049,1051,1057,1059,1065,1067,1073],{"type":37,"value":1035},"Этот client ловит POST'ы на ",{"type":32,"tag":62,"props":1037,"children":1039},{"className":1038},[],[1040],{"type":37,"value":565},{"type":37,"value":1042},", парсит JSON body и трансформирует в sGTM event model. Вызов ",{"type":32,"tag":62,"props":1044,"children":1046},{"className":1045},[],[1047],{"type":37,"value":1048},"runContainer()",{"type":37,"value":1050}," триггерит tag'и — GA4 tag видит ",{"type":32,"tag":62,"props":1052,"children":1054},{"className":1053},[],[1055],{"type":37,"value":1056},"event_name=purchase",{"type":37,"value":1058}," и отправляет в Measurement Protocol, Meta CAPI tag видит ",{"type":32,"tag":62,"props":1060,"children":1062},{"className":1061},[],[1063],{"type":37,"value":1064},"user_data.email",{"type":37,"value":1066}," и отправляет SHA-256 хеш в ",{"type":32,"tag":62,"props":1068,"children":1070},{"className":1069},[],[1071],{"type":37,"value":1072},"\u002Fevents",{"type":37,"value":1074}," endpoint.",{"type":32,"tag":33,"props":1076,"children":1077},{},[1078,1080,1085,1087,1092,1094,1100,1102,1108],{"type":37,"value":1079},"Production setup работает с 4 client'ами: (1) GA4 default client (",{"type":32,"tag":62,"props":1081,"children":1083},{"className":1082},[],[1084],{"type":37,"value":557},{"type":37,"value":1086},"), (2) custom JSON client (",{"type":32,"tag":62,"props":1088,"children":1090},{"className":1089},[],[1091],{"type":37,"value":565},{"type":37,"value":1093},"), (3) Meta Pixel client (",{"type":32,"tag":62,"props":1095,"children":1097},{"className":1096},[],[1098],{"type":37,"value":1099},"\u002Ftr\u002F",{"type":37,"value":1101}," endpoint — совместимость с Facebook SDK), (4) health check client (",{"type":32,"tag":62,"props":1103,"children":1105},{"className":1104},[],[1106],{"type":37,"value":1107},"\u002Fhealth",{"type":37,"value":1109},") — Cloud Run liveness probe пингует этот endpoint, проверяя здоровье контейнера. Каждый client имеет приоритет (priority number) — если два client'а claim одной path, выигрывает с наивысшим приоритетом.",{"type":32,"tag":33,"props":1111,"children":1112},{},[1113,1115,1121,1123,1129],{"type":37,"value":1114},"Custom template'ы нужно держать под version control. Изменения в UI Google Tag Manager не видны в git history. Наш workflow: сохраняем template'ы как ",{"type":32,"tag":62,"props":1116,"children":1118},{"className":1117},[],[1119],{"type":37,"value":1120},".tpl",{"type":37,"value":1122}," файлы в repo, CI pipeline использует ",{"type":32,"tag":62,"props":1124,"children":1126},{"className":1125},[],[1127],{"type":37,"value":1128},"gtm-template-push",{"type":37,"value":1130}," CLI tool для развертывания в sGTM workspace, тестируем на staging контейнере, затем promote в production. Rollback — один git revert.",{"type":32,"tag":40,"props":1132,"children":1134},{"id":1133},"production-monitoring-какие-метрики-критичны",[1135],{"type":37,"value":1136},"Production Monitoring: какие метрики критичны",{"type":32,"tag":33,"props":1138,"children":1139},{},[1140],{"type":37,"value":1141},"После развертывания server-side GTM мониторинг на 4 уровнях обязателен: (1) container health (uptime, latency, error rate), (2) event throughput (event\u002Fsec, tag success rate), (3) deduplication accuracy (delta между клиент и сервер event count), (4) downstream platform validation (Meta Event Quality Score, Google Ads conversion tracking status).",{"type":32,"tag":33,"props":1143,"children":1144},{},[1145],{"type":37,"value":1146},"Cloud Run native метрики:",{"type":32,"tag":1148,"props":1149,"children":1150},"ul",{},[1151,1169,1179,1189],{"type":32,"tag":1152,"props":1153,"children":1154},"li",{},[1155,1160,1162,1167],{"type":32,"tag":531,"props":1156,"children":1157},{},[1158],{"type":37,"value":1159},"Request count",{"type":37,"value":1161}," — количество POST на ",{"type":32,"tag":62,"props":1163,"children":1165},{"className":1164},[],[1166],{"type":37,"value":565},{"type":37,"value":1168},", breakdown по минутам",{"type":32,"tag":1152,"props":1170,"children":1171},{},[1172,1177],{"type":32,"tag":531,"props":1173,"children":1174},{},[1175],{"type":37,"value":1176},"Request latency (p50, p95, p99)",{"type":37,"value":1178}," — если median > 120ms, проблема (норма 40-80ms)",{"type":32,"tag":1152,"props":1180,"children":1181},{},[1182,1187],{"type":32,"tag":531,"props":1183,"children":1184},{},[1185],{"type":37,"value":1186},"Container instance count",{"type":37,"value":1188}," — если min=1, всегда должно быть 1, spike'ы trigg'ат auto-scale",{"type":32,"tag":1152,"props":1190,"children":1191},{},[1192,1197],{"type":32,"tag":531,"props":1193,"children":1194},{},[1195],{"type":37,"value":1196},"Error rate (5xx)",{"type":37,"value":1198}," — >0.1% постоянно = проблема в downstream tag'ах",{"type":32,"tag":33,"props":1200,"children":1201},{},[1202,1204,1210,1212,1218],{"type":37,"value":1203},"sGTM Console имеет \"Logs\" вкладку с event-level debug log, но production ",{"type":32,"tag":62,"props":1205,"children":1207},{"className":1206},[],[1208],{"type":37,"value":1209},"console.log",{"type":37,"value":1211}," каждого event создает I\u002FO overhead. Наш setup: debug logging только при ",{"type":32,"tag":62,"props":1213,"children":1215},{"className":1214},[],[1216],{"type":37,"value":1217},"?gtm_debug=1",{"type":37,"value":1219}," query param, production трафик отключен. Критические ошибки (tag HTTP 4xx\u002F5xx) идут в Google Cloud Logging как structured JSON log, оттуда Cloud Monitoring alert policy trigger'ит — если за 3 минуты 10+ \"Invalid access token\" ошибок из Meta CAPI, Slack notif отправляется.",{"type":32,"tag":33,"props":1221,"children":1222},{},[1223,1225,1231],{"type":37,"value":1224},"Для event throughput monitoring создаешь custom metric: внутри sGTM tag'а call ",{"type":32,"tag":62,"props":1226,"children":1228},{"className":1227},[],[1229],{"type":37,"value":1230},"sendHttpGet('https:\u002F\u002Fmetrics.roibase.com.tr\u002Fincrement?metric=capi_event')",{"type":37,"value":1232},", метрик-сервис хранит Prometheus counter. В Grafana dashboard видишь real-time event flow — если client-side GA4 отправляет 1000 event\u002Fмин, но server-side CAPI получает только 850, это значит collision в deduplication ID или network drop.",{"type":32,"tag":33,"props":1234,"children":1235},{},[1236,1238,1244,1246,1252],{"type":37,"value":1237},"Downstream platform validation — самое критичное. В Meta Events Manager есть Event Match Quality (EMQ) score — ниже 6.5\u002F10 = \"низкое качество\", хеш-алгоритм неправильный или PII field'ы неполные. Google Ads Conversion Tracking должно быть \"Status: Eligible\" — если видишь \"Rarely used\" или \"Below threshold\", event volume недостаточен (минимум 15 conversion\u002F30 дней). В GA4 DebugView фильтруешь по ",{"type":32,"tag":62,"props":1239,"children":1241},{"className":1240},[],[1242],{"type":37,"value":1243},"traffic_type=server_side",{"type":37,"value":1245},", сравниваешь ",{"type":32,"tag":62,"props":1247,"children":1249},{"className":1248},[],[1250],{"type":37,"value":1251},"event_count",{"type":37,"value":1253}," с client-side — разница >20% требует investigation.",{"type":32,"tag":40,"props":1255,"children":1257},{"id":1256},"identity-resolution-и-user-matching-сигналы",[1258],{"type":37,"value":1259},"Identity Resolution и User Matching сигналы",{"type":32,"tag":33,"props":1261,"children":1262},{},[1263,1265,1271,1273,1279,1281,1287,1289,1295,1297,1303,1305,1311,1313,1319,1321,1327,1328,1334,1336,1341,1343,1349,1351,1357,1358,1364],{"type":37,"value":1264},"Мощь server-side ölçüm — контролируемая отправка PII (Personally Identifiable Information) платформам. Meta CAPI принимает 7 user matching параметров: ",{"type":32,"tag":62,"props":1266,"children":1268},{"className":1267},[],[1269],{"type":37,"value":1270},"em",{"type":37,"value":1272}," (email hash), ",{"type":32,"tag":62,"props":1274,"children":1276},{"className":1275},[],[1277],{"type":37,"value":1278},"ph",{"type":37,"value":1280}," (phone hash), ",{"type":32,"tag":62,"props":1282,"children":1284},{"className":1283},[],[1285],{"type":37,"value":1286},"fn",{"type":37,"value":1288}," (first name), ",{"type":32,"tag":62,"props":1290,"children":1292},{"className":1291},[],[1293],{"type":37,"value":1294},"ln",{"type":37,"value":1296}," (last name), ",{"type":32,"tag":62,"props":1298,"children":1300},{"className":1299},[],[1301],{"type":37,"value":1302},"ct",{"type":37,"value":1304}," (city), ",{"type":32,"tag":62,"props":1306,"children":1308},{"className":1307},[],[1309],{"type":37,"value":1310},"st",{"type":37,"value":1312}," (state), ",{"type":32,"tag":62,"props":1314,"children":1316},{"className":1315},[],[1317],{"type":37,"value":1318},"zp",{"type":37,"value":1320}," (zip), ",{"type":32,"tag":62,"props":1322,"children":1324},{"className":1323},[],[1325],{"type":37,"value":1326},"country",{"type":37,"value":77},{"type":32,"tag":62,"props":1329,"children":1331},{"className":1330},[],[1332],{"type":37,"value":1333},"external_id",{"type":37,"value":1335}," (CRM ID). Чем больше сигналов, тем выше EMQ — один ",{"type":32,"tag":62,"props":1337,"children":1339},{"className":1338},[],[1340],{"type":37,"value":1270},{"type":37,"value":1342}," дает 4.2\u002F10, ",{"type":32,"tag":62,"props":1344,"children":1346},{"className":1345},[],[1347],{"type":37,"value":1348},"em + ph + fn + ln",{"type":37,"value":1350}," дает 7.8\u002F10. Google Enhanced Conversions работает аналогично: добавляешь ",{"type":32,"tag":62,"props":1352,"children":1354},{"className":1353},[],[1355],{"type":37,"value":1356},"sha256_email_address",{"type":37,"value":272},{"type":32,"tag":62,"props":1359,"children":1361},{"className":1360},[],[1362],{"type":37,"value":1363},"sha256_phone_number",{"type":37,"value":1365}," в Ads Conversion tag — attribution accuracy растет на 40% (по бета-тесту Google 2025).",{"type":32,"tag":33,"props":1367,"children":1368},{},[1369,1371,1377,1379,1385],{"type":37,"value":1370},"Production identity resolution pipeline Roibase: (1) пользователь вводит email\u002Fтелефон в веб-форму, (2) client-side JS хеширует SHA-256 (plain text не держится в браузере), (3) хешированное значение push'ится в DataLayer, (4) sGTM берет хеш и отправляет Meta CAPI как ",{"type":32,"tag":62,"props":1372,"children":1374},{"className":1373},[],[1375],{"type":37,"value":1376},"user_data.em",{"type":37,"value":1378}," field, Google как ",{"type":32,"tag":62,"props":1380,"children":1382},{"className":1381},[],[1383],{"type":37,"value":1384},"user_data.sha256_email_address",{"type":37,"value":1386},". Этот flow GDPR-compliant — plain PII никогда не падает в server log'и, SHA-256 — one-way hash, обратно не возвращается.",{"type":32,"tag":33,"props":1388,"children":1389},{},[1390,1392,1398,1400,1406,1408,1413,1415,1420,1422,1428,1430,1435],{"type":37,"value":1391},"Дополнительный сигнал: ",{"type":32,"tag":62,"props":1393,"children":1395},{"className":1394},[],[1396],{"type":37,"value":1397},"fbp",{"type":37,"value":1399}," (Facebook Browser ID) и ",{"type":32,"tag":62,"props":1401,"children":1403},{"className":1402},[],[1404],{"type":37,"value":1405},"fbc",{"type":37,"value":1407}," (Facebook Click ID) cookie'и читаешь на стороне сервера и отправляешь в CAPI. ",{"type":32,"tag":62,"props":1409,"children":1411},{"className":1410},[],[1412],{"type":37,"value":1397},{"type":37,"value":1414}," cookie set'ит client-side Pixel, но ITP expire'ит за 7 дней; мы переписываем с server-side с 90-дневным TTL (first-party domain bypass'ит ITP). ",{"type":32,"tag":62,"props":1416,"children":1418},{"className":1417},[],[1419],{"type":37,"value":1405},{"type":37,"value":1421}," cookie несет ",{"type":32,"tag":62,"props":1423,"children":1425},{"className":1424},[],[1426],{"type":37,"value":1427},"fbclid",{"type":37,"value":1429}," query param из Facebook ad — server-side парсим этот ID и добавляем в CAPI ",{"type":32,"tag":62,"props":1431,"children":1433},{"className":1432},[],[1434],{"type":37,"value":1405},{"type":37,"value":1436}," field, что расширяет Meta attribution с 24 часов на 28 дней.",{"type":32,"tag":33,"props":1438,"children":1439},{},[1440,1442,1447,1449,1454,1456,1462,1464,1469,1471,1476,1477,1482,1484,1489,1491,1496,1498,1503,1505,1511],{"type":37,"value":1441},"Google ",{"type":32,"tag":62,"props":1443,"children":1445},{"className":1444},[],[1446],{"type":37,"value":487},{"type":37,"value":1448}," (Google Click ID) механизм аналогичен. Client-side GTM читает ",{"type":32,"tag":62,"props":1450,"children":1452},{"className":1451},[],[1453],{"type":37,"value":487},{"type":37,"value":1455}," из URL и записывает в ",{"type":32,"tag":62,"props":1457,"children":1459},{"className":1458},[],[1460],{"type":37,"value":1461},"_gcl_aw",{"type":37,"value":1463}," cookie (90 дней TTL). Server-side читаешь этот cookie и добавляешь ",{"type":32,"tag":62,"props":1465,"children":1467},{"className":1466},[],[1468],{"type":37,"value":487},{"type":37,"value":1470}," параметр в Ads Conversion tag. Server-side Conversion Tracking API Google'а использует ",{"type":32,"tag":62,"props":1472,"children":1474},{"className":1473},[],[1475],{"type":37,"value":487},{"type":37,"value":489},{"type":32,"tag":62,"props":1478,"children":1480},{"className":1479},[],[1481],{"type":37,"value":495},{"type":37,"value":1483}," как unique key — если отправишь 2 conversion с одним ",{"type":32,"tag":62,"props":1485,"children":1487},{"className":1486},[],[1488],{"type":37,"value":487},{"type":37,"value":1490},", платформа дедуплицирует. Наш setup: если ",{"type":32,"tag":62,"props":1492,"children":1494},{"className":1493},[],[1495],{"type":37,"value":487},{"type":37,"value":1497}," cookie отсутствует (direct traffic), fallback на ",{"type":32,"tag":62,"props":1499,"children":1501},{"className":1500},[],[1502],{"type":37,"value":232},{"type":37,"value":1504}," client ID, который маппируем в ",{"type":32,"tag":62,"props":1506,"children":1508},{"className":1507},[],[1509],{"type":37,"value":1510},"gbraid",{"type":37,"value":1512}," параметр — это связывает Google Analytics attribution с Ads.",{"type":32,"tag":40,"props":1514,"children":1516},{"id":1515},"compliance-и-consent-orchestration",[1517],{"type":37,"value":1518},"Compliance и Consent Orchestration",{"type":32,"tag":33,"props":1520,"children":1521},{},[1522,1524,1530],{"type":37,"value":1523},"Server-side tagging без интеграции Consent Mode v2 = GDPR risk. Правило Google: при ",{"type":32,"tag":62,"props":1525,"children":1527},{"className":1526},[],[1528],{"type":37,"value":1529},"ad_storage=denied",{"type":37,"value":1531}," consent state sGTM не должен триггерить Google Ads Conversion tag или отправлять только anonymized сигналы (IP masking + drop user ID). Meta Limited Data Use (LDU",{"type":32,"tag":1533,"props":1534,"children":1535},"style",{},[1536],{"type":37,"value":1537},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":16,"searchDepth":326,"depth":326,"links":1539},[1540,1541,1542,1543,1544,1545],{"id":42,"depth":305,"text":45},{"id":104,"depth":305,"text":107},{"id":521,"depth":305,"text":524},{"id":1133,"depth":305,"text":1136},{"id":1256,"depth":305,"text":1259},{"id":1515,"depth":305,"text":1518},"markdown","content:ru:data:server-side-gtm-konversiya-api-production.md","content","ru\u002Fdata\u002Fserver-side-gtm-konversiya-api-production.md","ru\u002Fdata\u002Fserver-side-gtm-konversiya-api-production","md",1778306636708]