Skip to main content
Skip table of contents

Iframe Stages


From this document, you’ll know:

  • The different iframe connection stages and their purposes.

  • How you can customize the UI for each stage.

  • At which stage you can start sending messages from the webpage to the Unreal app.

Stage 1. In Queue (stage1_inqueued)

Triggered when the user enters the queue to connect to the app.

CODE
case "stage1_inqueued":
    //add your code here
    break;

Purpose: Show the first loading screen.

You can customize: Queue waiting screen (spinner, estimated wait time, branding).

Stage 2. De-Queued (stage2_deQueued)

Triggered when the user leaves the queue and is about to start app preparation.

CODE
case "stage2_deQueued":
    // loading screen 1 hides
    break;

Purpose: End the queue loading UI.

You can customize: Transition animation from queue to loading phase.

Stage 3. Slot Occupied (stage3_slotOccupied)

Triggered when the server has reserved a slot for the user’s app session.

CODE
case "stage3_slotOccupied":
    // add your code here
    break;

Purpose: Hide queue UI and show app loading UI.

You can customize: Loading animation, progress bar, status messages.

Stage 4. Play Button Showed Up (stage4_playBtnShowedUp)

Triggered when the play button is available to start the Pixel Streaming session.

CODE
case "stage4_playBtnShowedUp":
    loaderStep2.style.visibility = "hidden";
    iframeElem.style.visibility = "visible";
    let playButton = document.getElementById("playButtonParent");
    playButton.click();
    onPlayBtnPressed();
    break;

Purpose: Hide loading, show iframe, automatically click play.

You can customize: Play screen, confirmation message before starting.

Stage 5. Play Button Pressed (stage5_playBtnPressed)

Triggered after the play button is pressed — the app is now running and interactive.

CODE
case "stage5_playBtnPressed":
    sidebar.style.visibility = "visible";
    loaderStep2.style.display = "none";
    iframeElem.style.visibility = "visible";
    $('#iframe_1').focus();
    break;

Purpose: Show sidebar and make iframe interactive.

Important: Only after this stage, you can start sending data from the webpage to the Unreal Engine app.

Other Events

  • ResponseFromUE4 → Receives messages from Unreal Engine. (Triggered whenever UE app sends data to webpage.)

  • QueueNumberUpdated →Shows updated queue position. (E.g., from position 4 → 3 → 2 → 1.)

  • stage3_1_AppAcquiringProgress → Shows download progress (only triggered if the app is not yet downloaded on the streamer machine).

  • stage3_2_AppPreparationProgress → Shows preparation progress (only triggered if the app is being extracted on the streamer machine).

  • isIframe → Sends confirmation that this is inside an iframe.

  • shortCuts → Logs key press shortcuts.

  • Error_Redirect → Handles errors and focuses iframe.

Full Code Example:

CODE
const messageHandler = (event) => {
    const loaderStep1 = document.getElementById("loaderStep1");
    const loaderStep2 = document.getElementById("loaderStep2");
    const loaderStep3 = document.getElementById("loaderStep3");
    const iframeElem = document.getElementById("iframe_1");
    const sidebar = document.getElementById("sidebar");

    console.log("received data event type " + event.data.type);
    switch (event.data.type) {
        case "ResponseFromUE4":
            console.log("UE4->iframe: " + event.data.descriptor);
            myHandleResponseFunction(event.data.descriptor);
            break;

        case "stage1_inqueued":
            loaderStep1.style.visibility = "visible";
            break;

        case "stage2_deQueued":
            // loading screen 1 hides
            break;

        case "stage3_slotOccupied":
            loaderStep1.style.display = "none";
            loaderStep2.style.visibility = "visible";
            break;

        case "stage4_playBtnShowedUp":
            loaderStep2.style.visibility = "hidden";
            iframeElem.style.visibility = "visible";
            let playButton = document.getElementById("playButtonParent");
            playButton.click();
            onPlayBtnPressed();
            break;

        case "stage5_playBtnPressed":
            sidebar.style.visibility = "visible";
            loaderStep2.style.display = "none";
            iframeElem.style.visibility = "visible";
            $('#iframe_1').focus();
            break;

        case "_focus":
            document.getElementById("iframe_1").focus();
            break;

        case "isIframe":
            let obj = { cmd: 'isIframe', value: true };
            document.getElementById("iframe_1").focus();
            document.getElementById("iframe_1").contentWindow.postMessage(JSON.stringify(obj), "*");
            break;

        case "QueueNumberUpdated":
            console.log("QueueNumberUpdated. New queuePosition: " + event.data.queuePosition);
            break;

        case "stage3_1_AppAcquiringProgress":
            console.log("stage3_1_AppAcquiringProgress percent: " + JSON.stringify(event.data.percent));
            break;

        case "stage3_2_AppPreparationProgress":
            console.log("stage3_2_AppPreparationProgress percent: " + JSON.stringify(event.data.percent));
            break;

        case "shortCuts":
            console.log("Key pressed");
            break;

        case "Error_Redirect":
            loaderStep2.style.display = "none";
            iframeElem.style.visibility = "visible";
            $('#iframe_1').focus();
            break;

        default:
            console.error("Unhandled message data type");
            break;
    }
};


Need help?

🛠️ Contact our Support Team

💬 Join the Community on Discord

🆓 Get Started for free

 

Follow us on:

Facebook | GitHub | LinkedIn | YouTube

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.