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

Zgoda pojawia się w raportach GA4 jako zestawienie, jeśli w ogóle. W eksporcie do BigQuery pojawia się przy każdym zdarzeniu, w zagnieżdżonym rekordzie zapisanym obok każdego wiersza, trzymającym stan obowiązujący w chwili zapisu tego jednego zdarzenia.

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 nazywa się privacy_info i trzyma stany przechowywania jako ciągi znaków, nie jako wartości logiczne. Ponieważ jest zagnieżdżony, wymaga dostępu przez kropkę; ponieważ to ciągi, wymaga porównań w cudzysłowie; a ponieważ mogą być puste, wymaga przed każdym współczynnikiem rozstrzygnięcia, co oznacza brak wartości.

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

Ponieważ stan jest przy zdarzeniu, a nie przy zasobie, da się go skrzyżować ze wszystkim innym w wierszu.

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 samym zapytaniu warto utrzymać trzeci kubełek w polu widzenia, zamiast zostawiać go porównaniu: COALESCE(privacy_info.analytics_storage, 'puste') zamienia wartość pustą w osobną wartość, która pojawia się jawnie w każdym grupowaniu i każdym filtrze. Decyzja, co oznacza „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.

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