Widget events: Google Analytics, GTM and other counters

The Widget sends nothing to an analytics product on its own, and it is not tied to any of them. It hands every event to one function that you write, and the function sends the event wherever you want: Google Analytics 4, Google Tag Manager, Yandex Metrika, Plausible, Matomo or your own backend. Your consent logic stays on your page.

Subscribe to events

window.hdwDataLayer = window.hdwDataLayer || [];
hdwDataLayer.push({ onEvent: function (e) {
  console.log(e.name, e.params);
} });

e is { name, params }. Without a function there are no events. A second onEvent replaces the first, so keep all your counters in one function. An error inside your function does not break the Widget.

Events

Event Parameters Fires when
widget_open, widget_close none the panel opens or closes
tab_change tab the visitor clicks a tab (not when a command opens one)
teaser_show, teaser_click, teaser_close id a Teaser appears, is clicked or is closed
article_open source, title, from an article opens; from is list, search, teaser, page, ai or article
article_search query, results 1.2 seconds after the visitor stops typing
ask_sent length, suggested a question is sent; suggested tells whether it was a suggested one
ask_answered article an answer is complete; article is the source of the article it rests on or null
ask_vote helpful the visitor votes
ticket_handover none the visitor presses Create a ticket under an answer
ticket_created from_ask a ticket is created

What events never contain

The text of a question or an answer, a name, an email or a ticket number. One exception: article_search.query is what the visitor typed in the search field, and a visitor can type personal data there. Google Analytics forbids sending personal data, so drop it if you are unsure:

if (e.name === 'article_search') delete e.params.query;

Google Analytics 4 (gtag)

With the Google tag already on your page:

hdwDataLayer.push({ onEvent: function (e) {
  if (e.name === 'article_search') delete e.params.query;
  gtag('event', 'hdw_' + e.name, e.params);
} });

In GA4 the events appear in Reports, Engagement, Events within a day. Mark hdw_ticket_created as a key event, and register id, source, tab or helpful as custom dimensions under Admin, Custom definitions to use them in reports. The prefix keeps Widget events apart from your own.

Google Tag Manager

  1. Create a Custom HTML tag on All Pages with this code. dataLayer is the array of GTM, hdwDataLayer is the array of the Widget.
  2. Create a Custom Event trigger with the regular expression hdw_.* ("Use regex matching" on).
  3. Create Data Layer Variables such as hdw.id, hdw.source, hdw.tab and hdw.helpful.
  4. Create a GA4 Event tag on that trigger, with the event name {{Event}} and the variables as parameters.
<script>
window.hdwDataLayer = window.hdwDataLayer || [];
hdwDataLayer.push({ onEvent: function (e) {
  dataLayer.push({ event: 'hdw_' + e.name, hdw: e.params });
} });
</script>

Pushing Widget commands into dataLayer does nothing; commands go to hdwDataLayer. GTM can also drive the Widget: any GTM trigger (scroll depth, timer, element visibility) can fire a Custom HTML tag that pushes a Teaser, see Teaser and page buttons.

Yandex Metrika, Plausible and others

hdwDataLayer.push({ onEvent: function (e) {
  ym(COUNTER_ID, 'reachGoal', e.name, e.params);     // Yandex Metrika
  plausible(e.name, { props: e.params });            // Plausible
  _paq.push(['trackEvent', 'Widget', e.name]);       // Matomo
} });

What to measure

  • Widget use: widget_open divided by page views of the pages that carry the Widget.
  • Self-service: ask_answered and article_open against ticket_created. A rising answer count with a flat ticket count means the Widget absorbs questions.
  • Quality of AI answers: share of ask_vote with helpful true. The server-side figure with tickets included is in the AI answer outcomes report.
  • Content gaps: article_search with results 0 (if you keep the query), and the questions of the report that got no answer.
  • Teaser performance: teaser_click divided by teaser_show per id.
  • Which articles help: article_open by source, and ask_answered by article.

Consent

Check consent inside your function, so nothing reaches a counter before the visitor agrees:

hdwDataLayer.push({ onEvent: function (e) {
  if (!window.analyticsConsent) return;
  gtag('event', 'hdw_' + e.name, e.params);
} });

The Widget itself keeps in the browser: which Teasers were shown, the open tab and the question token for the session, and the name and email after a successful form unless you push remember: false. On the Redmine side, a remembered or prefilled name and email are stored with each AI question and appear in the server request log.

Related articles

Was this article helpful? Yes  No