Jak śledzić czat AskSpot w Google Analytics

Widget AskSpot emituje publiczne zdarzenia (otwarcie czatu, nowa wiadomość, zmiana sesji itd.), których możesz nasłuchiwać własnym skryptem JS. Co z nimi zrobisz, zależy od Ciebie: przekażesz je do dataLayer (GTM), wyślesz wprost do GA4 albo do wewnętrznej analityki. Ten przewodnik prowadzi przez rdzeń wdrożenia – zdarzenia widgetu, most do dataLayer, GTM i konfigurację GA4. Atrybucję sprzedaży, eksploracje GA4 i pełne skrypty referencyjne znajdziesz w uzupełnieniu zaawansowanym, a Shopify ma osobny poradnik.

W skrócie

  • Pomiar ma cztery warstwy: AskSpot dostarcza warstwę 0 (widget) i 1 (zdarzenia); warstwy 2–4 (most do dataLayer, GTM, GA4) budujesz u siebie.
  • Domyślnie ładuj widget przez GTM; dla dużych sklepów lepsza jest hybryda (widget z frontu, most z GTM).
  • conversationId to klucz spinający wszystko – powstaje przy pierwszej wiadomości, nie przy otwarciu dymka.
  • Gotowy most do dataLayer (Custom HTML tag w GTM) uruchamia pomiar w kilka minut; pełny skrypt produkcyjny jest w uzupełnieniu referencyjnym.
  • GA4 zawsze pokaże mniej rozmów niż panel AskSpot (zgody, adblocki) – to normalne, nie błąd.

Po co to robić – co realnie zmierzysz

Widget czatu AskSpot ma własny panel analityczny – widzisz w nim liczbę rozmów, kategorie pytań, rozwiązania. To jednak widok od strony czatu. Google Analytics daje widok od strony sesji użytkownika: skąd przyszedł, co oglądał przed rozmową, czy kupił po niej, ile wydał. Spinając jedno z drugim, odpowiadasz na pytania, na które osobno nie odpowiesz:

Pytanie biznesoweCo potrzebujesz
Jaki % ruchu w ogóle dotyka czatu?askspot_widget_open / wszystkie sesje
Czy rozmawiający z czatem konwertują lepiej?segment „sesje z askspot_conversation_started” vs reszta
Ile przychodu przechodzi przez ścieżkę z czatem?purchase w segmencie z czatem
Na jakich podstronach czat jest najbardziej potrzebny?page_location na askspot_conversation_started
Czy czat ratuje porzucone koszyki?ścieżka askspot_*begin_checkoutpurchase
Które konkretne rozmowy skończyły się zakupem?conversationId przekazany do purchase
Jak głębokie są rozmowy?licznik new_user_action na rozmowę

Architektura: cztery warstwy

Cały pomiar składa się z czterech warstw, jedna nad drugą:

WarstwaCo to jestKto ją buduje
0 – ładowanie widgetuSkrypt osadzający AskSpot (frontend / GTM / Custom Pixel) tworzy window.AskWidget[widgetId].AskSpot
1 – API zdarzeń widgetuwidget.addEventListener("new_user_action", cb) i widget.sessionInfo.conversationId.AskSpot
2 – most do dataLayerTwój skrypt mapuje zdarzenia widgetu na Twoje nazwy: window.dataLayer.push({ event: "askspot_...", ... }).Ty
3 – Google Tag ManagerReguła Custom Event + zmienne Data Layer + tag GA4.Ty
4 – Google Analytics 4Zdarzenia + wymiary niestandardowe + kluczowe zdarzenia + eksploracje.Ty

Kluczowa zasada: AskSpot dostarcza wyłącznie warstwy 0 i 1. Warstwy 2–4 są po Twojej stronie – i to jest celowe. Nie narzucamy nazw zdarzeń, formatu payloadu ani konwencji. Dopasuj je do tego, co już masz w GA4.

Jeśli wolisz, żeby AskSpot zbudował za Ciebie warstwę 2 (most) wewnątrz naszego custom scriptu – to możliwe, ustalmy indywidualnie. Domyślnie zakładamy, że robisz to sam, bo masz kontrolę nad nazewnictwem.

Warstwa 0 – jak ładujesz widget

Skrypt osadzający wygląda tak (ID integracji dostajesz od nas – jest unikalne per widget):

<script
  crossorigin="anonymous"
  async
  src="https://chat.askspot.io/api/v1/integration/{TWOJE_ID_INTEGRACJI}/embed-script"
></script>

Masz trzy sensowne miejsca, w których możesz go umieścić. Wybór ma realne konsekwencje analityczne.

Porównanie metod

A. Bezpośrednio we frontendzieB. Przez GTM (Custom HTML)C. Shopify Custom Pixel
Odporność na adblocki✓ najwyższa⚠ najniższa – adblocki blokują gtm.js w całości⚠ zależy od pixela
Obsługa zgód (consent)✗ robisz sam✓ wbudowana (Consent Mode / Cookiebot w GTM)✓ natywny consent API Shopify
Zasięg na ścieżcetam, gdzie jest Twój kod✓ wszędzie, gdzie działa kontenertylko tam, gdzie działa pixel
Działa na checkoucie Shopify✗ nie⚠ tylko przy Checkout Extensibility / Shopify Plus✓ tak (ale w sandboxie)
Widget się renderuje✓ tak✓ taknie (sandbox = brak dostępu do DOM strony)
Czas wdrożenia zmianydeploy frontu✓ publikacja kontenerapublikacja pixela
Ryzyko duplikacji⚠ jeśli zostawisz też frontend⚠ jeśli zostawisz też frontend

Rekomendacja

Domyślnie: GTM (wariant B). Powody:

  1. Zgody masz już rozwiązane – kontener GTM zwykle zna Cookiebot / CMP i respektuje Consent Mode. Nie duplikujesz logiki zgód w trzech miejscach.
  2. GTM działa na całej ścieżce, więc masz jedno miejsce prawdy.
  3. Zmiany bez deployu frontu.

Świadomy koszt: adblocki, które blokują googletagmanager.com, zablokują przy okazji czat. Na typowym e-commerce B2C to rząd kilku–kilkunastu procent ruchu. Jeśli czat jest krytycznym elementem obsługi klienta, a nie tylko „dodatkiem”, rozważ hybrydę.

Hybryda (zalecana dla dużych sklepów): widget ładowany bezpośrednio we frontendzie (odporność), most do dataLayer ładowany z GTM (zgody + elastyczność). Most i tak tylko nasłuchuje – jeśli GTM zostanie zablokowany, czat nadal działa, tracisz wyłącznie pomiar.

Nie duplikuj

Jeśli przechodzisz z frontendu na GTM – usuń skrypt z frontendu. Dwa równolegle załadowane embed-scripty to:

  • dwa wpisy w window.AskWidget → most może podpiąć się do złego,
  • podwójne listenery → zdarzenia liczone dwa razy w GA4,
  • potencjalnie dwa widgety w DOM.

Jeśli musisz mieć oba przejściowo, zabezpiecz się document.getElementById("askspot-script") przed dodaniem drugiego (zob. uzupełnienie referencyjne) i koniecznie użyj flagi window.askSpotDataLayerEventsBound, żeby most podpiął się tylko raz.

Ukrycie widgetu na wybranych podstronach

Na koszyku, checkoucie i stronie podziękowania widget zwykle przeszkadza. Nie rozwiązuj tego przez „nie ładuj skryptu” (stracisz pomiar) – poproś AskSpot o regułę wyświetlania po naszej stronie. Wtedy skrypt działa, analityka leci, a dymek się nie pokazuje.

Jeśli chcesz ukryć widget na konkretnych URL-ach, napisz do nas z listą wzorców – ustawimy to w konfiguracji integracji. Nie wymaga zmian w Twoim kodzie.

Warstwa 1 – API zdarzeń widgetu

Po załadowaniu skryptu widget wystawia globalne API:

window.AskWidget = {
  "<widgetId>": {
    sessionInfo: {
      chatId: "...",
      conversationId: "...",      // null przed pierwszą wiadomością
      sessionExpireTime: 1234567890,
      isMinimized: false
    },
    addEventListener: (eventName, callback) => void,
    openChat: () => void,
    closeChat: () => void,
    minimizeChat: () => void,
    changeLabel: (label) => void
  }
}

Jak się podpiąć

const widgetId = Object.keys(window.AskWidget)[0];
const widget = window.AskWidget[widgetId];

widget.addEventListener("new_chat_message", (event) => {
  const conversationId = widget.sessionInfo?.conversationId;
  console.log("AI odpisało w rozmowie", conversationId, event);
});

Cztery rzeczy, o których trzeba pamiętać

  1. Nazwy zdarzeń to stringi, nie stałe. Do addEventListener przekazujesz wartość stringową ("showNotification"), a nie nazwę klucza z wewnętrznej enumeracji (add_notification). Trzymaj się dokładnie nazw z tabeli w sekcji „Katalog zdarzeń”.
  2. Widget ładuje się asynchronicznie. Twój skrypt (zwłaszcza z GTM) prawie na pewno wystartuje, zanim window.AskWidget będzie istniał. Potrzebujesz retry z interwałem – nie setTimeout z jedną próbą. W przykładach używamy setInterval(500ms) z limitem 60 prób (30 sekund). To bezpieczne, bo zdarzenia i tak lecą dopiero po interakcji użytkownika.
  3. Payload bywa stringiem. W niektórych ścieżkach (forwarding z iframe) payload przychodzi jako JSON string, a nie obiekt. Rozpakuj go defensywnie, zanim użyjesz (wzorzec poniżej).
  4. conversationId czytaj z widget.sessionInfo w momencie zdarzenia – nie cache’uj go przy podpinaniu listenera, bo wtedy jeszcze nie istnieje.
const data = typeof event?.data === "string"
  ? JSON.parse(event.data)
  : event?.data;

Katalog zdarzeń widgetu

Zdarzenia publiczne (używaj tych)

ZdarzenieKiedy leciPayloadDo czego w analityce
chat_loadedBundle czatu skończył się ładować po otwarciuDiagnostyka wydajności
chat_openedChat został otwartyZainteresowanie – górna część lejka czatu
chat_closedChat zamknięty, stan rozmowy/UI posprzątanyKoniec interakcji
minimize_chatChat zminimalizowany (nie zamknięty)Odróżnia „odłożyłem” od „skończyłem”
new_user_actionUżytkownik wysłał wiadomość / wykonał akcję{ actionName }Rozpoczęcie i głębokość rozmowy
new_chat_messageAI odpisało (nowa odpowiedź asystenta){ awaitingUserResponse }Liczba tur, responsywność
session_updateZmiana sesji{ chatId, conversationId, sessionExpireTime, isMinimized }Źródło conversationId
agent_mode_enabledTryb agenta (copilot) aktywowany{ source } / { widgetId }Użycie zaawansowanych funkcji
agent_mode_disabledTryb agenta wyłączony{ source, reason? }j.w.
showNotificationPokazano proaktywną notyfikację / zaczepkę{ content, actions, durationMs }Ekspozycja proaktywna – mianownik CTR
hideNotificationUkryto notyfikacjęj.w.
custom_openHook: jeśli masz listener, kliknięcie dymka odpala to zamiast domyślnego otwarciaWłasna logika otwierania

Najczęściej wystarczy sześć: chat_opened, new_user_action, new_chat_message, minimize_chat, chat_closed, session_update.

Zdarzenia wewnętrzne (NIE podpinaj się)

Te istnieją w wewnętrznej magistrali zdarzeń widgetu, ale nie są częścią publicznego kontraktu. Mogą zniknąć lub zmienić semantykę bez ostrzeżenia:

open_chat, close_chat, add_button, remove_button, add_bar, remove_bar, iframe_style, update_label, minimize_notification, end_conversation, floating_button_animation_finished, setup, resize, run_agent, stop_agent, agent_steps_state

Do sterowania widgetem używaj metod publicznych: openChat(), closeChat(), minimizeChat(), changeLabel(...) – nie emituj wewnętrznych komend.

Zdarzenia biznesowe z konfiguracji rozmowy

Poza powyższymi widget może emitować własne zdarzenia zdefiniowane w konfiguracji Twojej integracji (conversationContext.eventAction) – np. „użytkownik kliknął rekomendowany produkt”, „przekierowanie do kategorii”. To najciekawsze zdarzenia z perspektywy sprzedażowej, ale są specyficzne dla Twojej konfiguracji.

Zapytaj swojego opiekuna AskSpot, jakie eventAction są aktywne na Twoim widgecie. To pytanie warto zadać, zanim zamkniesz zakres pomiaru.

conversationId – klucz spinający wszystko

To najważniejszy identyfikator w całym wdrożeniu. Jest to zarazem klucz, po którym łączysz swoje dane z analityką rozmów w panelu AskSpot.

Cykl życia

Krok użytkownikaZdarzenieconversationId
Wchodzi na stronęwidget się ładujenull
Klika dymekchat_openednull
Wysyła PIERWSZĄ wiadomośćnew_user_actionsession_update"abc-123" ✓ powstaje tutaj
Rozmowa trwa (kolejne wiadomości, nawigacja)new_user_action / new_chat_message"abc-123" (stały)
Kończy rozmowę i zaczyna nowąnew_user_action"def-456" (NOWY)

Konsekwencje praktyczne

  • chat_opened i chat_closed przed pierwszą wiadomością nie mają conversationId. To nie błąd – rozmowa jeszcze nie istnieje. Nie próbuj tego łatać podstawianiem chatId; mieszanie przestrzeni identyfikatorów jest gorsze niż pusta wartość. Zdarzenia sprzed pierwszej wiadomości sklejaj po swoim identyfikatorze sesji (GA4 client_id / session_id).
  • conversationId rotuje. Jeden użytkownik w jednej sesji może mieć kilka conversationId. Jeśli liczysz „unikalnych użytkowników czatu”, licz po client_id, nie po conversationId. Jeśli liczysz „rozmowy” – po conversationId.
  • conversationId przeżywa nawigację między podstronami (jest w pamięci sesji widgetu), ale sessionStorage Twojego mostu już niekoniecznie – dlatego deduplikacja conversation_started musi trzymać listę widzianych ID w sessionStorage, nie w zmiennej JS. Bez tego każde przeładowanie strony w trakcie rozmowy zgłosi kolejny „start rozmowy” i zawyżysz metrykę.

Zapisz go jako User Property (opcjonalnie)

Jeśli chcesz mieć conversationId dostępny na każdym późniejszym zdarzeniu w sesji (w tym na purchase, którego nie kontrolujesz), ustaw go jako GA4 user property w momencie startu rozmowy. Szczegóły w uzupełnieniu o atrybucji.

Warstwa 2 – most do dataLayer (gotowy skrypt)

To Twój kod. Poniższy skrypt jest przykładem – nazwy askspot_* i zestaw parametrów dopasuj do swojej konwencji nazewniczej w GA4.

Wersja minimalna (start w 5 minut)

Wklej jako Custom HTML tag w GTM, wyzwalany na All Pages (albo Initialization – All Pages).

<script>
(function () {
  window.dataLayer = window.dataLayer || [];

  function init() {
    var ids = window.AskWidget ? Object.keys(window.AskWidget) : [];
    if (!ids.length) return false;
    var widget = window.AskWidget[ids[0]];

    function push(name) {
      window.dataLayer.push({
        event: name,
        conversationId: widget.sessionInfo && widget.sessionInfo.conversationId
      });
    }

    // dedup: ta sama rozmowa trwa przez wiele odsłon - start liczymy raz
    function firstInConversation(id) {
      if (!id) return false;
      var key = "askspot_started_seen";
      var list;
      try { list = JSON.parse(sessionStorage.getItem(key)) || []; } catch (e) { list = []; }
      if (list.indexOf(id) !== -1) return false;
      list.push(id);
      try { sessionStorage.setItem(key, JSON.stringify(list)); } catch (e) {}
      return true;
    }

    widget.addEventListener("chat_opened",   function () { push("askspot_widget_open"); });
    widget.addEventListener("minimize_chat", function () { push("askspot_widget_minimize"); });
    widget.addEventListener("chat_closed",   function () { push("askspot_widget_close"); });

    widget.addEventListener("new_user_action", function () {
      var id = widget.sessionInfo && widget.sessionInfo.conversationId;
      if (firstInConversation(id)) push("askspot_conversation_started");
    });

    return true;
  }

  // AskWidget ładuje się async - retry aż będzie dostępny (max 30 s)
  if (!init()) {
    var n = 0, t = setInterval(function () {
      if (init() || ++n > 60) clearInterval(t);
    }, 500);
  }
})();
</script>

Efekt: do dataLayer trafiają askspot_widget_open, askspot_conversation_started, askspot_widget_minimize, askspot_widget_close – każde z conversationId.

Co dodać w wersji pełnej

Wersja minimalna nie mierzy głębokości rozmowy ani proaktywnych zaczepek. Pełny skrypt produkcyjny (w uzupełnieniu referencyjnym) dokłada:

  • askspot_user_message z licznikiem messageIndex – pozwala liczyć średnią długość rozmowy,
  • askspot_ai_message z awaitingUserResponse,
  • askspot_notification_shown – mianownik do CTR zaczepek proaktywnych,
  • askspot_agent_mode – użycie trybu agenta,
  • ochronę przed podwójnym bindowaniem (window.askSpotDataLayerEventsBound),
  • pageLocation na każdym zdarzeniu (przydatne, gdy GA4 przypisze zdarzenie do innej strony niż ta, na której faktycznie padło).

Konwencja nazewnicza – zrób to raz, porządnie

Zanim wkleisz skrypt, zdecyduj o nazwach. Zmiana po miesiącu = dziura w danych historycznych. Zalecany wzorzec: askspot_<obiekt>_<akcja>, snake_case, prefiks zawsze askspot_ (żeby jeden regex w GTM łapał wszystko).

Zdarzenie widgetuSugerowana nazwa w dataLayer
chat_openedaskspot_widget_open
minimize_chataskspot_widget_minimize
chat_closedaskspot_widget_close
pierwszy new_user_action w rozmowieaskspot_conversation_started
każdy new_user_actionaskspot_user_message
new_chat_messageaskspot_ai_message
showNotificationaskspot_notification_shown
agent_mode_enabledaskspot_agent_mode

Uwaga na limit GA4: darmowy GA4 ma limit 500 unikalnych nazw zdarzeń na property. Osiem nazw to nic, ale nie generuj nazw dynamicznie (np. askspot_msg_1, askspot_msg_2) – używaj parametrów.

Warstwa 3 – konfiguracja Google Tag Manager

Zmienne (Data Layer Variables)

Zmienne → Nowa → Data Layer Variable. Utwórz po jednej dla każdego parametru, którego chcesz używać:

Nazwa zmiennej w GTMNazwa w Data Layer
DLV – conversationIdconversationId
DLV – messageIndexmessageIndex
DLV – actionNameactionName
DLV – awaitingUserResponseawaitingUserResponse
DLV – pageLocationpageLocation

Ustaw Default Value na (not set) tam, gdzie parametr bywa pusty (np. conversationId przy askspot_widget_open). Inaczej GA4 dostanie undefined i parametr zniknie z raportu, zamiast pokazać wartość „brak”.

Reguła – jeden regex na wszystko

Reguły → Nowa → Zdarzenie niestandardowe (Custom Event):

  • Nazwa zdarzenia: ^askspot_w+
  • ✓ zaznacz Use regex matching
  • Uruchamiaj: Wszystkie zdarzenia niestandardowe

Nazwij ją CE – AskSpot (all). Jedna reguła obsłuży wszystkie obecne i przyszłe zdarzenia z prefiksem askspot_. Jeśli chcesz osobno wyzwalać wybrane zdarzenia (np. tylko askspot_conversation_started jako konwersję), utwórz dodatkowe reguły z dokładnym dopasowaniem nazwy – ale tag zbiorczy i tak zostaw.

Tag GA4 Event

Tagi → Nowa → Google Analytics: zdarzenie GA4.

PoleWartość
Tag konfiguracji / Measurement IDTwój istniejący tag GA4 Configuration
Nazwa zdarzenia{{Event}}
Reguła wyzwalającaCE – AskSpot (all)

Parametry zdarzenia:

Nazwa parametruWartość
conversation_id{{DLV - conversationId}}
message_index{{DLV - messageIndex}}
action_name{{DLV - actionName}}
page_location_custom{{DLV - pageLocation}}

Dlaczego {{Event}} jako nazwa? Bo jeden tag obsłuży wszystkie zdarzenia AskSpot. Alternatywa – osobny tag na każde zdarzenie – jest czytelniejsza w audycie, ale mnoży pracę. Przy 8 zdarzeniach zbiorczy tag wygrywa.

Ustawienia zgód na tagu

Na zakładce Zaawansowane → Ustawienia zgody ustaw dla tagu mostu (Custom HTML) i tagu GA4: Wymagana dodatkowa zgoda przed uruchomieniem: analytics_storage. Dzięki temu GTM sam wstrzyma tag do momentu uzyskania zgody, bez logiki w Twoim kodzie. Szczegóły w sekcji „Zgody”.

Kolejność ładowania

Jeśli ładujesz i widget, i most z GTM, ustaw:

  • Tag AskSpot – embed script (Custom HTML) → trigger Initialization – All Pages
  • Tag AskSpot – dataLayer bridge (Custom HTML) → trigger All Pages, w Zaawansowane → Kolejność tagów zaznacz „Uruchom tag przed tym tagiem”: AskSpot – embed script

W praktyce retry w moście i tak to załatwi, ale jawna kolejność skraca czas do pierwszego zdarzenia.

Warstwa 4 – Google Analytics 4

Same zdarzenia w GA4 to za mało. Bez poniższych kroków parametry nie pojawią się w raportach.

Zarejestruj wymiary niestandardowe

Administracja → Definicje niestandardowe → Utwórz wymiar niestandardowy:

Nazwa wyświetlanaZakresParametr zdarzenia
AskSpot Conversation IDEventconversation_id
AskSpot Message IndexEventmessage_index
AskSpot Action NameEventaction_name

Wymiary działają tylko od momentu utworzenia. GA4 nie uzupełnia ich wstecz. Zarejestruj je tego samego dnia, w którym publikujesz kontener GTM – inaczej stracisz pierwsze dni danych. Limit: 50 wymiarów o zakresie Event w standardowym GA4. Sprawdź, ile masz wolnych, zanim dodasz trzy.

Oznacz kluczowe zdarzenia (key events)

Administracja → Kluczowe zdarzenia → Nowe kluczowe zdarzenie: askspot_conversation_started – to jest Twoja główna mikrokonwersja czatu. Nie oznaczaj jako key event askspot_user_message ani askspot_ai_message – będą się liczyć wielokrotnie w jednej sesji i zniekształcą współczynnik konwersji.

Odbiorcy (audiences) – fundament pod atrybucję

Administracja → Odbiorcy → Nowy odbiorca → Utwórz niestandardowego:

  • Odbiorca „Użytkownicy czatu”: warunek – zdarzenie askspot_conversation_started wystąpiło co najmniej raz; okres członkostwa 30 dni.
  • Odbiorca „Otworzyli, nie napisali”: warunek – askspot_widget_open ≥ 1 ORAZ askspot_conversation_started = 0. Przydatne do oceny, czy dymek obiecuje coś, czego czat nie dowozi.

Odbiorcy zaczynają zbierać dane od momentu utworzenia – tak samo jak wymiary. Utwórz je od razu.

Raporty i eksploracje

A. Lejek czatu (Funnel exploration)

KrokWarunek
1session_start
2askspot_widget_open
3askspot_conversation_started
4add_to_cart
5begin_checkout
6purchase

Ustaw lejek otwarty (open funnel), nie zamknięty – użytkownik może dodać do koszyka przed rozmową – i włącz podział wg Device category oraz Session default channel group.

Co z tego odczytasz: gdzie ludzie odpadają. Duży spadek między krokiem 2 a 3 = dymek przyciąga, ale pierwsza wiadomość jest za trudna (rozważ podpowiedzi startowe). Duży spadek między 3 a 4 = rozmowy nie prowadzą do produktu.

B. Porównanie konwersji: z czatem vs bez

Eksploracje → Eksploracja swobodna.

  • Wiersze: Session default channel group
  • Wartości: Sesje, Zakupy, Przychód, Współczynnik konwersji sesji
  • Segmenty porównania: A = sesje zawierające askspot_conversation_started; B = sesje nie zawierające

To nie jest dowód przyczynowości. Ludzie, którzy piszą do czatu, są z definicji bardziej zaangażowani – kupiliby częściej także bez czatu. Ta tabela pokazuje korelację i tak trzeba ją prezentować. Twardy dowód wymaga testu A/B (zob. uzupełnienie o atrybucji).

C. Gdzie zaczynają się rozmowy

Eksploracje → Eksploracja swobodna.

  • Wiersze: Strona docelowa lub Page location
  • Filtr: nazwa zdarzenia askspot_conversation_started
  • Wartości: Liczba zdarzeń

Podstrony z największą liczbą startów rozmów to miejsca, gdzie treść nie odpowiada na pytania – bezpośredni sygnał dla treści i UX.

D. Głębokość rozmów

  • Wiersze: AskSpot Message Index
  • Wartości: Liczba zdarzeń

Rozkład pokazuje, na której wiadomości ludzie odpadają. Jeśli 70% rozmów kończy się na jednej wiadomości – albo czat odpowiada świetnie za pierwszym razem, albo tak źle, że użytkownik rezygnuje; zestaw to z danymi z panelu AskSpot (resolution), żeby rozstrzygnąć.

E. Ścieżka po rozmowie (Path exploration)

Eksploracje → Eksploracja ścieżek. Punkt początkowy = zdarzenie askspot_conversation_started; kroki +1, +2, +3 = nazwy zdarzeń. Pokazuje, co realnie robią użytkownicy zaraz po rozmowie. Jeśli dominuje page_view na kategorię, czat kieruje ruch; jeśli session_end – nie.

Eksport do BigQuery (dla zaawansowanych)

GA4 sampluje i agreguje. Jeśli chcesz policzyć realny wpływ czatu na przychód per rozmowa, podłącz BigQuery Export (darmowy w standardowym GA4) i połącz po conversation_id z eksportem rozmów z panelu AskSpot. To jedyny sposób na analizę bez ograniczeń kardynalności.

Atrybucja: czy czat sprzedaje? → gdy raporty są już gotowe, cztery poziomy atrybucji sprzedaży – plus pełne skrypty produkcyjne i słownik KPI – znajdziesz w uzupełnieniu zaawansowanym.

Zasada

Czat AskSpot ma dwie natury i dwa reżimy zgody:

FunkcjaCharakterZgoda
Sam widget czatu (obsługa klienta)zwykle niezbędny funkcjonalniezwykle nie wymaga zgody analitycznej
Wysyłka zdarzeń do GA4 / dataLayeranalityczny✓ wymaga analytics_storage
Cookie askspot_cid do atrybucjianalityczny✓ wymaga analytics_storage

To kwalifikacja praktyczna, nie porada prawna. Ostateczną klasyfikację czatu w Twoim CMP ustal ze swoim inspektorem ochrony danych. Jeśli potrzebujesz, mamy gotowe zapisy do regulaminu i polityki prywatności dotyczące integracji czatu – poproś swojego opiekuna.

Rekomendacja: zostaw to GTM-owi

Najczystsze rozwiązanie: nie pisz logiki zgód w swoim kodzie. Zamiast tego:

  1. Upewnij się, że Twój CMP (Cookiebot, Consentmanager, OneTrust…) działa w trybie Google Consent Mode v2 i jest wdrożony w GTM.
  2. Na tagach AskSpot (most + GA4) ustaw Zaawansowane → Ustawienia zgody → Wymagana dodatkowa zgoda: analytics_storage.
  3. Gotowe. GTM sam wstrzyma tagi do momentu zgody i odpali je po jej udzieleniu (dzięki Consent Initialization).

Zalety: jedno miejsce zarządzania, spójność z resztą pomiaru, brak ryzyka rozjazdu, gdy CMP się zmieni.

Jeśli musisz sprawdzać zgodę w kodzie

Bywa konieczne – np. w Shopify Custom Pixel, gdzie GTM nie sięga. Wzorzec dla Cookiebota w sandboxie Shopify:

const getCookiebotConsent = async () => {
  try {
    const cookieString = await browser.cookie.get('CookieConsent');
    if (!cookieString) return null;
    return {
      marketing:   cookieString.includes('marketing:true'),
      statistics:  cookieString.includes('statistics:true'),
      preferences: cookieString.includes('preferences:true')
    };
  } catch (e) {
    return null;
  }
};

async function loadIfAnalyticsConsentGranted() {
  const consent = await getCookiebotConsent();
  if (consent?.statistics) loadAskSpot();
}

Trzy pułapki tego podejścia:

  1. Parsowanie stringiem jest kruche. includes('statistics:true') przestanie działać, jeśli Cookiebot zmieni format cookie. Traktuj to jako rozwiązanie tymczasowe.
  2. Brak reakcji na zmianę zgody. Powyższy kod sprawdza zgodę raz. Jeśli użytkownik zaakceptuje ciasteczka po uruchomieniu kodu, nic się nie stanie. Dodaj nasłuch na zdarzenie zmiany zgody swojego CMP i ponów próbę.
  3. Domyślnie brak zgody = brak czatu. Jeśli sklasyfikowałeś czat jako niezbędny funkcjonalnie, blokowanie go pod statistics jest nadmiarowe – zablokuj wtedy tylko most, nie sam widget.

Consent Mode v2 – co się dzieje przy braku zgody

Przy Consent Mode v2 i odmowie zgody GA4 wysyła tzw. cookieless pings – bez identyfikatorów, ale zliczane w modelowaniu konwersji. Zdarzenia AskSpot nie zostaną wysłane, jeśli tag ma ustawione wymaganie analytics_storage. Efekt: Twoje liczby rozmów w GA4 będą niższe niż w panelu AskSpot. To oczekiwane i poprawne.

Na Shopify? Storefront działa dokładnie jak wyżej; checkout uruchamia się w izolowanym sandboxie Custom Pixela, z własnymi regułami. Zobacz analitykę AskSpot na Shopify.

Debugowanie i checklista QA

Sprawdź warstwę 1 (widget) – konsola przeglądarki

// 1. Czy widget w ogóle jest?
Object.keys(window.AskWidget || {});
// oczekiwane: ["<jakieś-id>"] - jeśli [] to skrypt się nie załadował

// 2. Podepnij logger na wszystko
(function () {
  var w = window.AskWidget[Object.keys(window.AskWidget)[0]];
  ["chat_loaded","chat_opened","chat_closed","minimize_chat",
   "new_user_action","new_chat_message","session_update",
   "agent_mode_enabled","agent_mode_disabled","showNotification"]
   .forEach(function (name) {
     w.addEventListener(name, function (e) {
       console.log("[AskSpot]", name, e, "cid:", w.sessionInfo && w.sessionInfo.conversationId);
     });
   });
  console.log("logger podpięty");
})();

// 3. Sprawdź stan sesji
window.AskWidget[Object.keys(window.AskWidget)[0]].sessionInfo;

Napisz wiadomość do czatu i obserwuj konsolę. Powinieneś zobaczyć new_user_actionsession_update (z conversationId) → new_chat_message.

Sprawdź warstwę 2 (dataLayer)

// podgląd na żywo wszystkich pushy z prefiksem askspot_
(function () {
  var orig = window.dataLayer.push;
  window.dataLayer.push = function () {
    var a = arguments[0];
    if (a && typeof a.event === "string" && a.event.indexOf("askspot_") === 0) {
      console.log("[dataLayer]", a);
    }
    return orig.apply(window.dataLayer, arguments);
  };
  console.log("podsłuch dataLayer aktywny");
})();

// historia (co już poleciało)
window.dataLayer.filter(function (x) {
  return x.event && String(x.event).indexOf("askspot_") === 0;
});

Sprawdź warstwy 3 i 4

  • GTM Preview (Tag Assistant): włącz podgląd, przejdź ścieżkę, sprawdź, że w lewym panelu pojawiają się zdarzenia askspot_* i że tag GA4 ma status Fired. Kliknij tag → Values → sprawdź, że conversation_id nie jest undefined.
  • GA4 DebugView: Administracja → DebugView. Wymaga aktywnego GTM Preview albo rozszerzenia GA Debugger. Rozwiń zdarzenie i sprawdź parametry.
  • GA4 Raporty czasu rzeczywistego: Raporty → Czas rzeczywisty → Liczba zdarzeń wg nazwy zdarzenia. Opóźnienie do ~1 min.
  • Raporty standardowe: dane pojawią się po 24–48 h. Nie panikuj wcześniej.

Checklista przed publikacją

Warstwa 0 – ładowanie

  • Skrypt AskSpot ładuje się dokładnie raz (Network → filtr embed-script, jeden wpis).
  • Object.keys(window.AskWidget).length === 1.
  • Po przejściu z frontendu na GTM: stary skrypt usunięty z motywu / kodu.
  • Widget nie pokazuje się na koszyku / checkoucie / stronie podziękowania (reguła po stronie AskSpot).

Warstwy 1–2 – zdarzenia i most

  • askspot_widget_open leci przy otwarciu dymka.
  • askspot_conversation_started leci przy pierwszej wiadomości.
  • askspot_conversation_started nie leci ponownie po przeładowaniu strony w trakcie rozmowy ← najczęstszy błąd.
  • conversationId jest niepuste na askspot_conversation_started.
  • Most nie podpina listenerów dwa razy (window.askSpotDataLayerEventsBound === true).
  • Zdarzenia lecą na wszystkich typach podstron (home, kategoria, produkt, koszyk).

Warstwy 3–4 – GTM i GA4

  • Wszystkie zmienne DLV mają Default Value ((not set)).
  • Trigger regex ^askspot_w+ łapie wszystkie zdarzenia.
  • Tag GA4 ma ustawione analytics_storage w Ustawieniach zgody; przy odmowie zgody tagi się nie odpalają (test w incognito).
  • Wymiary niestandardowe i kluczowe zdarzenie utworzone przed publikacją kontenera.
  • Po 48 h liczby w GA4 są w tym samym rzędzie wielkości co w panelu AskSpot (rozjazd 10–40% w dół jest normalny).

Shopify – dodatkowo: Custom Pixel wdrożony najpierw na testowym sklepie; zweryfikowane, czy sandbox nie blokuje dostępu do pamięci rozmowy (czy conversationId jest dostępny na checkoucie); jeśli blokuje – włączony fallback na cookie askspot_cid na domenie głównej; zakup testowy łączy się z rozmową (potwierdzenie po stronie AskSpot – napisz do opiekuna z datą i godziną testu).

Weryfikacja po stronie AskSpot. Rozmowy i konwersje zapisujemy u siebie. Po Twoim teście możemy potwierdzić, czy zakupy poprawnie łączą się z rozmowami – nawet jeśli po Twojej stronie czegoś nie widać. Napisz do opiekuna z datą i przybliżoną godziną testu.

Najczęstsze błędy wdrożeniowe

  1. Zdublowany skrypt po migracji na GTM. Zostawiony skrypt we frontendzie + nowy w GTM = podwojone zdarzenia. Objaw: liczba rozmów w GA4 dwa razy większa niż w panelu. Zawsze usuwaj stary.
  2. conversation_started liczone przy każdej odsłonie. Brak deduplikacji po conversationId w sessionStorage. Objaw: „starty rozmów” ≈ „wiadomości użytkownika”. Napraw funkcją firstInConversation.
  3. Cache’owanie conversationId przy podpinaniu listenera. const cid = widget.sessionInfo.conversationId poza callbackiem zwróci null na zawsze. Czytaj wewnątrz callbacka.
  4. Wymiary niestandardowe utworzone po fakcie. GA4 nie uzupełnia wstecz. Dwa tygodnie danych bez conversation_id to dwa tygodnie stracone.
  5. Brak Default Value w zmiennych DLV. undefined powoduje, że parametr w ogóle nie trafia do GA4.
  6. Jedna próba zamiast retry. setTimeout(init, 1000) zadziała na szybkim łączu i zawiedzie na 3G. Zawsze setInterval z limitem prób.
  7. Sprawdzanie zgody tylko raz. Użytkownik akceptuje cookies po 3 s, kod sprawdził po 1 s → brak pomiaru dla całej grupy „akceptujących z opóźnieniem”. Nasłuchuj zmiany zgody.
  8. Traktowanie GA4 jako źródła prawdy o rozliczeniach. Zawsze będzie niższe. Do faktury służy panel AskSpot.
  9. Nazwy zdarzeń zmieniane w trakcie. askspot_chat_startaskspot_conversation_started po miesiącu = dwa niepowiązane zestawy danych. Ustal konwencję przed startem.
  10. Wyciąganie wniosków przyczynowych z segmentów. „Sesje z czatem konwertują 3× lepiej” nie znaczy „czat potraja konwersję”. Bez testu A/B mów o korelacji.

Pełne skrypty i słownik KPI → kompletny produkcyjny most do dataLayer, hook Reacta i słownik KPI znajdziesz w uzupełnieniu referencyjnym.

Czego ten poradnik nie rozstrzyga

Kilka rzeczy zależy od Twojej konkretnej instalacji i wymaga sprawdzenia u nas albo testu:

  1. Jakie zdarzenia biznesowe (conversationContext.eventAction) są aktywne na Twoim widgecie – zapytaj opiekuna AskSpot.
  2. Czy sandbox Shopify Custom Pixel przepuszcza dostęp do pamięci rozmowy – wymaga testu na Twojej instalacji.
  3. Dokumentacja API konwersji AskSpot (wariant server-side z Poziomu 3) – udostępniamy na życzenie.
  4. Reguły ukrywania widgetu na wybranych URL-ach – konfigurujemy po naszej stronie, przyślij listę wzorców.
  5. Kwalifikacja czatu w Twoim CMP (niezbędny funkcjonalnie vs analityczny) – decyzja Twojego IOD; mamy gotowe zapisy do polityki prywatności.

Chcesz zobaczyć, co dokładnie mierzysz? Zajrzyj na stronę Agenta czatu AI – a jeśli używasz też skrzynki, Agenta Skrzynki AI.

Dlaczego GA4 pokazuje mniej rozmów niż panel AskSpot?

Bo część ruchu odrzuca zgody analityczne, a adblocki blokują GTM/GA4. Przy Consent Mode v2 zdarzenia AskSpot nie lecą bez zgody na analytics_storage. Rozjazd 10–40% w dół jest normalny i poprawny – do rozliczeń służy panel AskSpot, nie GA4.

Kiedy powstaje conversationId?

Przy pierwszej wiadomości użytkownika (new_user_action), nie przy otwarciu dymka. chat_opened przed pierwszą wiadomością ma conversationId = null – to nie błąd, rozmowa jeszcze nie istnieje.

Czy czat na pewno podnosi konwersję?

Segment „sesje z czatem vs bez” pokazuje korelację, nie przyczynowość – rozmawiający są z definicji bardziej zaangażowani. Twardy dowód „czat dowozi X zł” daje wyłącznie test A/B ze stabilną grupą kontrolną.

Muszę pisać kod, czy AskSpot to zrobi?

AskSpot dostarcza warstwy 0 i 1 (widget + zdarzenia). Warstwy 2–4 (most, GTM, GA4) budujesz u siebie, żebyś kontrolował nazewnictwo. Jeśli wolisz, żebyśmy zbudowali most wewnątrz naszego custom scriptu – to możliwe, ustalmy indywidualnie.

LinkedIn

Autor

Zespół AskSpot

AskSpot tworzy agentów AI – Chat i Inbox – dla e-commerce: doradztwo produktowe na stronie i obsługę 24/7 w mailu, czacie i na marketplace’ach, w ponad 200 językach.

Case studies

Realne wyniki sklepów e-commerce

Zobacz, jak sklepy internetowe wykorzystują AskSpot, by automatyzować rozmowy, odciążać obsługę i zwiększać sprzedaż.

Wszystkie case studies

Morele.net

Jak Morele.net obniżyło koszty obsługi klienta o 90%

Morele.net obniżyło koszty obsługi o 90%, z 50 do 5 osób. AskSpot rozwiązuje 65% z 37 600 rozmów miesięcznie bez konsultanta i odpowiada na Allegro.

Czytaj historię →

Militaria.pl

Jak Militaria rozwiązuje 72% czatów w 8 językach

Militaria.pl prowadzi czat AI AskSpot na trzech domenach i w 8 językach: 61% klikalności rekomendacji, 26% dodań do koszyka, 72% czatów bez konsultanta.

Czytaj historię →

4FIZJO

Jak 4FIZJO rozwiązuje 61% czatów klientów dzięki AI

Chat AI AskSpot rozwiązuje 61% z 21 360 rozmów miesięcznie bez konsultanta na 6 rynkach, a Agent Inbox sam obsługuje 25% zgłoszeń e-mail i Allegro w helpdesku Thulium.

Czytaj historię →

Meblobranie

Jak doradztwo w czacie wprowadza do koszyka meble ogrodowe za 8,2 mln zł miesięcznie

Agent AskSpot w Meblobranie odpowiada na pytania, od których zależy zakup mebli ogrodowych: wymiar, kolor, kotwienie, moskitiery. Doradztwo w czacie wprowadza do koszyka 8,2 mln zł miesięcznie, 20% czatów napełnia koszyk, 70% rozwiązanych.

Czytaj historię →

Szopex

Jak jeden agent AI obsługuje trzy marki Szopexu

Jeden agent AskSpot działa w trzech sklepach Szopexu – Sklep Biegacza, Warsaw Sneaker Store i SKStore – na trzech platformach e-commerce. 67% rozmów rozwiązanych, 58% CTR, 11,7% kończy się zakupem.

Czytaj historię →

moderno.dk

Jak moderno.dk rozwiązuje 64% czatów o meble bez konsultanta

Agent AskSpot rozwiązuje w moderno.dk 64% pytań o meble bez konsultanta – terminy dostaw, wymiary, dostępność – a 12,3% czatów kończy się koszykiem.

Czytaj historię →

16analiz przypadków

Zobacz wszystkie historie

Każdy sklep, który zmierzyliśmy – o co pytali klienci, co zrobił agent i jakie liczby z tego wyszły.

Przejrzyj wszystkie →

Gotowy, by każda rozmowa sprzedawała?

Umów demo i zobacz AskSpot na swoim asortymencie. Wdrożenie zajmuje kilka dni.