Events and API
Listen to N2I session lifecycle events and call the runtime API from an iframe or WebView.
Events
N2I emits events throughout the session lifecycle. Subscribe to them to react to connection state changes, user interactions, and data from the streamed app.
Event Reference
| Event | Detail payload | Description |
|---|---|---|
n2i_connected | — | The session has been allocated and the stream is establishing. Use this to show a loading indicator. |
n2i_ready | — | The stream is active and the first frame has been rendered. Use this to reveal the iframe/WebView to the user. |
n2i_disconnected | { reason, code } | The session has ended. reason: one of api, n2i://close, inactivity, duration, network. code: a WebSocket close code (1000 = normal close, 1006 = abnormal, negative = unknown). Use this to hide the iframe/WebView and show a return-to-menu screen. |
n2i_inactivity_timeout | — | The session ended because the inactivity timer expired. |
n2i_invisibility_timeout | — | The session ended because the invisibility timer expired. |
n2i_status_data | { downBytes, upBytes, nbFrames, networkStatus: { downJitterMs, jitterBufferExpMs, jitterBufferMs } } | Periodic network and rendering statistics since n2i_connected. Useful for displaying connection quality indicators. |
n2i_custom_packet | { type, str, binData } | A custom packet was received from the streamed app. type is an integer identifier; str is string data; binData is a Uint8Array. |
n2i_open_url_notify | <url string> | The streamed app opened a URL with an http:, https:, or n2i-send: scheme. |
n2i_data | { data: <url>, extras: <object> } | The streamed app sent data via the N2I receiver Intent. |
n2i_app_start_end | <package name> | The streamed application was started. |
Receiving Events from an iframe
N2I dispatches events to the parent page via the browser's postMessage API. Each message has the shape:
{ type: "<event-type>", detail: <event-detail> }
window.addEventListener("message", (event) => {
// Always validate the origin
if (event.origin !== "https://project-xyz.k8s.n2i.io") return;
const { type, detail } = event.data ?? {};
switch (type) {
case "n2i_ready":
document.getElementById("n2i-iframe").style.visibility = "visible";
break;
case "n2i_disconnected":
console.log("Session ended:", detail.reason, detail.code);
document.getElementById("n2i-iframe").src = "about:blank";
break;
case "n2i_status_data":
console.log("Frames rendered:", detail.nbFrames);
break;
}
});
Receiving Events from a WebView
Register a JavaScript interface on the WebView under the name n2iWebView. N2I will call onEvent for each event.
private class N2iHandler {
@JavascriptInterface
public void onEvent(String type, String detail) {
// detail is a JSON string for events that carry a payload, null otherwise
Log.d("N2I", "event=" + type + " detail=" + detail);
runOnUiThread(() -> {
switch (type) {
case "n2i_ready":
myWebView.setVisibility(View.VISIBLE);
break;
case "n2i_disconnected":
// parse detail JSON, then navigate away
myWebView.loadUrl("about:blank");
break;
}
});
}
}
myWebView.addJavascriptInterface(new N2iHandler(), "n2iWebView");
API
Use the N2I API to control the streaming session programmatically from your client.
API Reference
| Method | Parameters | Description |
|---|---|---|
connect | — | Connects the streaming session. |
disconnect | — | Disconnects the streaming session cleanly. |
back | — | Sends an Android back-button event to the streamed app. |
sendCustomPacket | type (integer), data (string or Uint8Array) | Sends a custom packet to the streamed app. |
sendDeeplink | app (package name), uri (deeplink URI) | Sends a deeplink to the streamed app. |
startApp | app (package name), uri (deeplink URI, optional), startIntent (JSON intent, optional) | Starts an application on the stream using a deeplink or Intent. |
Calling the API from an iframe
Send a postMessage to the iframe's contentWindow:
const iframe = document.getElementById("n2i-iframe");
iframe.contentWindow.postMessage(
{ type: "<method-name>", detail: <parameters> },
"https://project-xyz.k8s.n2i.io" // use the exact N2I origin, not "*"
);
Examples:
// Send a custom packet
iframe.contentWindow.postMessage(
{ type: "sendCustomPacket", detail: [0x1234, "Hello from client"] },
"https://project-xyz.k8s.n2i.io"
);
// Send a deeplink
iframe.contentWindow.postMessage(
{ type: "sendDeeplink", detail: ["com.example.mygame", "mygame://level/5"] },
"https://project-xyz.k8s.n2i.io"
);
// Disconnect the session
iframe.contentWindow.postMessage(
{ type: "disconnect" },
"https://project-xyz.k8s.n2i.io"
);
Always specify the exact N2I origin as the targetOrigin argument instead of "*". This prevents your messages from being intercepted by other frames.
Calling the API from a WebView
The n2i JavaScript object is available directly in the WebView context.
Android:
myWebView.loadUrl("javascript:n2i.sendCustomPacket(0x1234, 'Hello from client')");
myWebView.loadUrl("javascript:n2i.sendDeeplink('com.example.mygame', 'mygame://level/5')");
myWebView.loadUrl("javascript:n2i.disconnect()");
iOS:
webView.evaluateJavaScript("n2i.sendCustomPacket(0x1234, 'Hello from client')")
webView.evaluateJavaScript("n2i.disconnect()")