> ## Documentation Index
> Fetch the complete documentation index at: https://www.pagent.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Event listener

> Listen to everything the SDK records on the pagent:event bus

Every event the pagent SDK records is also dispatched on `window` as a `pagent:event` `CustomEvent`. Listen to it to debug your tracking or to forward pagent data to your own tools.

<Tip>
  To send test assignments and conversions to Google Tag Manager, JENTIS or another dataLayer, you don't need a listener. Turn on [tag manager forwarding](/docs/guides/tracking/tag-manager-forwarding) instead.
</Tip>

This page is about reading what pagent records. To send your own events to pagent, see [Sending events](/docs/guides/tracking/events).

Here is an example:

```html theme={"dark"}
<script>
  window.addEventListener('pagent:event', (e) => {
      console.log("pagent:event", e.detail);
  });
</script>
```

> **Note:** If no session is active, pagent will not emit any events on the `pagent:event` bus.

## Event types

Below is an overview of all event kinds that pagent emits.

| Event `kind` | Description |
| - | - |
| click | Fired whenever the visitor clicks anywhere on the page. |
| page\_view | Fired each time a page is loaded or navigated to. |
| opt\_in | Fired when the visitor explicitly opts-in to tracking. |
| opt\_out | Fired when the visitor opts-out of tracking. |
| event | Fired when an [event](/docs/guides/tracking/events) is recorded, whether your code reported it or pagent observed it. |
| conversion | Fired when the SDK records a conversion in the browser: a click goal, a page view goal, or a deprecated programmatic conversion. Event goals are computed later and do not fire this. |
| session\_start | Fired the moment a new session begins. |
| session\_end | Fired when the current session is terminated. |
| error | Fired whenever an error occurs while running pagent. |
| highlight\_text | Fired when pagent highlights text on the page. |
| element\_view | Fired when a tracked element scrolls into the viewport. |
| hover | Fired when the visitor hovers over a tracked element. |
| session\_ping | Sent periodically while a session is active to keep it alive. |

## Common properties

The following attributes are included in **every** event:

| Property | Type | Description |
| - | - | - |
| session\_id | string | Unique identifier of the current session. |
| visit\_id | string | Unique identifier of the current page view. |
| time | number | Unix timestamp in milliseconds when the event occurred. |
| is\_unique | boolean (optional) | `true` if this is the first time this event type was emitted during the session. |
| is\_opted\_in | boolean | Indicates whether the visitor has opted-in to tracking. |
| session\_duration | number | Session duration in milliseconds at the moment the event was emitted. |
| scroll\_depth | number | Maximum vertical scroll position in pixels that the visitor has reached so far. |
| scroll\_percentage | number | Percentage of the page that has been scrolled. |
| url | string | Absolute URL of the page where the event happened. |

## event properties

Events of kind `event` carry these properties alongside the common ones:

| Property | Type | Description |
| - | - | - |
| label | string | The event label, for example `purchase`. |
| source | string (optional) | How the SDK captured it: `reported` (or absent) for `window._pgnt.push`, `data_layer`, `window_event` or `trigger` for [observed events](/docs/guides/tracking/instrumentation). |
| revenue | number (optional) | Revenue in cents. |
| properties | object or array (optional) | The event's properties. |

## session\_start properties

The `session_start` event is the one that carries the visitor's experiment context. When the
visitor is enrolled in a running test, it includes the following additional properties (alongside
the common properties above):

| Property | Type | Description |
| - | - | - |
| experiment\_id | string (optional) | The experiment UUID. |
| experiment\_numeric\_id | number (optional) | The sequential test number shown in the pagent dashboard as "Test #N" (for example, `27`). Useful for building human-readable names. |
| variation\_id | string (optional) | UUID of the variation assigned to this visitor. |
| is\_control | boolean (optional) | `true` if the visitor is in the control group, `false` if in a variant. |
| endpoint\_id | string (optional) | UUID of the targeted endpoint. |
| endpoint\_path | string (optional) | The path the test is configured to target, for example `/pricing`. For tests targeting a URL pattern (glob), this may be the pattern rather than the exact visited URL. |
| cohort\_id | string (optional) | UUID of the cohort the visitor belongs to. |
| cohort\_version | number (optional) | Version of the cohort definition. |

> **Note:** All of these experiment fields are absent (or `null`) when there is no active pagent
> test on the current page, for example analytics-only sessions or visitors not enrolled in any
> running test. Always check `event.experiment_id` before reading the others, as the JENTIS example
> below does.

## Example integration

You can also forward individual pagent events to other analytics platforms by hand. The example below sends the **conversion** event to [JENTIS](https://docs.jentis.com/documentation/jentis-data-layer-fundamentals) using its push-based data layer. For JENTIS itself, [tag manager forwarding](/docs/guides/tracking/tag-manager-forwarding) now does this without code; use the example as a pattern for other tools.

```html theme={"dark"}
<script>
  // Keep track of the current session
  let session = null;

  // Forward pagent "conversion" events to the JENTIS data layer
  window.addEventListener('pagent:event', (e) => {
    const event = e.detail;

    // Store the session start event in case we are running an experiment
    if (event.kind === 'session_start' && event.experiment_id) {
      session = event;
      return;
    }

    // Only track conversions for active experiments
    if (!session || event.kind !== "conversion") return;

    // Prepare the JENTIS queue (it as a simple array on window)
    window._jts = window._jts || [];

    // Push the event object itself
    _jts.push({
      track: 'event', // JENTIS track command
      group: 'generic', // optional grouping
      context: 'pagent', // helps to identify the source
      kind: 'conversion', // helps to identify the event type
      experiment_id: session.experiment_id, // unique identifier of the experiment
      variation_id: session.variation_id, // unique identifier of the variation
      cohort_id: session.cohort_id, // unique identifier of the cohort
      is_control: session.is_control // whether the displayed variation is control
    });

    // Finally submit everything to JENTIS
    _jts.push({ track: 'submit' });
  });
</script>
```

This keeps your implementation lightweight. You only need to listen for pagent events and decide which ones you want to forward. The example above listens exclusively for the `conversion` event and immediately submits it to JENTIS. To forward your own events as well, also match `event.kind === "event"` and pass `event.label` along.
