LW IT Solutions
« Przegląd bloga /Digital Analytics/Tutorials / Tutorial: Z zagnieżdżonego dataLayer zbudować trwałe zmienne...
Ten artykuł w innych językach:

Tutorial: Z zagnieżdżonego dataLayer zbudować trwałe zmienne GTM

Tutorial: Z zagnieżdżonego dataLayer zbudować trwałe zmienne GTM
Spis treści
  1. Jak dociera zagnieżdżony push
  2. Wersja 2 i kropka będąca rozdzielnikiem
  3. Listy i dlaczego indeks jest częścią kruchą
  4. Scalanie, o które nikt nie prosił
  5. Jedna zmienna zamiast dwudziestu
  6. Sprawdzenie w podglądzie
  7. Pytania i odpowiedzi
  8. Źródła

Sklep wypycha dane produktowe jako jeden zagnieżdżony obiekt, bo tak je i tak przechowuje. Menedżer tagów chce wartości płaskich, po jednej na zmienną, a pomostem między nimi jest zapis z kropkami.

Ten zapis sięga wszystkiego. Nie mówi natomiast, która z powstałych ścieżek będzie poprawna także w przyszłym miesiącu – a mniej więcej połowa nie będzie, z powodu niemającego nic wspólnego z menedżerem tagów.

Po lewej zagnieżdżony push dataLayer, po prawej jego płaskie ścieżki kropkowe, każda oznaczona jako stabilna albo zależna od pozycji artykułu w liście
Każda wartość jest osiągalna. Ścieżki biegnące przez indeks listy to te, które stają się błędne, gdy tylko zmieni się kolejność.

Jak dociera zagnieżdżony push

Zwykły push e-commerce niesie trzy poziomy: zdarzenie, obiekt pod nim, a pod nim listę artykułów.

dataLayer.push({
  event: "add_to_cart",
  ecommerce: {
    currency: "EUR",
    value: 129.90,
    items: [
      { item_id: "SKU-42", item_name: "Stuhl", price: 64.95, quantity: 2,
        item_category: "Moebel", index: 0 },
      { item_id: "SKU-77", item_name: "Tisch", price: 219.00, quantity: 1,
        item_category: "Moebel", index: 1 }
    ]
  },
  user: { logged_in: true, segment: "b2b" }
});

Rozpisany na ścieżki obiekt ten zawiera jedną nazwę zdarzenia, trzy wartości pod ecommerce, dwanaście wewnątrz listy artykułów i dwie pod user. Każda z nich jest osiągalna, a adresem jest łańcuch kluczy połączony kropkami.

Wersja 2 i kropka będąca rozdzielnikiem

Zmienna warstwy danych w menedżerze tagów ma ustawienie wersji i to ono wyznacza sposób odczytu nazwy.

Wersja 2:  ecommerce.currency          →  "EUR"
           ecommerce.items.0.item_id   →  "SKU-42"
           user.segment                →  "b2b"

Wersja 1:  ecommerce.currency          →  undefined
           (caly ciag uchodzi za jeden klucz)

Wersja 2 jest domyślna dla nowych zmiennych i niemal zawsze właściwa. Wersja 1 istnieje dla jednego przypadku: klucza faktycznie noszącego kropkę w nazwie. Push z {"page.type": "pdp"} jest osiągalny wyłącznie wersją 1, bo wersja 2 szukałaby type w page, którego nie ma.

Dwa szczegóły kosztujące czas, dopóki są nieznane. Ścieżka rozróżnia wielkość liter w całości, więc Ecommerce.Items nic nie znajduje i nic nie zgłasza. A zmienna bez wartości domyślnej zwraca dla brakującej ścieżki undefined, co w tagu staje się pustym parametrem, a nie błędem – przekręcona ścieżka wygląda więc tak samo jak wartość nigdy niewysłana.

Listy i dlaczego indeks jest częścią kruchą

Krok w listę jest liczbą, a ta liczba to pozycja, a nie tożsamość.

Ścieżka Stabilna? Dlaczego
ecommerce.currency tak Nazwany klucz na stałej głębokości
ecommerce.value tak Tak samo
user.segment tak Tak samo
ecommerce.items.0.item_id nie Pozycja 0 to artykuł, który akurat stoi z przodu
ecommerce.items.1.price nie Brakuje jej całkiem w koszyku z jednym artykułem

Drugi wiersz dolnej połowy wytwarza szkodę cichą. W koszyku z jednym artykułem items.1 nie istnieje, zmienna pozostaje pusta, a tag wysyła parametr bez wartości. Nic nie zawodzi, a raport pokazuje liczbę nieco mniejszą niż sklep.

Ścieżka z indeksem da się obronić w dokładnie jednym położeniu: na stronie zawsze noszącej dokładnie jeden artykuł, na przykład karcie produktu. Wszędzie indziej – koszyk, kasa, zakup – liczba artykułów jest zmienna, a ich kolejność tak samo.

Scalanie, o które nikt nie prosił

Warstwa danych nie jest listą komunikatów. Menedżer tagów prowadzi scalony model wszystkich dotychczasowych pushy, a nowy push zostaje w niego wtopiony, zamiast go zastąpić.

Skutek jest określony i przykry. Strona wypychająca najpierw view_item z jednym artykułem, a potem add_to_cart z innym, zostawia wartości pierwszego artykułu wszędzie tam, gdzie drugi push ich nie nadpisze. Po liście artykułów o długości trzy przychodzi lista o długości jeden, a wychodzi scalona lista o długości trzy, z dwoma wpisami z poprzedniego zdarzenia.

dataLayer.push({ ecommerce: null });   // sprzata galaz
dataLayer.push({
  event: "add_to_cart",
  ecommerce: { currency: "EUR", value: 64.95, items: [ /* … */ ] }
});

Push sprzątający należy bez wyjątku przed każdy push e-commerce i jest najczęstszym pominięciem w podłączeniu sklepu. Jego działanie widać w podglądzie: widok komunikatów pokazuje, co zostało wypchnięte, widok modelu pokazuje, co zmienna naprawdę odczyta – a różnica między nimi to dokładnie ten problem.

Jedna zmienna zamiast dwudziestu

Tam, gdzie potrzebna jest cała lista, odpowiedzią nie jest dwadzieścia ścieżek z indeksem. Jest nią własna zmienna JavaScript czytająca listę i zwracająca to, czego potrzebuje tag.

function () {
  var artikel = {{DLV - ecommerce.items}};
  if (!Array.isArray(artikel) || !artikel.length) { return undefined; }

  return artikel.map(function (a) {
    return {
      item_id:       String(a.item_id || a.id || ""),
      item_name:     String(a.item_name || a.name || ""),
      price:         Number(a.price) || 0,
      quantity:      Number(a.quantity) || 1,
      item_category: String(a.item_category || "")
    };
  }).filter(function (a) { return a.item_id !== ""; });
}

Trzy rzeczy daje to ponad odporność na kolejność. Ujednolica nazwy pól, więc sklep wysyłający na jednej stronie id, a na innej item_id, wytwarza dalej jedną postać. Wymusza typy, przez co cena przychodząca jako ciąg "64.95" przestaje być problemem. I odrzuca artykuły bez identyfikatora, które GA4 i tak by odrzuciło – tyle że po cichu.

Zmienna, którą to czyta, jest zwykłą zmienną warstwy danych wskazującą ecommerce.items, bez indeksu. Ta ścieżka jest stabilna, bo nazywa klucz, a nie pozycję.

Sprawdzenie w podglądzie

Dwa widoki podglądu rozstrzygają wszystko omówione powyżej i łatwo je ze sobą pomylić.

Widok komunikatów pokazuje push dokładnie tak, jak wysłała go strona. Widok modelu pokazuje scalony stan, który zmienna odczyta w tej chwili. Wartość stojąca w drugim, a brakująca w pierwszym, to pozostałość po wcześniejszym pushu – problem sprzątania – a wartość w pierwszym, brakująca w drugim, została zwykle nadpisana przez push późniejszy.

Trzeci widok, obszar zmiennych wybranego zdarzenia, pokazuje, co każda skonfigurowana zmienna faktycznie zwróciła. undefined w tym miejscu jest odpowiedzią na niemal każde pytanie o brakujący parametr i rozdziela dwie możliwe przyczyny: ścieżka jest błędna albo wartość nigdy nie została wypchnięta. Zestawienie zmiennej z widokiem modelu rozdziela to w sekundy.

Ostatni nawyk zapobiega najbardziej mozolnej klasie błędów. Ścieżka ze źródła strony to nie ścieżka z warstwy danych – wtyczka sklepu potrafi zmienić nazwy kluczy między szablonem a pushem, a sklep przetłumaczony czasem tłumaczy je razem z resztą. Ścieżkę należy skopiować z widoku modelu prawdziwego zdarzenia, a nie przepisać z dokumentacji.

Pytania i odpowiedzi

Co własna zmienna JavaScript robi z ceną zapisaną z przecinkiem dziesiętnym?

Zero, i to po cichu. Number('64,95') daje NaN, bo JavaScript zna jako separator dziesiętny tylko kropkę, a || 0 za nim zamienia NaN w 0. Pozycja trafia do GA4 z ceną 0, przychodu na poziomie artykułów brakuje, a nigdzie nie pojawia się błąd. To samo dotyczy cen ze znakiem waluty, takich jak '64.95 €', a przy ilości nieczytelna wartość zamienia się w ten sam sposób w 1.

Najczystsze rozwiązanie leży u źródła: jeśli strona wypycha ceny jako liczby, nie ma czego przeliczać. Tam, gdzie to niemożliwe, zmienna potrzebuje jawnej konwersji, która najpierw usuwa separatory tysięcy, a potem zamienia przecinek na kropkę. Sama zamiana przecinka nie wystarcza: z „1 299,00” powstałoby „1 299.00”, a więc znowu NaN.

W podglądzie ten przypadek wychodzi na jaw tylko wtedy, gdy obszar zmiennych czyta się obok widoku modelu. W widoku modelu cena stoi wtedy jako tekst z przecinkiem, w obszarze zmiennych jako 0.

Czy zmienna JavaScript może sama coś wypychać do warstwy danych?

Nie powinna. Menedżer tagów oblicza zmienną za każdym razem, gdy potrzebuje jej tag lub wyzwalacz, przy jednym zdarzeniu więc niekiedy kilka razy, a podgląd wywołuje ją dodatkowo na potrzeby obszaru zmiennych. Push z wnętrza zmiennej tworzyłby przy tym niekontrolowane dodatkowe komunikaty, w najgorszym razie pętlę; funkcja powinna, tak jak ta w artykule, tylko czytać i zwracać wynik.

Lukas Wójcik

Lukas Wójcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Napisanie komentarza

Odmienne wyniki z innych kont i pytania o konfigurację są tu mile widziane.

Adres e-mail nie jest publikowany. Pola obowiązkowe oznaczono gwiazdką.

Artykuły i kategorie

CCTV

Śledź tę kategorię przez RSS

Cloud & AI

Wszystkie artykuły w tej kategorii (17) Śledź tę kategorię przez RSS

Data Privacy

Wszystkie artykuły w tej kategorii (19) Śledź tę kategorię przez RSS

Digital Analytics

Wszystkie artykuły w tej kategorii (58) Śledź tę kategorię przez RSS

Digital Marketing

Wszystkie artykuły w tej kategorii (37) Śledź tę kategorię przez RSS

IT & Networks

Wszystkie artykuły w tej kategorii (18) Śledź tę kategorię przez RSS

Music Production

Wszystkie artykuły w tej kategorii (17) Śledź tę kategorię przez RSS

Raspberry Pi

Śledź tę kategorię przez RSS

SaaS & Internet Earning

Śledź tę kategorię przez RSS

Smart Home

Wszystkie artykuły w tej kategorii (18) Śledź tę kategorię przez RSS

Tworzenie stron internetowych

Wszystkie artykuły w tej kategorii (11) Śledź tę kategorię przez RSS

Wtyczki i triki WordPress

Wszystkie artykuły w tej kategorii (14) Śledź tę kategorię przez RSS