The outcome: a clean stream that loads fast on cellular, responds to touch, doesn’t bake the device, and survives the iOS Safari quirks that break naive integrations. Streampixel works on mobile via the device browser — Safari on iOS and Chrome on Android. There is no native mobile SDK; everything is the same Web SDK with a different config profile.Documentation Index
Fetch the complete documentation index at: https://docs.streampixel.io/llms.txt
Use this file to discover all available pages before exploring further.
Step 1 — Detect mobile, don’t guess
User-agent sniffing is fragile, but for switching between desktop and mobile config it’s good enough:Step 2 — Mobile-tuned SDK init
touchInput: true— translate browser touch events into Pixel Streaming touch input so Unreal sees taps as taps, not as mouse clicks at (0, 0).startResolutionMobile: '480p'— load fast. Adaptive bitrate negotiates upward as the connection allows.preferredCodec: 'H264'— every mobile decoder has H264 silicon. VP9 software-decodes on most phones and burns CPU.maxBitrate— cap the stream so an over-eager adaptive controller doesn’t try to push 12 Mbps over LTE.forceTurn: true— most carrier NATs block direct WebRTC; TURN relays just work.
Step 3 — Touch UI in Unreal
The browser-sidetouchInput: true flag delivers touch events to Unreal. Whether your Unreal project does anything useful with them depends on what touch UI is built into the project itself.
For projects packaged with on-screen joysticks, on-screen buttons, or other touch HUD, see Hide / unhide touch controls for runtime control of those overlays. Show them when touchInput is active and hide them on desktop.
Step 4 — Bandwidth budget
Plan for the network the user actually has, not the network you wish they had:| Connection | Realistic sustained bitrate | Recommended maxBitrate |
|---|---|---|
| LTE (good signal) | 10–20 Mbps | 4 Mbps |
| LTE (weak / congested) | 1–3 Mbps | 2 Mbps |
| 5G (sub-6) | 50–200 Mbps | 6 Mbps |
| 5G (mmWave) | 500+ Mbps | 8 Mbps |
| Hotel / cafe Wi-Fi | 5–20 Mbps shared | 4 Mbps |
maxBitrate is in bits per second. The 4 Mbps cap above is 4_000_000. Adaptive bitrate will scale down further on bad networks; it will not scale up beyond the cap.
Step 5 — Battery and thermals
A long mobile streaming session is a sustained workload: GPU decode, screen at full brightness, radio active. Phones throttle when they get hot, and a throttled phone produces a worse stream. Things you can do from your application:- Set a sensible AFK timeout. If the user puts the phone down for 30 seconds, Streampixel can disconnect them and free the worker. They can reconnect when they pick it back up.
- Drop FPS targets if your UE project supports it. A console command via
emitConsoleCommand('t.MaxFPS 30')halves render work and saves battery on long-form, low-motion content (configurators, tours). - Honour
prefers-reduced-motionfor any spinner / loader animations on your page.
Step 6 — iOS Safari quirks
iOS has the most edge cases. The big ones:Audio requires a user gesture
iOS will not start playing audio until a tap, click, or other input event. The “Tap to start” overlay in the example above exists to satisfy that requirement. Without it, the stream connects, video plays muted, and audio never starts even afteraudio.play() is called.
Autoplay policies
Even muted autoplay can fail in some Safari configurations, especially with PiP enabled. The Web SDK handles the muted autoplay attribute correctly, but if you wrap it in your own<video> element, set playsinline muted autoplay explicitly.
Tab background
iOS pauses all media playback when the tab backgrounds. Streampixel disconnects after 60 seconds of background; if the user returns sooner, the stream resumes. Beyond 60 seconds, they reconnect (see Troubleshooting — mobile disconnects).Viewport units
100vh does not behave the same on iOS Safari as it does in desktop browsers — the URL bar takes a slice and 100vh doesn’t account for it. Use 100dvh (dynamic viewport height) for full-screen layouts:
Step 7 — Orientation
Most streamed UE projects are designed for landscape. Lock orientation if your project depends on it:lock() method works on Android Chrome but is not supported on iOS Safari, which is why a visual hint is the portable solution.
Gotchas
Pinch-zoom hijacks touch input
Pinch-zoom hijacks touch input
Without the
viewport meta tag pinning user-scalable=no and CSS touch-action: none on the stream container, browser pinch-zoom and double-tap-to-zoom intercept touches before they reach Unreal. The example above sets both.iOS PWA mode strips features
iOS PWA mode strips features
Streams launched from a saved-to-home-screen PWA on iOS run in a stripped-down WebView with stricter autoplay, no PiP, and quirky media handling. Test there explicitly if you support that install path.
Android Chrome address bar resizes the viewport
Android Chrome address bar resizes the viewport
Scrolling on Android Chrome shrinks/expands the URL bar, which resizes the viewport and can trigger video reflow. Using
100dvh and avoiding scroll on the stream page (overscroll-behavior: none) prevents this.Cellular networks often block UDP
Cellular networks often block UDP
Some carriers and corporate cellular gateways block UDP entirely, which kills WebRTC media.
forceTurn: true falls back to TCP via TURN, at the cost of a few ms of latency and slightly higher relay load. Worth it for reach.Android keyboard pushes the layout
Android keyboard pushes the layout
If your stream UI includes a text input (chat, login), opening the soft keyboard reflows the page and can shift the video. Use
position: fixed on the stream container and let the keyboard overlay it instead of resizing.Next steps
Hide / unhide touch controls
Toggle the UE-side touch HUD from your web page.
Performance tuning
Bitrate and codec recipes for every device class.
Resolution settings
Set per-device opening resolution defaults.
Troubleshooting
Mobile disconnects, audio gating, and other common issues.