Skip to main content

Lifecycle Events

The SDK emits lifecycle events during iframe mount/unmount operations and SDK teardown — useful for analytics, debugging, coordinating UI state, and cleanup.

Lifecycle Diagram

Intellirent.init()


┌─────────────────┐
│ SDK Active │◄─────────────────────────────┐
└────────┬────────┘ │
│ │
│ sdk.mount(selector) │
▼ │
┌─────────┐ │
│MOUNTING │ ─── Event emitted │
└────┬────┘ │
│ │
▼ │
┌─────────┐ │
│ MOUNTED │ ─── Event emitted │
└────┬────┘ │
│ │
│ sdk.unmount() │
│ or instance.destroy() │
▼ │
┌───────────┐ │
│UNMOUNTING │ ─── Event emitted │
└─────┬─────┘ │
│ │
▼ │
┌───────────┐ │
│ UNMOUNTED │ ─── Event emitted ───────────────┘
└───────────┘

│ sdk.destroy()

┌───────────┐
│DESTROYING │ ─── Event emitted
└─────┬─────┘
│ (unmounts iframe if mounted)

┌───────────┐
│ DESTROYED │ ─── Event emitted
└───────────┘


SDK Inactive (cannot be reused)

Events Reference

EventWhen EmittedPayload
mountingBefore iframe creation starts{ selector }
mountedAfter iframe is ready and initialized{ selector, instanceId }
unmountingBefore iframe cleanup starts{ selector, instanceId }
unmountedAfter iframe cleanup is complete{ selector, instanceId }
destroyingBefore SDK teardown starts{ hadMountedIframe }
destroyedAfter SDK is fully torn down{ hadMountedIframe }
component_loadedWhen the component's iframe is about to begin loading (before HTML/CSS starts fetching), emitted right after mounting{ component, sessionId, timestamp }
component_readyWhen component is interactive and ready for use{ component, sessionId, timestamp, loadTimeMs }
component_errorWhen a component-level error occurs{ component, sessionId, timestamp, errorCode, errorMessage }
component_destroyedWhen a component is unmounted within the iframe{ component, sessionId, timestamp, durationMs }

Typed Events

Event names are the string literals in the table above, and LifecycleEventMap maps each name to the payload its listener receives. In TypeScript, sdk.on() infers the payload type from the event name, so a listener never needs an explicit annotation.

type LifecycleEventType =
| "mounting"
| "mounted"
| "unmounting"
| "unmounted"
| "destroying"
| "destroyed"
| "component_loaded"
| "component_ready"
| "component_error"
| "component_destroyed";

interface LifecycleEventMap {
mounting: MountEventPayload;
mounted: MountEventPayload;
unmounting: UnmountEventPayload;
unmounted: UnmountEventPayload;
destroying: DestroyEventPayload;
destroyed: DestroyEventPayload;
component_loaded: ComponentLoadedPayload;
component_ready: ComponentReadyPayload;
component_error: ComponentErrorPayload;
component_destroyed: ComponentDestroyedPayload;
}

type LifecycleEventListener<T extends LifecycleEventType> = (
payload: LifecycleEventMap[T],
) => void;
// payload is inferred as MountEventPayload
sdk.on("mounted", ({ selector, instanceId }) => { /* ... */ });

// payload is inferred as ComponentReadyPayload
sdk.on("component_ready", ({ component, loadTimeMs }) => { /* ... */ });

Basic Usage

Subscribing to Events

const sdk = Intellirent.init({
publishableKey: "pk_test_xxx",
userContext: { userId: "user_123", userType: "END_USER" },
});

// Subscribe using event name string
sdk.on("mounted", ({ selector, instanceId }) => {
console.log(`Iframe mounted at ${selector} with id ${instanceId}`);
});

sdk.on("unmounted", ({ selector, instanceId }) => {
console.log(`Iframe unmounted from ${selector}`);
});

// Mount the form (triggers 'mounting' then 'mounted' events)
await sdk.mount("#application-form");

Unsubscribing from Events

There are two ways to unsubscribe:

// Method 1: Use the returned unsubscribe function
const unsubscribe = sdk.on("mounted", (payload) => {
console.log("Mounted:", payload);
});

// Later, when you want to stop listening:
unsubscribe();

// Method 2: Use sdk.off() with the same listener reference
const listener = (payload) => {
console.log("Mounted:", payload);
};

sdk.on("mounted", listener);

// Later:
sdk.off("mounted", listener);

Common Use Cases

Analytics & Tracking

Track widget usage for analytics:

const sdk = Intellirent.init({
publishableKey: "pk_live_xxx",
userContext: { userId: "user_123", userType: "END_USER" },
});

sdk.on("mounted", ({ selector, instanceId }) => {
analytics.track("widget_mounted", {
selector,
instanceId,
timestamp: Date.now(),
});
});

sdk.on("unmounted", ({ selector, instanceId }) => {
analytics.track("widget_unmounted", {
selector,
instanceId,
timestamp: Date.now(),
});
});

Loading States

Show/hide loading indicators:

const sdk = Intellirent.init({
publishableKey: "pk_live_xxx",
userContext: { userId: "user_123", userType: "END_USER" },
});

sdk.on("mounting", ({ selector }) => {
showLoadingSpinner(selector);
});

sdk.on("mounted", ({ selector }) => {
hideLoadingSpinner(selector);
});

React Integration

Use lifecycle events with React's useEffect. The SDK is loaded via <script> tag in your index.html and available as a global:

import { useEffect, useRef, useState } from "react";

function ApplicationWidget({ publishableKey, userId, userType }) {
const sdkRef = useRef(null);
const [isLoading, setIsLoading] = useState(true);
const [isMounted, setIsMounted] = useState(false);

useEffect(() => {
const sdk = Intellirent.init({
publishableKey,
userContext: { userId, userType },
});
sdkRef.current = sdk;

// Track mounting state
sdk.on("mounting", () => setIsLoading(true));
sdk.on("mounted", () => {
setIsLoading(false);
setIsMounted(true);
});
sdk.on("unmounted", () => setIsMounted(false));

// Mount the widget
sdk.mount("#widget-container");

// Cleanup on unmount
return () => {
sdk.destroy();
};
}, [publishableKey]);

return (
<div>
{isLoading && <LoadingSpinner />}
<div id="widget-container" style={{ opacity: isMounted ? 1 : 0 }} />
</div>
);
}

Cleanup Verification

Ensure proper cleanup in tests or debugging:

const sdk = Intellirent.init({
publishableKey: "pk_test_xxx",
userContext: { userId: "user_123", userType: "END_USER" },
});

let wasUnmounted = false;

sdk.on("unmounted", () => {
wasUnmounted = true;
console.log("Iframe was properly unmounted");
});

sdk.on("destroyed", ({ hadMountedIframe }) => {
console.log(`SDK destroyed. Had mounted iframe: ${hadMountedIframe}`);

if (hadMountedIframe && !wasUnmounted) {
console.warn(
"Cleanup issue - iframe was mounted but unmount event not received",
);
}
});

// Mount the form
await sdk.mount("#application-form");

// Full teardown
sdk.destroy();
// Logs: "Iframe was properly unmounted"
// Logs: "SDK destroyed. Had mounted iframe: true"

SDK Destruction

After calling sdk.destroy(), the SDK instance cannot be reused:

const sdk = Intellirent.init({
publishableKey: "pk_test_xxx",
userContext: { userId: "user_123", userType: "END_USER" },
});

await sdk.mount("#container");
sdk.destroy();

// This will throw an error:
try {
await sdk.mount("#another-container");
} catch (error) {
console.error(error.message);
// "SDK has been destroyed. Create a new instance with Intellirent.init()"
}

// Create a new instance if needed:
const newSdk = Intellirent.init({
publishableKey: "pk_test_xxx",
userContext: { userId: "user_123", userType: "END_USER" },
});
await newSdk.mount("#another-container"); // Works fine

Event Payload Reference

MountEventPayload

interface MountEventPayload {
/** CSS selector where iframe is being mounted */
selector: string;
/** Instance ID (only available in 'mounted' event) */
instanceId?: string;
}

UnmountEventPayload

interface UnmountEventPayload {
/** CSS selector of the unmounted iframe */
selector: string;
/** Instance ID that was unmounted */
instanceId: string;
}

DestroyEventPayload

interface DestroyEventPayload {
/** Whether an iframe was mounted when destroy was called */
hadMountedIframe: boolean;
}

ComponentLoadedPayload

interface ComponentLoadedPayload {
component: string; // Component type (e.g., 'consumer_screening')
sessionId: string; // Per-mount correlation ID (sess_<12 hex chars>); not IframeInstance.id/instanceId
timestamp: string; // ISO 8601 timestamp
}

ComponentReadyPayload

interface ComponentReadyPayload {
component: string; // Component type (e.g., 'consumer_screening')
sessionId: string; // Per-mount correlation ID (sess_<12 hex chars>); not IframeInstance.id/instanceId
timestamp: string; // ISO 8601 timestamp
loadTimeMs: number; // Time from component_loaded (iframe load starting) to component_ready in ms — includes iframe creation, not just HTML/CSS fetch time
}

ComponentErrorPayload

interface ComponentErrorPayload {
component: string; // Component type (e.g., 'consumer_screening')
sessionId: string; // Per-mount correlation ID (sess_<12 hex chars>); not IframeInstance.id/instanceId
timestamp: string; // ISO 8601 timestamp
errorCode: string; // Error code
errorMessage: string; // Human-readable error message
}

ComponentDestroyedPayload

interface ComponentDestroyedPayload {
component: string; // Component type (e.g., 'consumer_screening')
sessionId: string; // Per-mount correlation ID (sess_<12 hex chars>); not IframeInstance.id/instanceId
timestamp: string; // ISO 8601 timestamp
durationMs: number; // Total time the component was alive in ms
}

Best Practices

  1. Always clean up: Call sdk.destroy() when your application/component unmounts to prevent memory leaks.

  2. Use unsubscribe functions: Store and call unsubscribe functions if you need to remove listeners before SDK destruction.

  3. Handle errors in listeners: The SDK catches errors thrown in event listeners to prevent breaking functionality, but you should still handle errors appropriately.

  4. Unmount before remounting: Call sdk.unmount() before mounting to a different container.

  5. Reinitialize after destroy: Once destroyed, an SDK instance cannot be reused. Call Intellirent.init() again if needed.

Next Steps