Server-Side GTM: wzbogacanie danych CRM z Firestore i BigQuery

Spis treści
Serwerowe wzbogacanie danych dodaje do zdarzenia pomiarowego wybrane atrybuty z backendu, na przykład wcześniej obliczony segment wartości klienta. Wewnętrzne pola CRM mogą dzięki temu pozostać poza przeglądarką. Przeniesienie przetwarzania na serwer nie zapewnia jednak anonimowości ani automatycznej zgody na przekazanie danych platformom reklamowym.
Mniej danych w przeglądarce, wyraźne granice
Numer klienta lub zahaszowany identyfikator pozostaje daną osobową albo pseudonimizowaną, jeżeli możliwe jest powiązanie z osobą. Haszowanie nie jest szyfrowaniem ani ogólnym dowodem anonimowości. Tokeny sesji mogą być szczególnie wrażliwe: tokeny dostępu i ciasteczka uwierzytelniające nie powinny trafiać do zdarzeń analitycznych.
Właściwy projekt oddziela identyfikator pomiarowy od uwierzytelniania. Serwer musi zweryfikować dozwolone powiązanie z kontem klienta. Dowolnie zmienialne pole user_id w publicznym żądaniu przeglądarki nie może wybierać dowolnych rekordów CRM. Sama poprawna składnia identyfikatora nie stanowi uprawnienia.
| Etap | Zadanie |
|---|---|
| Przeglądarka | Wysyłka potrzebnych pól zdarzenia i ewentualnie dozwolonego pseudonimowego identyfikatora pomiarowego. |
| Zweryfikowany backend | Ustalenie tożsamości, uprawnienia do zdarzenia i dozwolonego celu wzbogacania. |
| Baza wzbogacania | Udostępnienie niewielkiego zestawu zatwierdzonych atrybutów z czasem aktualizacji. |
| Tag docelowy | Wysyłka dozwolonych pól w schemacie odbiorcy zgodnie z wymaganymi regułami zgody. |

Odczyt z Firestore, obliczenia w BigQuery
Firestore nadaje się do odczytu dokumentów według klucza. Czas odpowiedzi zależy między innymi od regionu, sieci i obciążenia. Całe żądanie ssGTM nie ma gwarantowanej odpowiedzi poniżej milisekundy ani bez opóźnień. Potrzebny jest pomiar typowych i wysokich opóźnień pod realistycznym obciążeniem.
BigQuery służy do obliczeń analitycznych, na przykład segmentu wartości klienta na podstawie historii zamówień. Osobny, monitorowany proces eksportu zapisuje zatwierdzone wyniki w Firestore. Samo połączenie produktów nie tworzy takiego eksportu. Aktualność obliczeń, błędy eksportu i usuwanie danych wymagają jawnej obsługi. Ścieżka żądania odczytuje przygotowane wartości zamiast wykonywać złożone zapytanie do hurtowni dla każdego zdarzenia.
Celowo ograniczony przykład odczytu
Poniższy kod jest przeznaczony do niestandardowej zmiennej serwerowej i nie stanowi kompletnego szablonu. Wymagane są trzy pola szablonu: projectId jako stała konfiguracja projektu, authorizedCustomerKey ze zweryfikowanego powiązania po stronie serwera oraz lookupAllowed jako wartość logiczna wynikająca ze sprawdzonej kontroli uprawnień i zgody. Bezpośrednie kopiowanie tych wartości z pól przeglądarki nie spełnia warunku.
Oddzielna kolekcja enrichment zawiera wyłącznie zatwierdzone atrybuty. Eksporter zapisuje updated_at_ms jako czas uniksowy w milisekundach, a nie obiekt Timestamp Firestore. Wartości segmentów i limit aktualności wynoszący 24 godziny są przykładami wymagającymi dopasowania do rzeczywistego modelu danych.
const Firestore = require('Firestore');
const getType = require('getType');
const queryPermission = require('queryPermission');
const getTimestampMillis = require('getTimestampMillis');
// Template inputs: trusted server-side mapping, never raw browser fields.
if (data.lookupAllowed !== true) return {status: 'not_allowed'};
const key = data.authorizedCustomerKey;
if (getType(key) !== 'string' || key.length < 16 || key.length > 128) {
return {status: 'invalid_key'};
}
const alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';
for (let i = 0; i < key.length; i++) {
if (alphabet.indexOf(key.charAt(i)) < 0) return {status: 'invalid_key'};
}
if (getType(data.projectId) !== 'string' || data.projectId.length === 0) {
return {status: 'invalid_project'};
}
const path = 'enrichment/' + key;
if (!queryPermission('access_firestore', 'read', {projectId: data.projectId, path: path})) {
return {status: 'permission_denied'};
}
const maxAgeMs = 86400000; // Example freshness policy: 24 hours.
return Firestore.read(path, {
projectId: data.projectId
}).then((result) => {
const record = result.data;
if (getType(record) !== 'object' || record === null) {
return {status: 'invalid_record'};
}
const timestamp = record.updated_at_ms;
const now = getTimestampMillis();
if (getType(timestamp) !== 'number' || !(timestamp > 0) || timestamp > now) {
return {status: 'invalid_timestamp'};
}
if (now - timestamp > maxAgeMs) return {status: 'stale'};
const segment = record.ltv_segment;
if (segment !== 'low' && segment !== 'medium' && segment !== 'high') {
return {status: 'invalid_segment'};
}
return {status: 'ok', attributes: {ltv_segment: segment}};
}, (error) => {
return {status: error && error.reason === 'not_found' ? 'not_found' : 'lookup_error'};
});
Firestore.read zwraca obiekt z polami id i data; pola dokumentu znajdują się pod result.data. Brak dokumentu powoduje odrzucenie z reason: 'not_found'. Kod rozróżnia dane brakujące, przestarzałe, nieprawidłowe i niedostępne z przyczyn technicznych. Nieznana wartość nie staje się marżą zerową ani standardowym klientem.
Tag docelowy może pobrać jawnie przypisane atrybuty tylko przy status === 'ok'. Wewnętrzny obiekt statusu nie jest pakietem do wysyłki. Udany odczyt nie zastępuje również zgody właściwej dla odbiorcy. Każde zdarzenie wymaga ustalonej reguły błędu: wysyłki już dozwolonego zdarzenia podstawowego bez dodatkowych pól albo wstrzymania przekazania.
Uprawnienia i czas wykonania
Wbudowane API Firestore w ssGTM obsługuje zgodnie z dokumentacją tryb Native i wyłącznie bazę (default). Izolacja może wykorzystywać osobny projekt z własną bazą domyślną. Szablon potrzebuje tylko odczytu przez access_firestore dla konkretnego projektu i przewidzianej ścieżki. Ograniczenia szablonu uzupełniają IAM, ale nie zastępują IAM.
Usługa wykonawcza potrzebuje osobnej tożsamości z minimalnymi uprawnieniami odczytu. Eksport używa oddzielnej tożsamości zapisującej. Dostęp serwerowy jest kontrolowany przez IAM; przeglądarkowe Security Rules nie chronią tej ścieżki. Kolekcja z niewielką liczbą pól i granica osobnego projektu ograniczają zakres danych dostępnych po przejęciu usługi.
Odczyt wydłuża przetwarzanie zależnych tagów. Oczekiwanie odpowiedzi przeglądarki zależy od klienta i sposobu zwracania odpowiedzi. Udokumentowane opcje Firestore.read nie obejmują własnego parametru timeout; nieznane opcje są ignorowane. Obietnice w izolowanym JavaScript mają udokumentowany limit pięciu sekund. Limit nie zastępuje świadomie ustalonego krótkiego budżetu odpowiedzi. Ściślejsze terminy mogą wymagać osobnej usługi odczytu albo procesu asynchronicznego.
Kontrola odbiorców i działania
GA4 i Meta CAPI mają różne modele danych oraz wymagania. Hash nie zezwala na dowolne dane osobowe w parametrach zdarzeń. Google udostępnia specjalnie konfigurowane funkcje user-provided data; funkcje te różnią się od zwykłego User-ID i parametrów niestandardowych. Marże i segmenty powinny trafiać wyłącznie do odbiorców rzeczywiście wymagających takich informacji.
Kontrola działania obejmuje udział trafień, brakujące dokumenty, nieaktualne eksporty, błędy techniczne i rozkład opóźnień. Zagregowane liczniki ograniczają zbędne dane CRM w logach. Koszty obejmują odczyty, zapisy eksportu, przechowywanie i ewentualny ruch sieciowy. Pamięć podręczna API obejmuje bieżące żądanie lub wykonanie kontenera, a nie globalny cache klientów.
Pytania i odpowiedzi
Dlaczego nie zastępować braku danych zerem?
Wartość nieznana i rzeczywiste zero mają różne znaczenie. Wartość zastępcza może zniekształcić analizę. Status błędu i pominięcie dodatkowego pola zachowują tę różnicę.
Czy serwer gwarantuje brak wycieków?
Nie. Odpowiedzi do przeglądarki, diagnostyka, logi, eksporty i żądania wyjściowe pozostają możliwymi ścieżkami danych. Konfiguracja oraz rzeczywiście wysyłane pola wymagają kontroli.
Co zostało sprawdzone w przykładzie?
29 izolowanych testów z symulowanymi API obejmuje granice danych wejściowych, blokady odczytu, brakujące i nieaktualne rekordy oraz dozwolony zestaw pól. Testy nie potwierdzają zgodności z piaskownicą GTM, rzeczywistych uprawnień IAM, zachowania pod obciążeniem ani poprawności pakietów dla dostawców.