# Events

> Lifecycle events your page can hook into.

The SDK emits events as the form progresses through its lifecycle. Subscribe with `Maxforms('on', ...)`.

## Event vocabulary

| Event | Payload fields | Fires when |
| --- | --- | --- |
| `maxforms.form.loaded` | `formId, embedId, page` | Form has rendered inside the iframe. |
| `maxforms.form.page_view` | `formId, embedId, page` | User moved to a new page of a multi-page form. |
| `maxforms.form.submitted` | `formId, embedId, submissionId, page` | Submission persisted successfully. |
| `maxforms.form.resize` | `formId, embedId, height` | The form's content height changed (drives dynamic height). |

Those four are the complete set the SDK emits today. `maxforms.form.error`, `maxforms.popup.opened` and `maxforms.popup.closed` are reserved names — they are accepted by `Maxforms('on', ...)` but nothing dispatches them yet, so do not build on them.

## Routing by embedId

When a page hosts multiple embeds of the same form, each gets a unique `embedId` (`mf_1`, `mf_2`, …). Filter on `payload.embedId` if you need to distinguish them.

```js
Maxforms('on', 'maxforms.form.submitted', function (p) {
  if (p.embedId === 'mf_1') {
    analytics.track('Hero form submitted', { formId: p.formId });
  }
});
```

## Security notes

Events arrive over `postMessage`. The SDK validates the origin before dispatching, so events from any window other than `https://form.maxforms.com` are ignored. Your handlers can trust the `payload` object's shape, but **do not** trust `submissionId` for authentication — it's intended as a client-side correlation key, not a credential.

