# Widget-interaction analytics (avoiding double-counting)

[← Back to GenUI Reference](https://kaltura.github.io/intelligent-agents-sdk/reference/genui-reference/index.md)


A recipe for reporting GenUI widget interactions (which widget the learner acted on, what they picked) to KAVA via `KavaAnalytics.buttonClicked()` (`./experience/analytics`).

## What to report

`KavaAnalytics` sends two client-side Application Events only: `pageLoad` and `buttonClicked` (see the module docblock in `src/experience/analytics.js`). It has no code path for call, message-delivery or feedback events, so don't build client-side reporting for these:

| Signal | Don't report it as... |
|---|---|
| A message was delivered to the user | A `buttonClicked`/`pageLoad` for "message shown" |
| The user thumbs-up/down'd a reply (`mgmt.feedback.add`) | A `buttonClicked` for "feedback given" |
| A call/session started or ended | A `buttonClicked`/`pageLoad` for "session start/end" |

A widget rendering on screen is a message arrival, not a separate signal. Report the **client-only choice the learner makes on that widget**: which chip they clicked, which link they opened, or which answer they picked. That choice is the only thing this recipe reports.

## The recipe: two widget interaction types, two distinguishable events

Wire each widget's `onAction` intent (see [GenUI · Authoring and Consuming Widgets § `onAction`, `WIDGET_KINDS`, and the hand-rolled escape hatch](https://kaltura.github.io/intelligent-agents-sdk/reference/genui/authoring-and-consuming/index.md#onaction-widget_kinds-and-the-hand-rolled-escape-hatch) above) straight into one `buttonClicked()` call. Construct one `KavaAnalytics` per page/session (same pattern as README's [KAVA analytics](https://github.com/kaltura/intelligent-agents-sdk/blob/main/README.md#kava-analytics-opt-in-client-only-application-events) section) and call it from the same `onAction` handler you already pass to `ExperienceRenderer`:

```js
import { ExperienceRenderer } from '@kaltura/intelligent-agents/experience/genui';
import { KavaAnalytics } from '@kaltura/intelligent-agents/experience/analytics';

// AGENTIC_PARTNER_ID: your partner id (see the README's KAVA analytics section linked above)
// session: an active KalturaAvatarSession from your app
const analytics = new KavaAnalytics({
  partnerId: AGENTIC_PARTNER_ID,
  sessionId: session.threadId,   // ties the event to this conversation without re-reporting the conversation itself
  hostingKalturaApplication: 25, // HOSTING_APPLICATIONS.agents
});

new ExperienceRenderer({
  session,
  mount: document.getElementById('widgets'),
  onAction(action, payload) {
    if (action === 'followup') {
      // Interaction type 1: a followups-tool suggested-question chip was clicked.
      analytics.buttonClicked({
        buttonType: 'Select',
        buttonName: 'genui-followup-chip',
        buttonValue: payload.question,   // which chip, makes this event distinguishable per question
        buttonInfo: 'GenUI followups widget, suggested-question chip clicked',
      });
      session.speak(payload.question);
    } else if (action === 'open') {
      // Interaction type 2: a show-link-tool (or sources/content-gallery) link card was opened.
      analytics.buttonClicked({
        buttonType: 'Open',
        buttonName: 'genui-show-link-card',
        buttonValue: payload.url,
        buttonInfo: 'GenUI show-link widget, link card opened',
      });
    }
  },
}).start();
```

Two rules keep the two events distinguishable and non-duplicated:

- **A different `buttonName` per widget/interaction type** (`genui-followup-chip` vs. `genui-show-link-card`), this is what a KAVA dashboard groups and filters on. Don't reuse one generic name across widget kinds.
- **`buttonValue` carries the specific choice** (the exact question text, the exact URL) rather than a boolean or the widget kind, the kind already lives in `buttonName`. Two clicks on two different chips inside the SAME `followups` widget still produce two distinct, non-duplicate rows, because each carries a different `buttonValue`.

Apply the same two-line pattern to any other `onAction` intent:

- `'play'` (`{entryId, url, embedUrl}`): a video-gallery clip was opened.
- `'submit'` (`{values}`): a `user-properties-form` was submitted. Report only that it happened and which fields were filled, not the raw values if they're personal data. See [Structured Data Forms](https://kaltura.github.io/intelligent-agents-sdk/guides/structured-data-forms/index.md) for where that data durably belongs instead.

## Why the two events stay distinct

`followups-tool` and `show-link-tool` (the second requires enabling the `show_link` capability, which is off by default, see [GenUI · Authoring and Consuming Widgets](https://kaltura.github.io/intelligent-agents-sdk/reference/genui/authoring-and-consuming/index.md#authoring-which-capability-turns-each-widget-on)) can arrive in the same turn. Run through the two `buttonClicked()` calls above, the resulting payloads share the same `partnerId`/`sessionId` (same conversation), but differ in `buttonName`/`buttonType`/`buttonValue`. That makes them two distinguishable, non-duplicated events tied to one conversation, not two copies of the same one. To test this without landing rows on your live KAVA data, pass an injected transport to `KavaAnalytics`.

## Related docs

| Doc | Covers |
|---|---|
| [GenUI · Authoring and Consuming Widgets](https://kaltura.github.io/intelligent-agents-sdk/reference/genui/authoring-and-consuming/index.md) | `ExperienceRenderer`'s `onAction` contract this recipe wires into |
| [GenUI · Per-Runtime Widget Detail](https://kaltura.github.io/intelligent-agents-sdk/reference/genui/widgets/index.md) | Per-runtime model keys, constraints, and descriptor shapes |
| [GenUI Reference](https://kaltura.github.io/intelligent-agents-sdk/reference/genui-reference/index.md) | Back to the index |

