onEvent (or offEvent to remove a listener). React apps can use useEvent from @dynamic-labs-sdk/react-hooks for a hook with built-in cleanup.
Subscribing
listener is fully typed against the event name: hover over event in your editor to see the payload TypeScript expects.
Authentication state
State-change events fire whenever a top-level field on theDynamicClient changes. They are the primary way to react to login, logout, and JWT refreshes.
| Event | Payload | When it fires |
|---|---|---|
initStatusChanged | { initStatus: 'uninitialized' | 'in-progress' | 'finished' | 'failed' } | Each time client initialization advances. Use 'finished' to know the client is ready. |
userChanged | { user: User | null } | The authenticated user object is set, updated, or cleared (e.g. on logout). |
tokenChanged | { token: string | null } | The JWT changes — on sign in, refresh, or logout. |
sessionExpiresAtChanged | { sessionExpiresAt: Date | null } | Session expiry timestamp updates. |
projectSettingsChanged | { projectSettings: ProjectSettings | null } | Dashboard settings are fetched or refreshed. |
logout | { reason: LogoutReason } (optional) | logout is called. reason is one of 'user-intent', 'token-expired', 'user-deleted', 'device-revoked', 'all-devices-revoked', 'session-refresh-unauthorized', 'user-refresh-failed', 'keychain-migration-failed', 'keychain-key-missing'. |
Wallet accounts and providers
| Event | Payload | When it fires |
|---|---|---|
walletAccountsChanged | { walletAccounts: WalletAccount[] } | A wallet is added, removed, verified, or its primary status changes. |
walletProviderRegistered | { walletProvider: WalletProvider } | A wallet provider is registered (typically when a chain extension loads). |
walletProviderUnregistered | { walletProviderKey: string } | A wallet provider is unregistered. |
walletProviderChanged | { walletProviderKey: string } | A registered provider’s metadata or capabilities change. |
MFA
| Event | Payload | When it fires |
|---|---|---|
mfaTokenChanged | { mfaToken: string | null } | The MFA token is issued, refreshed, or cleared. |
mfaCompletionSuccess | { deviceId?: string; mfaToken?: string } | A user successfully completes an MFA challenge. deviceId is undefined if a recovery code was used. |
mfaCompletionFailure | { deviceId?: string; error: unknown } | An MFA challenge fails verification. |
Device registration
| Event | Payload | When it fires |
|---|---|---|
deviceRegistrationCompleted | (no args) | Device registration completes successfully in the current tab. |
deviceRegistrationCompletedInAnotherTab | (no args) | Device registration completed in another tab — broadcast cross-tab so every tab can refresh state. |
Checkout
| Event | Payload | When it fires |
|---|---|---|
checkoutTransactionExecutionStateChanged | { transactionId: string; previousState: CheckoutExecutionState; newState: CheckoutExecutionState; timestamp: string } | A checkout transaction’s execution state advances (queued, executing, executed, etc.). |
checkoutTransactionSettlementStateChanged | { transactionId: string; previousState: CheckoutSettlementState; newState: CheckoutSettlementState; timestamp: string } | A checkout transaction’s settlement state advances. |
React patterns
UseuseEvent from @dynamic-labs-sdk/react-hooks — it subscribes on mount and cleans up on unmount:
useUser, useWalletAccounts, useInitStatus) — they subscribe to the relevant events internally.
One-time listeners
UseonceEvent for a listener that auto-removes after firing once — useful for waiting on initialization or a single MFA completion.
Type safety
The full event surface is declared globally asDynamicEvents, augmented by each module that emits events. onEvent, offEvent, and onceEvent are generic over keyof DynamicEvents, so the listener signature is inferred from the event name — there is no central enum to keep in sync.