Pixel Streaming Pipeline

Streams an Unreal Engine project to any device with a web browser, no powerful local hardware required on the viewer's end. Built as a custom Unreal 4.26 source build for the LiViCi We Won't Forget show in 2020.

Unreal EnginePixel StreamingAWSWebRTCWeb StreamingPipeline ToolTutorial
Role
Technical Artist
Client
Lifelike & Believable
Year
2020-2021
Status
Completed
Type
Streaming Pipeline
The demo from the LinkedIn article and YouTube tutorial: the same Unreal Engine third-person scene running on a PC (top) and streamed live to a phone via Ngrok (bottom right), both controllable simultaneously.
The demo from the LinkedIn article and YouTube tutorial: the same Unreal Engine third-person scene running on a PC (top) and streamed live to a phone via Ngrok (bottom right), both controllable simultaneously.

What it is

A pipeline for streaming an Unreal Engine project to any device with a web browser, with no powerful local hardware needed on the viewer’s end — the server does all the rendering, the browser just handles input and displays the stream. Built as a custom Unreal Engine 4.26 source build with the Pixel Streaming plugin patches applied, plus a configured Node.js signalling server and Ngrok for public-internet exposure.

Built and shipped as Technical Artist at Lifelike & Believable in late 2020 to power the browser-based audience path on the LiViCi We Won’t Forget show. Used in production through 2021. The setup was involved enough that I wrote it up afterwards as a LinkedIn article and a YouTube tutorial so other Unreal users could replicate the same setup, plus a public GitHub gist of free STUN servers.

In short: a viewer on a phone, tablet, or weak laptop opens a URL and plays the same Unreal scene a powerful gaming PC is rendering — same input, same render, just streamed.

The problem

Unreal Engine projects need a powerful GPU to render. A viewer on a phone, tablet, or low-spec laptop can’t run them locally. For LiViCi We Won’t Forget, the show needed a remote audience path that worked on any device — viewers couldn’t be expected to have a VR headset or a gaming PC.

In late 2020, Pixel Streaming wasn’t shipped in the Unreal Engine editor. It existed as a plugin maintained inside Epic’s source tree but wasn’t bundled with public binary releases. Using it meant compiling Unreal from source with the plugin’s patches applied — and then standing up a Node.js signalling server, configuring STUN entries, and exposing the host to the public internet, none of which Epic’s docs walked through end-to-end. This pipeline put all of those pieces together into a repeatable workflow.

What it does

A browser sends inputs (clicks, key presses, touch joysticks on phones) to a packaged Unreal Engine executable running on a host PC. The Unreal process renders the scene and pipes frames back through the Pixel Streaming plugin to a Node.js signalling server, which negotiates a WebRTC connection to the browser. Ngrok tunnels the host’s port out to a public HTTPS URL with no static IP required — the free tier caps at ~40 concurrent users, enough for a curated audience like LiViCi’s.

How the pipeline runs (8 setup steps)

The setup runs in eight stages, from plugin activation through to a publicly-shareable URL. Each step’s how-to lives inside its collapsible below.

Step 1 — Enable the Pixel Streaming plugin in the Unreal project.

Step 1 in detail

Open the Unreal project. Edit > Plugins. Under the Graphics category, find the Pixel Streaming Plugin and check its enabled box. Click Yes to accept the beta-plugin warning, then Restart Now to reload the project with the plugin active.

Step 2 — Configure project settings — touch interface for phone/tablet input + launch parameters for audio and streaming ports.

Step 2 in detail

Project Settings → Engine → Input: check Always Show Touch Interface so the on-screen joysticks appear when the project’s accessed from a phone or tablet.

Editor Preferences → Level Editor → Play → Additional Launch Parameters: set the value to:

-AudioMixer -PixelStreamingIP=localhost -PixelStreamingPort=8888

These params route audio through the AudioMixer (otherwise the stream is silent) and tell Pixel Streaming which host and port to bind to.

Step 3 — Install dependencies — Visual Studio Community 2019 (Game Dev with C++ workload + .NET Framework 4.8 SDK), Node.js.

Step 3 in detail

Visual Studio Community 2019: open the installer (Windows key → “Add or Remove Programs” → find Visual Studio → Modify). Under Workloads, enable Game development with C++. Under Individual components, find and enable the latest .NET Framework SDK (4.8 in 2020). Modify to install. Restart the PC when prompted.

Node.js: download the Windows installer from https://nodejs.org/en/download/ and run it. Default options are fine.

Step 4 — Package the project as a Windows 64-bit executable.

Step 4 in detail

File > Package Project > Windows > Windows (64-bit). Pick a destination folder. The package step compiles the project — depending on size and machine, this can take 30+ minutes.

Step 5 — Edit the executable’s shortcut target with launch parameters for audio + off-screen rendering.

Step 5 in detail

Open the packaged folder, find the .exe inside WindowsNoEditor, right-click → Create shortcut. Right-click the shortcut → Properties → Shortcut tab → Target. After the existing path, add:

 -AudioMixer -PixelStreamingIP=localhost -PixelStreamingPort=8888 -RenderOfScreen

Note the leading space before -AudioMixer — without it, the launch fails. The -RenderOfScreen flag lets the executable run in the background so the host PC can keep doing other work while serving streams.

Step 6 — Configure the signalling server — copy the PixelStreaming folder out of the engine source, edit the STUN entry, paste in the local IPv4 address.

Step 6 in detail (STUN + Public IP edits with screenshots)

Go to the engine install folder: UE_4.26 > Engine > Source > Programs and copy the PixelStreaming folder. Paste it inside the packaged project’s WindowsNoEditor folder.

Open PixelStreaming > WebServers > SignalingWebServer. Make a backup copy of Start_AWS_WithTURN_SignallingServer (just in case). Open the original file in a text editor.

STUN edit. Replace the first + $PublicIp + :19302 reference with a free STUN server. Pick one from my GitHub gist — for example, stun4.l.google.com:19302.

Editing the STUN server entry in the signalling server PowerShell file
Figure 1. Editing the STUN server entry in the signalling server PowerShell file

Public IP edit. Open cmd, type ipconfig, and copy the IPv4 Address value (something like 192.168.x.x on a LAN).

Running ipconfig in cmd to find the local IPv4 address
Figure 2. Running ipconfig in cmd to find the local IPv4 address

Back in the signalling server file, replace the second + $PublicIp + reference with that IP address.

Pasting the IPv4 address into the signalling server PowerShell file
Figure 3. Pasting the IPv4 address into the signalling server PowerShell file

Save the file as Start_AWS_WithTURN_SignallingServer.ps1. Run runAWS_WithTURN.bat to start the signalling server.

Step 7 — Test on the same network — launch the packaged exe, hit the host IP from a browser on any device sharing the LAN.

Step 7 in detail

Launch the packaged executable shortcut from Step 5. The signalling server from Step 6 should be running in the background. From any device on the same LAN — another PC, a phone, a tablet — open a browser and navigate to the host’s IPv4 address.

Signalling server console confirming WebSocket listeners on ports 8888 and 80, HTTP on port 80
Figure 4. Signalling server console confirming WebSocket listeners on ports 8888 and 80, HTTP on port 80

The scene should appear in the browser, interactive. One quality note: running the editor in-place looks pixelated in the stream, but the packaged executable renders cleanly.

Step 8 — Expose to the public internet with Ngrok — authenticate once, run ngrok http 80, share the forwarding URL anywhere.

Step 8 in detail (Ngrok auth + tunnel)

Sign up at https://ngrok.com (I linked mine to GitHub). Download Ngrok for Windows, extract the executable, and place it next to the packaged project.

First-time auth. Open the Ngrok console. From your Ngrok dashboard, copy the ngrok authtoken <key> command and paste it into the console. This writes your auth credentials to the local Ngrok config.

Copying the ngrok authtoken command from the Ngrok dashboard
Figure 5. Copying the ngrok authtoken command from the Ngrok dashboard

Tunnel the port. Pixel Streaming uses port 80, so run:

ngrok http 80

The console shows two Forwarding lines — an HTTP and an HTTPS URL pointing at *.ngrok.io. Share the HTTPS URL with anyone, anywhere. They open it in a browser and they’re inside your Unreal scene.

Ngrok console showing the HTTPS forwarding URL pointed at localhost:80
Figure 6. Ngrok console showing the HTTPS forwarding URL pointed at localhost:80

One gotcha: double-tapping Ctrl+C in the Ngrok console kills the tunnel instead of just copying. If that happens, just re-run ngrok http 80.

How it was used in production

This pipeline powered the browser-based audience path for LiViCi We Won’t Forget (2020 premiere → 2021 ongoing). A viewer with no VR headset and no gaming PC could open a link, see the live circus performance rendered on AWS, and interact in the same multiplayer audience as the VR users and the local-PC users.

The free Ngrok tier’s ~40 concurrent user ceiling was the audience size cap. For LiViCi’s invite-only curated audiences, that was the right ceiling. Scaling further would require a static IP and a paid hosting tier (AWS, GCP, or similar), which the show didn’t need for its scale.

Where it didn’t fit — Virtual Camera attempt

I tried adapting this pipeline for the Versatile Media Virtual Camera workflow — Pixel Streaming the live Unreal viewport to the iPad rig. The pipeline worked, but the latency was too high for fine cinematographic control: framing a shot needs sub-frame motion response, and the WebRTC round-trip plus encode/decode added enough delay that subtle framing felt rubbery. The VCam rig ended up using a dedicated low-latency video transmitter instead. Pixel Streaming is great for audience-facing experiences; not for operator-facing ones where input timing is on the critical path.

What it became — the tutorial

The setup was involved enough — eight steps across two software toolchains, plus a custom signalling-server edit and a Node.js dependency — that I wrote it up afterwards so the next Unreal user trying this in 4.26 wouldn’t have to piece it together themselves:

In retrospect

Unreal Engine 4.27 (mid-2021) shipped Pixel Streaming as a stock plugin bundled with the editor, and Unreal 5.x matured it further. The custom 4.26 source-build approach this pipeline documents is now historical — anyone setting up Pixel Streaming today can skip Steps 3–5 entirely and just enable the bundled plugin. This page is a snapshot of what was needed before Epic built it in.