14 czerwca 2026
Wzbogacanie AddToCart danymi PII w Shopify — Event Match Quality bez logowania
Najmocniejszym sygnałem Event Match Quality w Meta CAPI są dane identyfikujące — e-mail, imię, nazwisko. Kłopot w tym, że na wczesnych etapach lejka po prostu ich nie ma: klient dodaje produkt do koszyka zanim się zaloguje, więc AddToCart leci do Mety bez żadnego PII i z marnym dopasowaniem.
Rozwiązaniem jest wzbogacanie eventów danymi PII z profilu zapisanego wcześniej. Jeśli klient kiedyś kupił i podał dane, jego profil leży w Stape Store pod trwałym identyfikatorem. Na każdym kolejnym zdarzeniu — także bez logowania — można odtworzyć ten profil i dokleić e-mail oraz nazwisko, zanim event poleci do Mety. To wariant dla Shopify: mostem tożsamości jest pierwszorzędne cookie _shopify_y.
Po co to robić: wzbogacanie eventów danymi PII dla powracających
Ważne zastrzeżenie na start, żeby dobrze ustawić oczekiwania: ta technika działa dla użytkowników powracających, którzy już kiedyś kupili i mają zapisany profil. Pierwszy AddToCart zupełnie nowego użytkownika nie ma czego wzbogacić — w magazynie nie ma jeszcze jego danych. To cecha, nie błąd. Zysk pojawia się przy kolejnych wizytach: gdy ten sam człowiek wraca anonimowo, jego wczesne zdarzenia zaczynają nieść PII, choć on sam się nie zalogował.
Dlaczego cookie Shopify, a nie stape_user_id czy user_id
W pierwszym use case kluczem był stape_user_id (per urządzenie), w drugim — user_id zalogowanego klienta. Tutaj problem jest inny: chcę wzbogacać event niezalogowanego użytkownika, więc user_id odpada (jeszcze go nie ma). Wybór padł na _shopify_y:
| Identyfikator | Kiedy dostępny | Ograniczenie |
|---|---|---|
stape_user_id | każde żądanie online | per żądanie / urządzenie |
user_id | dopiero po zalogowaniu | nie pokrywa fazy anonimowej |
_shopify_y | każde żądanie, też bez logowania | per przeglądarka (1st-party cookie) |
_shopify_y to trwałe (~roczne) pierwszorzędne cookie, które Shopify ustawia każdemu odwiedzającemu. Jest na każdym żądaniu z tej samej przeglądarki, przeżywa wylogowanie i przerwy między wizytami. To czyni ten wariant najprostszym z trzech — nie potrzeba ani resolucji wielu identyfikatorów (jak w UC2), ani identyfikatora w webhooku. Pod dwoma warunkami: cookie dociera na serwer na obu zdarzeniach, a klucz zapisu i odczytu jest ten sam.
Architektura — dwie fazy, jeden klucz
Mechanizm działa w dwóch momentach: przy zakupie zapisuję profil, a przy AddToCart odtwarzam go i wzbogacam zdarzenie.
tag klienta → serwer
Save PII
user_data pod _shopify_y
tag klienta → serwer
po _shopify_y
enriched_data
z e-mailem/nazwiskiem
_shopify_y — ta sama wartość przy zapisie i przy odczycie, bo to trwałe cookie tej samej przeglądarki.| # | Element | Strona | Rola |
|---|---|---|---|
| 1 | cookie _shopify_y | klient | trwały identyfikator z Shopify |
| 2 | tag purchase (X: Data Tag / Y: GA4) | klient | wysyła shopify + user_data na serwer |
| 2b | tag add_to_cart (X: Data Tag / Y: GA4) | klient | wysyła shopify na serwer — klucz do Lookup |
| 3 | zmienne Event Data shopify, user_data | serwer | wyciąga identyfikator i profil ze zdarzenia |
| 4 | Stape Store Writer | serwer | zapisuje user_data pod kluczem _shopify_y |
| 5 | Stape Store Lookup | serwer | odczytuje user_data po _shopify_y |
| 6 | Transformacja enriched_data | serwer | dokleja profil do zdarzenia |
| 7 | zmienne Event Data enriched_data.* | serwer | wyciąga pojedyncze pola PII |
| 8 | Meta — AddToCart | serwer | wysyła wzbogacone zdarzenie do CAPI |
Dwa warianty transportu danych na serwer
Dane z przeglądarki na serwer możesz przesłać na dwa sposoby. Strona serwerowa (Writer, Lookup, transformacja, Meta) jest wspólna — różnica jest tylko w tym, jak tagi klienckie dostarczają dane.
| Wariant X — Data Tag | Wariant Y — tag GA4 | |
|---|---|---|
| Transport | Osobny request (Stape Data Tag) | Istniejący hit GA4 |
| Klient sGTM | Data Client | Klient GA4 |
| Trigger Writera | dc - purchase | ga4 - client_name + purchase |
user_data | Sam definiujesz schemat i pola | Surowy schemat GA4 (niehashowany): email, phone_number, address.0.first_name/last_name |
Parametr shopify | Pole w Event Data tagu | Parametr zdarzenia w tagu GA4 |
| Kiedy wybrać | Pełna kontrola schematu, wartości surowe spoza GA4 | Domyślnie — jeden request mniej, natywny klient GA4, wbudowana obsługa zgody |
Wariant Y jest rekomendowany dla tego use case: reużywa istniejący hit GA4, nie generuje osobnego requestu do serwera i korzysta z natywnego klienta GA4 z wbudowaną obsługą Consent Mode. Wariant X wybierasz, gdy potrzebujesz pełnej kontroli nad schematem danych lub wartości spoza ekosystemu GA4.
Poniższa konfiguracja krok po kroku opisuje oba warianty tam, gdzie się różnią.
Konfiguracja krok po kroku
Strona klienta (kontener web)
Krok 1 — CDP 1. cookie - shopify
Zmienna „Własny plik cookie” (First-Party Cookie), Nazwa pliku cookie: _shopify_y. To Shopify tworzy to cookie; ja je tylko czytam i przekazuję dalej jako parametr o nazwie shopify.
Krok 2 — tag purchase (tu jest różnica X / Y)
Wariant X — Data Tag na purchase: tag Data Tag (Stape), event Purchase, GTM Server Side URL. W Event Data przekaż parametry ecommerce oraz pole shopify (= {{CDP 1. cookie - shopify}}) i obiekt user_data.
Wariant Y — tagi GA4 (rekomendowany): dane jadą na istniejących hitach GA4. Dwie rzeczy do ustawienia:
- Na tagu GA4 - purchase dodaj parametr zdarzenia
shopify={{CDP 1. cookie - shopify}}. - PII (
user_data) ustawiasz nie na evencie purchase, lecz na głównym tagu Google (Tag Google — page_view / konfiguracja) w sekcji „Ustawienia konfiguracji”: parametruser_data={{3. Dane przekazywane przez użytkowników}}(wbudowana zmienna User-Provided Data). To ustawienie obejmuje wszystkie zdarzenia GA4 — purchase też niesieuser_data, bez dodatkowej konfiguracji.
Krok 2b — tag add_to_cart — KRYTYCZNY
To najczęściej pomijany krok, a bez niego cały enrichment nie zadziała. Strona serwera pobiera profil użytkownika po kluczu _shopify_y — ale żeby to zrobić, musi znać wartość cookie na zdarzeniu add_to_cart. Cookie nie trafia do event data samo z siebie; musi je explicite przesłać tag kliencki.
- Wariant X: osobny Data Tag na event
add_to_cartz polemshopify={{CDP 1. cookie - shopify}}. - Wariant Y: tag GA4, event
add_to_cart, parametr zdarzeniashopify={{CDP 1. cookie - shopify}}.user_datatu niepotrzebne — PII i tak pochodzi z magazynu, nie z bieżącego eventu.
Brak tego taga → add_to_cart dociera na serwer bez shopify → Lookup nie ma klucza → enrichment nie zachodzi. Tag Meta odpali się na zielono, ale bez PII. Cicha awaria.
Strona serwera — zapis profilu (przy zakupie)
Krok 3 — CDP 3. shopify i CDP 3. user_data
Dwie zmienne typu „Dane zdarzenia” (Event Data):
CDP 3. (Use case 3) shopify→ Ścieżka klucza:shopify(wartość cookie = klucz dokumentu w Store).CDP 3. (Use case 3) user_data→ Ścieżka klucza:user_data(cały obiekt PII z eventu).
W wariancie Y dane user_data są surowe (niehashowane) — GA4 hashuje je dopiero przy wysyłce do Google, nie w event data. Struktura: email, phone_number, address.0.first_name, address.0.last_name.
Krok 4 — CDP 4. Stape Store Writer - Save PII
Tag Stape Store Writer:
- Document ID:
{{CDP 3. (Use case 3) shopify}}— klucz = wartość cookie. - Custom Data: pole
user_data={{CDP 3. (Use case 3) user_data}}. - Trigger: wariant X:
dc - purchase; wariant Y:ga4 - client_name + purchase.
Strona serwera — odczyt i wzbogacenie (przy AddToCart)
Krok 5 — CDP 5. Stape Store Lookup - user_data
Zmienna Stape Store Lookup: Lookup Type Document ID = {{CDP 3. (Use case 3) shopify}}, Key Path user_data. Ten sam klucz co w Writerze — to warunek powodzenia. Zwraca zapisany obiekt user_data dla bieżącej przeglądarki.
Krok 6 — CDP 6. Transformation - user_data
Przekształcenie „Uzupełnij zdarzenie”: parametr enriched_data = {{CDP 5. Stape Store Lookup - user_data}}, zakres „niektóre tagi” → CDP 8. Wkłada cały odczytany obiekt pod klucz enriched_data w event data bieżącego zdarzenia.
Krok 7 — CDP 7. enriched_data.email i CDP 7. enriched_data.address.0.last_name
Zmienne „Dane zdarzenia” czytające pojedyncze pola z obiektu wstawionego przez transformację:
CDP 7. (Use case 3) - enriched_data.email→ Ścieżka klucza:enriched_data.emailCDP 7. (Use case 3) - enriched_data.address.0.last_name→ Ścieżka klucza:enriched_data.address.0.last_name
Czytają z event data, nie odpytują Store — stąd oszczędność (patrz niżej).
Krok 8 — CDP 8. Meta - AddToCart
Tag Facebook Conversion API, event AddToCart (Override, Standard). W sekcji User Data podstaw zmienne z CDP 7 (e-mail, nazwisko…). Event ID do deduplikacji, Test ID do walidacji. Trigger: add_to_cart. Tag FB CAPI sam hashuje pola wymagające hashowania — dane surowe z GA4 zadziałają tu tak samo.
Jeden Lookup, wiele pól — optymalizacja kosztu
Najciekawszy fragment to relacja CDP 5 → 6 → 7, bo każde odpytanie Stape Store kosztuje. Gdybyś dla każdego pola (email, last_name, phone…) robił osobny Lookup z innym Key Path, byłoby to N zapytań na jedno zdarzenie. Zamiast tego:
- Jeden Lookup (CDP 5) pobiera cały obiekt
user_data. - Transformacja (CDP 6) wkłada go pod
enriched_dataw event data. - Pola czytasz zmiennymi Event Data (CDP 7) z
enriched_data.*— lokalnie, bez kolejnych zapytań do Store.
To jest sens rozdzielenia user_data (z magazynu) od enriched_data (w evencie): jeden płatny odczyt z bazy, wiele darmowych odczytów z event data.
Reguła krytyczna: klucz zapisu = klucz odczytu — na obu zdarzeniach
Writer (Document ID) i Lookup (Document ID) muszą używać tego samego _shopify_y. Rozjazd oznacza, że Lookup nic nie znajdzie, a tag i tak odpali się na zielono — bez PII. Cicha awaria.
Haczyk specyficzny dla tego wariantu: _shopify_y musi być w event data zarówno przy zapisie (purchase), jak i przy odczycie (add_to_cart). Cookie samo nie trafia do event data — dostarcza je tag kliencki (Krok 2 i Krok 2b). Jeśli add_to_cart nie niesie shopify, Lookup dostaje pusty klucz i nic nie zwraca.
Najczęstsze błędy
- Brak taga add_to_cart po stronie klienta (najczęstszy, krytyczny). Krok 2b jest łatwy do pominięcia, bo logicznie wydaje się zbędny — „przecież enrichment robimy po stronie serwera”. Ale serwer potrzebuje klucza do Lookup, a ten klucz musi przyjść z klienta jako parametr zdarzenia. Bez niego Lookup nie ma czego szukać.
- Klucz zapisu ≠ klucz odczytu. Writer i Lookup muszą używać tej samej zmiennej
CDP 3. (Use case 3) shopify. Nawet drobna różnica (np. inna nazwa parametru) = pusty Lookup. - Złe ścieżki pól w wariancie Y. Schemat GA4 to
enriched_data.email(nieemail_address),enriched_data.phone_number,enriched_data.address.0.first_name/address.0.last_name— surowo, niehashowane. Key Path ustaw 1:1 z podglądem w debuggerze, inaczej zmienna zwróci pusto. - Tag wstrzymany. Finalny tag Meta musi być aktywny. Wstrzymany („paused”) nie odpali się, mimo poprawnej reszty łańcucha.
user_dataskonfigurowane na evencie purchase zamiast na Tag Google. W wariancie Yuser_dataustawiasz na głównym tagu konfiguracji (Tag Google — page_view), nie na tagupurchase. Tylko wtedy PII jedzie na wszystkich hitach GA4, w tym purchase.
Weryfikacja
- Zapis: w preview na
purchasesprawdź, że Writer tworzy dokument w Store pod kluczem = wartość_shopify_yi zawierauser_data. - Odczyt: na
add_to_cart(tą samą przeglądarką, po wcześniejszym zakupie) potwierdź, że Lookup zwracauser_data, transformacja wkładaenriched_data, a CDP 7 wyciąga pola. - Meta Test Events: sprawdź, że AddToCart dociera z polami User Data.
Prywatność — zanim trafi na produkcję
Zapis user_data (e-mail, imię, nazwisko) do Store i wysyłka PII na AddToCart to utrwalanie i przetwarzanie danych osobowych:
- Zapis (CDP 4) i wysyłkę PII (CDP 8) warunkuj zgodą marketingową (
ad_storage). - Ustaw TTL na dokumentach profilowych.
- Kluczowanie po
_shopify_y, a nie po surowym e-mailu, jest pod tym względem czystsze — w nazwie dokumentu nie leży PII.
To trzeci wariant tego samego wzorca (sGTM + magazyn jako mini-CDP). Poprzednie: wzbogacanie page_view e-mailem i przywracanie fbc/fbp dla zakupu offline. Szerszy kontekst — w case study o server-side taggingu.