A real iPhone. In your browser. Now.

simstream runs iOS simulators on real Macs and streams them to a browser tab — hardware-encoded, with your taps and swipes going back the other way. No install, no Xcode, no waiting for a device to free up.

90 seconds, on a real device
press Try it
and drive a live simulator
60 fps
captured at the source, hardware encoded
0 dropped
frames, measured over a live session
0.9 ms
round trip on the selected ICE pair
2.3 GB
per warm device — why switching is instant

Not a screenshot service

The simulator's framebuffer is read where it is drawn and encoded on the same machine. Nothing is recorded, nothing is polled, and no screen-recording permission is ever asked for.

Capture

Straight from the surface

Frames come from the simulator's own IOSurface and go into the Mac's video encoder without a copy. A static screen costs almost nothing; a moving one gets all 60.

Control

Touches, not clicks

Your gestures are replayed with the spacing your finger actually had, so a swipe is a swipe — with the fling velocity iOS expects, not a tap that happened to move.

Delivery

Built for the bad network

WebRTC where it works, and a WebSocket path that still shows a picture on a hotel wifi or a phone on cellular. Bitrate follows the link rather than fighting it.

One call, one simulator

Start a session with a project key, push a build into a session somebody is already watching, and read what it cost. That is the whole surface.

// npm i @palgroup/simstream
const sim = new SimStream({ baseUrl, apiKey });

// a device, waiting in line only if the fleet is full
const session = await sim.startSession({ wait: true });
open(session.url);

// a new build, onto the simulator already on screen
await sim.pushBuild(signedUrl, { version: etag });

// what each session cost, per project
await sim.usage();

Pay for the minutes you use

$0.08per simulator-minute, billed by the second

A session ends two minutes after the last touch, so a tab somebody forgot is not a bill. Usage is recorded per project with the rate that was in force when each session ended — a price change never rewrites what you already used.