Odczyt statusu zgody dla pojedynczego zdarzenia w eksporcie GA4 do BigQuery

Spis treści
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.
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.
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 dzialaNajpierw 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.
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 wygladzaPrzekró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.