- Subscribe to events
- Events
- What events never contain
- Google Analytics 4 (gtag)
- Google Tag Manager
- Yandex Metrika, Plausible and others
- What to measure
- Consent
- Related articles
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
- Create a Custom HTML tag on All Pages with this code.
dataLayeris the array of GTM,hdwDataLayeris the array of the Widget. - Create a Custom Event trigger with the regular expression
hdw_.*("Use regex matching" on). - Create Data Layer Variables such as
hdw.id,hdw.source,hdw.tabandhdw.helpful. - 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_opendivided by page views of the pages that carry the Widget. - Self-service:
ask_answeredandarticle_openagainstticket_created. A rising answer count with a flat ticket count means the Widget absorbs questions. - Quality of AI answers: share of
ask_votewithhelpfultrue. The server-side figure with tickets included is in the AI answer outcomes report. - Content gaps:
article_searchwithresults0 (if you keep the query), and the questions of the report that got no answer. - Teaser performance:
teaser_clickdivided byteaser_showperid. - Which articles help:
article_openbysource, andask_answeredbyarticle.
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.