Widget events
Listen for what the widget does, from actions shown to CTA clicks, dismissals and redirects, and forward them to your own analytics.
onReady
GeoEngage.onReady(callback: (ge: GeoEngage) => void): void
Calls callback once, when the widget has started and applied your rules, and hands it GeoEngage itself: the same object as window.GeoEngage. If the widget is already ready, it runs straight away, so it can't be missed however late your code asks. It always runs just after the onReady(...) line rather than inside it, so the code you write after that line runs first either way.
GeoEngage.onReady((ge) => {
const { country } = ge.getLocation();
console.log(`GeoEngage ${ge.version} for a visitor in ${country ?? 'an unknown country'}`);
});
getLocation() is never null here. When nobody could place the visitor, it returns { source: 'unknown', timezone }.
- In consent mode it runs once the visitor has accepted, and not at all if they don't.
- It runs once per page load. In a single-page app a route change doesn't run it again;
geoengage:route-change is for that.
- A callback that throws doesn't stop the others, or the widget. With
data-debug="true" the error is logged.
onAction
GeoEngage.onAction(callback): () => void
GeoEngage.onAction(type: string, callback): () => void
GeoEngage.onAction(filter: { type?, rule?, actionType? }, callback): () => void
Calls callback whenever a rule's action does something: appears, gets clicked, closes. Narrow it down by event type, by a rule's name as it appears in your dashboard, by action type, or any combination. Returns a function that stops listening.
// Everything
GeoEngage.onAction((event) => console.log(event.type, event.detail));
// One event type
GeoEngage.onAction('cta-click', ({ detail }) => {
console.log(`${detail.ruleName}: ${detail.ctaText}`);
});
// One rule, by its name in the dashboard
GeoEngage.onAction({ rule: 'Black Friday popup' }, ({ type, detail }) => {
if (type === 'rating-submitted') console.log('Rated', detail.ratingValue);
});
// Stop listening
const stop = GeoEngage.onAction({ type: 'dismissed', actionType: 'show_popup' }, handleDismiss);
stop();
Event types
type | When |
|---|
shown | Something appears: a popup, banner, sticky bar, notification, rating, countdown and so on. |
cta-click | The visitor clicks the main button. |
secondary-cta-click | The visitor clicks the secondary button. |
dismissed | The visitor closes it, with the close button, a click outside it or Escape. |
auto-closed | It closes itself when its display time runs out. |
rating-submitted | The visitor submits a rating. |
redirect | A Redirect to URL action is about to leave the page. Fired before leaving, so your own tracking still runs. |
replaced-text | A Replace Text action changed an element's text. |
swapped-image | A Swap Image action changed an image. |
inserted-html | An Insert HTML action added content. |
set-class | A Set Class action changed an element's classes. |
set-style | A Set Style action changed an element's styles. |
form-prefilled | A Prefill Form action filled in form fields. |
hidden-element | A Hide Element action hid an element. |
custom-js-executed | A Custom JavaScript action ran. |
The event object
{
type: 'cta-click',
detail: {
ruleId: '3f1c2a…',
ruleName: 'Black Friday popup',
actionType: 'show_popup',
variant: null,
timestamp: 1767225600000,
// Extra fields for this type:
ctaText: 'Shop now',
ctaUrl: 'https://example.com/sale',
},
}
variant is the variant's name for a rule with variants, and null otherwise. Some types add fields:
| Type | Extra fields |
|---|
cta-click, secondary-cta-click | ctaText, and ctaUrl when the button links somewhere |
rating-submitted | ratingValue, ratingType, maxValue, feedback |
redirect | redirectUrl |
inserted-html | target, position |
form-prefilled | target, filled (how many fields were filled) |
replaced-text, swapped-image, set-class, set-style, hidden-element | target, the element's selector |
The compliance banner's Accept button is a cta-click with consent: 'accepted'.
Sending actions to Google Analytics
Forward every action to Google Tag Manager's data layer, from the first page load on:
<script>
window.addEventListener('geoengage:action', (event) => {
const { type, detail } = event.detail;
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: `geoengage_${type.replace(/-/g, '_')}`,
geoengage_rule: detail.ruleName,
geoengage_action: detail.actionType,
});
});
</script>
onEvent
GeoEngage.onEvent(callback: (event) => void): () => void
Calls callback with every analytics event the widget records: page views, clicks, scroll depth, your custom events. It fires often, so keep the callback light. Returns a function that stops listening.
onExitIntent
GeoEngage.onExitIntent(callback: () => void): () => void
Calls callback when the visitor's pointer leaves the window through the top edge, the usual sign that they're heading for another tab or the address bar. Useful for a last-chance offer from your own code rather than from a rule. Desktop only: phones have no pointer to leave. Returns a function that stops listening.
DOM events
The widget also dispatches these events on window, for tools that can't call the methods, such as a tag manager, and for code that runs before the tag. An event only reaches the listeners that exist when it happens: a geoengage:ready listener added after the widget is ready never runs. Use the methods above wherever you can.
| Event | event.detail | When |
|---|
geoengage:ready | GeoEngage itself, as onReady gets it | The widget has started and applied your rules. |
geoengage:action | { type, detail } | The same events as onAction. |
geoengage:event | The event | The same events as onEvent. |
geoengage:exit-intent | — | The same moment as onExitIntent. |
geoengage:route-change | { url } | A single-page-app route change was handled. |
geoengage:awaiting-consent | { version } | Consent mode is waiting for the visitor. |
geoengage:consent-unavailable | { reason, version } | Consent mode has no way to ask. See Consent mode. |
geoengage:consent-granted | { version } | grantConsent() has started the widget. |
geoengage:consent-revoked | { version } | revokeConsent() was called. |
// In a script that may run before the tag. Anywhere else, use GeoEngage.onReady.
window.addEventListener('geoengage:ready', (event) => {
const ge = event.detail; // GeoEngage itself
console.log(`GeoEngage ${ge.version} is running for a visitor in ${ge.getLocation().country ?? 'an unknown country'}`);
});