LW IT Solutions logo LW IT Solutions logo LW IT Solutions
« Przegląd bloga /Digital Analytics / Odczyt statusu zgody dla pojedynczego zdarzenia w...
Ten artykuł w innych językach:

Odczyt statusu zgody dla pojedynczego zdarzenia w eksporcie GA4 do BigQuery

Odczyt statusu zgody dla pojedynczego zdarzenia w eksporcie GA4 do BigQuery
Spis treści
  1. Gdzie stoi
  2. Pułapka
  3. Co staje się dzięki temu możliwe
  4. Dwie rzeczy warte wiedzenia o wierszu
  5. Pytania i odpowiedzi
  6. Źródła

W raportach GA4 zgoda pojawia się jako zestawienie zbiorcze, jeśli w ogóle jest widoczna. Eksport do BigQuery zapisuje jej stan dla każdego zdarzenia w zagnieżdżonym rekordzie obok danych zdarzenia. Jest to stan obowiązujący w chwili jego zapisu.

To znacznie lepszy przedmiot do pracy i niesie ze sobą jedną pułapkę tworzącą błędną liczbę zamiast błędu.

Wcięte drzewo schematu tabeli zdarzeń GA4 z wyróżnionym rekordem privacy_info i jego trzema polami tekstowymi, obok panel z trzema możliwymi wartościami włącznie z pustą oraz panel porównujący dwa filtry SQL
Trzy możliwe wartości w polu, które większość zapytań filtruje tak, jakby miało dwie.

Gdzie stoi

Rekord privacy_info przechowuje stany przechowywania danych jako ciągi znaków, nie wartości logiczne. Do zagnieżdżonych pól odwołujesz się przez kropkę, a porównywane ciągi zapisujesz w cudzysłowie. Ponieważ wartości mogą być puste, przed obliczeniem współczynnika trzeba ustalić, co oznacza ich brak.

SQL
SELECT
  event_date,
  privacy_info.analytics_storage AS analytics,
  privacy_info.ads_storage       AS ads,
  COUNT(*)                       AS zdarzenia
FROM `projekt.analytics_XXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260801' AND '20260831'
GROUP BY 1, 2, 3
ORDER BY 1, 4 DESC

-- do uruchomienia przed kazdym filtrem. Chodzi o to, by
-- zobaczyc, ile wierszy wpada do trzeciego kubelka, bo ta
-- liczba rozstrzyga, czy pulapka nizej w ogole dziala

Najpierw grupowanie, potem filtr – na tym polega tu cała dyscyplina. Kosztuje jedno zapytanie, na pojedynczym miesiącu prawie nic, i odpowiada na pytanie, od którego zależy każde kolejne.

Pułapka

Dwa filtry czytające się jak przeciwieństwa nie są przeciwieństwami. analytics_storage = 'No' wybiera zdarzenia z wyraźną odmową. analytics_storage != 'Yes' wybiera odmowy plus wszystko bez utrwalonego stanu – bo w SQL porównanie z wartością pustą daje znowu wartość pustą, a nie prawdę, więc pierwszy filtr po cichu gubi puste wiersze, a drugi je zachowuje.

Współczynnik zgody na pierwszym wypada wyżej niż na drugim, na tych samych danych, dla tego samego dnia. Z zewnątrz żaden nie jest oczywiście błędny; oba dają wiarygodny procent. Który jest prawdziwy, zależy od tego, czym naprawdę są wartości puste, a to pytanie do wdrożenia, nie do SQL.

Wartości puste zwykle znaczą, że przy odpaleniu zdarzenia do tagu nie dotarł żaden sygnał zgody – trafienie przed rozstrzygnięciem na banerze, strona, na której platforma zgód się nie wczytała, zdarzenie po stronie serwera zbudowane bez przekazanego stanu. To trzy różne sytuacje o trzech różnych znaczeniach, a wrzucanie ich do jednego worka z wyraźnymi odmowami zawyża odmowę.

Co staje się dzięki temu możliwe

Stan zgody jest zapisany dla zdarzenia, nie tylko dla całego zasobu. Można go więc analizować razem z innymi polami tego samego wiersza.

Tekst
wedlug strony     ktore strony sa odrzucane najczesciej
                  zwykle te, na ktorych baner walczy z trescia
                  o te sama powierzchnie ekranu

wedlug urzadzenia komorka i komputer roznia sie na tyle, ze
                  liczba ogolna nie opisuje zadnego z nich

wedlug zrodla     ruch z linku wewnatrz aplikacji zachowuje
                  sie inaczej niz wizyta bezposrednia

wedlug godziny    wdrozenie psujace baner pokazuje sie jako
                  stopien o okreslonej godzinie - co wartosc
                  dzienna calkowicie wygladza

Przekrój według strony zwraca się najszybciej, bo zamienia liczbę, z którą nikt nic nie zrobi, w listę konkretnych stron.

Dwie rzeczy warte wiedzenia o wierszu

Pojedyncza wizyta może zawierać zdarzenia w więcej niż jednym stanie. Kto przyjmuje baner w połowie sesji, zostawia pod tym samym identyfikatorem pseudonimowym ślad zdarzeń odmówionych, po których idą udzielone – co jest poprawne i po cichu psuje każde zapytanie zakładające jeden stan na użytkownika.

A schemat eksportu rośnie. Do tabeli zdarzeń dodawano już pola i dodane zostaną kolejne, co jest argumentem przeciwko SELECT * we wszystkim dalej: kolumna przychodząca bez zapowiedzi jest nieszkodliwa dla zapytania wymieniającego kolumny z nazwy i zerwanym zadaniem ładowania dla takiego, które ich nie nazywa.

Pytania i odpowiedzi

Dlaczego eksport czasem nie zawiera ani jednej odmowy?

Zwykle dlatego, że Consent Mode działa w trybie podstawowym. Tag ładuje się wtedy dopiero po udzieleniu zgody; kto odmawia, nie wysyła niczego, a w eksporcie znajdują się wyłącznie zdarzenia ze zgodą albo bez utrwalonego stanu. Współczynnika zgody nie da się z takiego eksportu zbudować, musi on pochodzić z zapisów platformy zgód.

Jak przypisać wartości puste do trzech sytuacji opisanych w artykule?

Przez pozostałe pola tego samego wiersza, bo każda z trzech sytuacji zostawia własny wzorzec:

  • Trafienia przed rozstrzygnięciem na banerze skupiają się na początku sesji. Gdy zdarzenia każdej sesji zostaną uporządkowane według event_timestamp, wartości puste stoją na początku, a po nich idą zdarzenia z utrwalonym stanem.
  • Strona, na której platforma zgód się nie wczytała, ujawnia się w przekroju według strony albo według godziny: wartości puste skupione na określonych stronach lub szablonach stron albo stopień od chwili wdrożenia.
  • Zdarzenia po stronie serwera zbudowane bez przekazanego stanu da się rozpoznać po nazwie zdarzenia, jeśli wysyła je tylko serwer; są wtedy puste przez cały czas, niezależnie od strony i godziny.

W zapytaniu warto pokazać brakujące wartości jako trzecią grupę, zamiast pozostawiać ich obsługę samemu porównaniu. COALESCE(privacy_info.analytics_storage, 'puste') nadaje wartości pustej osobne oznaczenie widoczne w każdym grupowaniu i każdym filtrze. Decyzja o znaczeniu „puste” zapada wtedy raz, w jednym miejscu, a nie po cichu w każdym WHERE.

Dlaczego zapytanie zawęża zakres przez _TABLE_SUFFIX, a nie wyłącznie przez event_date?

Z dwóch powodów. Po pierwsze, BigQuery rozlicza zapytania w modelu na żądanie według ilości odczytanych danych, a tylko filtr na _TABLE_SUFFIX decyduje, które tabele dzienne w ogóle zostaną odczytane; sam filtr na event_date najpierw czyta każdą tabelę objętą symbolem wieloznacznym i dopiero potem odrzuca wiersze.

Po drugie, events_* obejmuje także tabele eksportu strumieniowego, events_intraday_…, których sufiks zaczyna się od intraday_. Zakres wartości dat, taki jak od '20260801′ do '20260831′, je wyklucza. Jeśli okres sięga bieżącego dnia, sam filtr na event_date wczytuje dodatkowo ich tymczasowe wiersze.

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.

Kontakt

Masz pytanie lub pomysł na projekt internetowy? Napisz krótko, o co chodzi. Formularz korzysta z reCAPTCHA do ochrony przed spamem.

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ą.