# Browser JavaScript commands and events

Look up browser RM commands, identification callbacks, widget controls, data clearing, and rm CustomEvent payloads.

Use the browser API to identify a visitor, control widgets, or respond to RightMessage activity on the current page. Commands use tuples passed to `window.RM.push`. Events use `document.addEventListener`. Neither interface is the local `RM` object available inside a [flow Code node](https://rightmessage.com/help/code-node-javascript-api-reference).

The API requires the [RightMessage installation snippet](https://rightmessage.com/help/everything-you-need-to-know-about-your-rightmessage-tracking-script). These commands act on the current visitor. They do not create or publish project configuration. Publish changes to flows, widgets, or segments before normal visitors use them. Commands that identify a visitor or alter answers can affect personalization and connected-provider activity immediately.

## Queue and return contract

Illustrative queue setup, not executed:

```javascript
window.RM = window.RM || [];
window.RM.push(['trigger', 'wdg_workforge_demo']);
```

Before initialization, `RM` is an array. `push()` returns its new length, not a Promise or a command result. When RightMessage initializes, it processes queued tuples and replaces `push` with a command dispatcher. Calls then execute immediately. Multiple tuples execute in order, and `push` returns the last command's return value.

There is no Promise that represents a previously queued call. `lookup` and `identifyByEmail` support callbacks for results across this boundary. A callback is a success-path callback, not an error-first callback. Use a returned Promise only when your code already knows that the dispatcher is initialized.

Unknown command names have no defined error behavior, and there is no general argument validation. Pass the exact command spelling and IDs from the current project.

## Identification commands

| Tuple                                   | Arguments                                                      | Return after initialization                                                                                               |
| --------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `['lookup', email, callback?]`          | Email string; optional function receiving the lookup result    | Provider lookup Promise. It looks up a contact ID without adopting that identity.                                         |
| `['identify', contactId]`               | Nonempty provider contact ID                                   | Promise resolving after the profile read and derived refresh. It does not return the fetched profile.                     |
| `['identifyByEmail', email, callback?]` | Email string; optional function receiving contact ID or `null` | Promise resolving to the adopted contact ID, or `null` when none is adopted.                                              |
| `['prepopulate']`                       | No arguments                                                   | Promise resolving after a forced integration-profile refresh and derived refresh. It does not return the fetched profile. |

### `lookup`

Without an integration, the command warns and rejects with `'No integration configured'`. With an integration but no email, it returns `undefined`. Other lookup failures follow the provider Promise. The optional callback runs only when that Promise resolves.

A lookup is not contact creation, opt-in, or identification. Its miss result depends on the provider lookup. Use `identifyByEmail` when the goal is to adopt an existing contact.

### `identify`

A nonempty ID becomes the current subscriber identifier before a forced profile read. With no ID argument, the runtime refreshes the current identity rather than clearing it. Without an integration, it warns and returns `undefined`.

The returned Promise settles through the refresh path even when the profile read fails. Resolution is not proof that a valid profile was found. Provider identification events can describe anonymous or failed states too.

### `identifyByEmail`

Missing email rejects with `'Email address required'`. Missing integration rejects with `'No integration configured'`. Lookup errors warn and become `null`. A lookup miss does not replace the existing identity. A newer lookup supersedes an older one, so an old response cannot restore a previous visitor identity.

The command waits for the adopted identity's profile fetch attempt. A contact ID result does not guarantee that every profile field loaded successfully. A callback exception can reject the returned Promise.

Illustrative queued call, not executed:

```javascript
window.RM = window.RM || [];
window.RM.push([
	'identifyByEmail',
	'visitor@example.com',
	(contactId) => {
		console.log(contactId === null ? 'No contact adopted' : 'Contact adopted');
	}
]);
```

An illustrative callback value is `'contact_workforge_42'` when lookup and identity adoption succeed, or `null` when they do not. Identification is not authentication. Never use this result to grant account access.

### `prepopulate`

This forces a refresh of the connected profile and joins compatible in-flight work. Without an integration, it logs a message and returns `undefined`. As with `identify`, Promise resolution is not a provider-success receipt.

## Widget and rendering commands

| Tuple                   | Effect                                                                                                                                              | Return      |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `['trigger', widgetId]` | Requests that the specified widget show. The widget must exist in the loaded configuration.                                                         | `undefined` |
| `['hide', widgetId]`    | Requests that the specified widget hide.                                                                                                            | `undefined` |
| `['personalize']`       | Reconciles current campaign output. Dependencies that are still loading can remain pending. Campaign personalization requires **Scale** or **Pro**. | `undefined` |
| `['reset']`             | Accepts a pending URL change if necessary, refreshes derived sources, and reruns widgets and campaigns.                                             | `undefined` |

Widget IDs are strings such as `wdg_workforge_demo`. Triggering does not return proof of visibility. `personalize` does not republish configuration, reroll unchanged holdbacks, or repeat an unchanged campaign exposure.

Normal SPA routes are observed automatically. A second route hook that calls `reset` is unnecessary. See [Use RightMessage in a single-page application](https://rightmessage.com/help/how-to-use-rightmessage-with-single-page-applications-spas).

## Answers and browser data

| Tuple                          | Effect                                                                                                                                                             | Return                    |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------- |
| `['addSegment', segmentId]`    | Records the exact segment ID as an answer and emits a segmentation refresh. This tuple does not perform name lookup or explicitly clear sibling answers.           | `undefined`               |
| `['removeSegment', segmentId]` | Removes that recorded answer and emits a segmentation refresh.                                                                                                     | `undefined`               |
| `['clearAnswers']`             | Clears recorded segment answers, input values, input parts, and question-sync metadata, then refreshes segmentation.                                               | `undefined`               |
| `['clearAllData']`             | Purges RightMessage browser storage and context cookies, clears identities, answers, profile state, and test or holdback assignments, and refreshes visitor state. | Purge result object below |

A removed answer can still match a segment through its signal rules or connected profile. These commands do not delete segment definitions. Unlike Code-node segment methods, the browser tuples emit refresh events for external callers.

`clearAllData` preserves debugger preferences. It does not delete the email-platform contact, undo completed provider writes, or delete historical server-side analytics. Storage removal is best effort.

Illustrative result shape, not executed:

```json
{
	"localStorageKeys": ["rm_variables", "rmpanda.rightask.answers"],
	"sessionStorageKeys": ["rm_dismissed_widgets"],
	"removedVisitorContextCookie": true
}
```

The arrays list matching keys selected for removal. The cookie boolean indicates that the host was eligible for the context-cookie removal attempt. Neither is proof that the browser accepted every removal.

## DOM CustomEvents

Listeners belong on `document`. Payloads are in `event.detail`. These events report runtime activity, not a transactional provider receipt or a promise of delivery to your listener. Register listeners before the activity you need to observe.

| Event                                 | Detail shape and meaning                                                                                                                                                                                             |
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rm:syncDetails`                      | `{ fields, tags }`. Field entries include `partnerName`, `fieldId`, and `fieldValue`; `tags` is `{ add: [tagId], remove: [tagId] }`. Describes the synchronization pass, which can include queued or skipped fields. |
| `rm:identify`                         | `{ esp, data }`. `esp` is the integration's runtime name; `data` is its visitor context, which can be anonymous.                                                                                                     |
| `rm:segmentation`                     | `{ segmentGroups: { [dimensionId]: { [segmentId]: boolean } } }`. Nested group decisions, not a flat array of active segments.                                                                                       |
| `rm:forced-segment-id`                | `{ segmentId }`. A forced segment ID was read from the runtime's forced-segment context. It can repeat during recalculation.                                                                                         |
| `rm:sources:page-view:save-page-view` | No application detail payload. The runtime is saving a pageview. This is not an analytics-ingestion acknowledgement.                                                                                                 |
| `rm:widget:acceptOffer`               | `{ widgetId, widgetName, offerId, offerName, formData }`. `formData` is the submitted data or `null`. Acceptance does not prove a subsequent provider write succeeded.                                               |
| `rm:widget:inputAnswer`               | `{ widgetId, widgetName, questionId, inputType, inputValue }`. An input question answer.                                                                                                                             |
| `rm:widget:answer`                    | `{ widgetId, widgetName, dimensionId, dimensionName, segmentId, segmentName }`. A segment-choice answer.                                                                                                             |
| `rm:widget:dismissed`                 | `{ widgetId, widgetName, widgetType, flowId }`. `flowId` can be `null`.                                                                                                                                              |
| `rm:widgetUpdated`                    | `{ widgetId, widgetName, currentStep, width, height, top, left }`. Current step and measured widget geometry. The four geometry values are `0` when the widget element cannot be found.                              |

The first five events have `bubbles: true` and `cancelable: true`. The widget events above are dispatched directly on `document` with the default non-bubbling, non-cancelable flags. No listed event provides a supported `preventDefault()` veto over conversions, navigation, or provider writes.

In debugger sessions, RightMessage can record these events as proposed writes rather than dispatching them to your listeners.

Illustrative listener and event detail, not executed:

```javascript
document.addEventListener('rm:widget:answer', (event) => {
	const { dimensionId, segmentId } = event.detail;
	console.log({ dimensionId, segmentId });
});
```

```json
{
	"widgetId": "wdg_workforge_quiz",
	"widgetName": "WorkForge quiz",
	"dimensionId": "dim_workforge_role",
	"dimensionName": "Role",
	"segmentId": "seg_workforge_manager",
	"segmentName": "Manager"
}
```

Avoid forwarding entire event payloads to third-party analytics. Identification and form events can contain email addresses and other personal data.

## Exclude a form from automatic observation

The presence of `data-rm-form-ignore` on a form opts it out of RightMessage's automatic form observer. The value is not interpreted as a boolean, so `data-rm-form-ignore="false"` still opts out.

The form observer is created for a **Popup** widget using **After a form is submitted**. Installing the snippet alone does not enable this observer for every site form. The opt-out applies to that observer, not every identification path. See [Identify visitors automatically](https://rightmessage.com/help/identifying-visitors-automatically) for Email Watcher and other supported methods.

Illustrative markup, not executed:

```html
<form action="https://example.com/search" data-rm-form-ignore>
	<input name="query" type="search">
	<button type="submit">Search WorkForge</button>
</form>
```

This exclusion does not prevent your own JavaScript from calling identification commands. Runtime-owned attributes such as `data-rm-form-id` and `data-rm-question-input` are not substitutes for the opt-out attribute.

## Related implementation guides

- [Use RightMessage in a single-page application](https://rightmessage.com/help/how-to-use-rightmessage-with-single-page-applications-spas) for client-side route changes.
- [Carry visitor context across domains](https://rightmessage.com/help/how-visitor-context-is-preserved-across-different-domains) for link and redirect handoffs between websites.
- [Code node JavaScript API](https://rightmessage.com/help/code-node-javascript-api-reference) for methods available inside a flow rather than the browser command queue.
