Your React Native build is done. Now your whole team can test it in the browser.

If your team ships a React Native app, you already know the build is the easy part. The friction shows up after the build — when everyone who isn’t a mobile developer needs to actually look at it.

The PM wants to compare two versions of a flow. The designer wants to check layout across screen sizes. The backend engineer wants to confirm what the staging build actually does with their API change. And every one of them ends up at the same place:

“Can you install the build on your machine and show me?”

Because the simulator only runs on a developer’s Mac, behind Xcode and Android Studio. So a mobile developer becomes a human deployment pipeline, interrupted a dozen times a day.

We built tapflow — an open-source, self-hosted tool that streams iOS simulators and Android emulators straight to the browser — to get rid of that interruption. This post is the whole picture, told from a React Native team’s point of view.

Why this fits React Native so naturally

tapflow isn’t a React Native tool. It’s framework-agnostic — and that’s exactly why it covers React Native so completely.

tapflow works one layer below the framework. It doesn’t care whether your app was built with RN, Expo, or bare native code. It operates on the built artifact — the .app or .apk — and the simulator running it:

RN / Expo / native        ← your framework
      │ build
      ▼
  .app / .apk              ← tapflow starts here
      │
      ▼
  simulator / emulator  ──stream──►  browser (your whole team)

Since a React Native build compiles down to an ordinary native app, it lands inside tapflow’s umbrella with nothing special required — an Expo/EAS build or a bare RN build, tapflow treats them all as the native artifacts they are. It never needs to know it’s React Native. (More on wiring up EAS below.)

And because React Native teams are cross-platform by nature — one codebase, iOS and Android — the payoff is sharper than for a single-platform native team. One dashboard, both platforms, anyone on the team, no local setup.

npm install -g tapflow
tapflow start
# → http://localhost:4000

That’s the whole install. Anyone opens the dashboard, picks a device, and starts interacting.

Works with Expo — and bare React Native

Turn every EAS build into a browser-based mobile preview.

If you’re on Expo, add one profile to your eas.json:

{
  "build": {
    "tapflow": {
      "ios": { "simulator": true },
      "android": { "buildType": "apk" }
    }
  }
}
eas build --profile tapflow --platform all
# iOS → .tar.gz (simulator .app inside)   ·   Android → .apk

That one profile produces exactly what tapflow runs: for iOS, a simulator build — which EAS hands you as a .tar.gz — not the default device .ipa (which can’t run on the Simulator); for Android, an .apk. tapflow takes both formats as-is, so there’s nothing to repackage:

  .tar.gz (iOS sim) · .apk (Android)
        │  CI uploads it as-is
        ▼
     tapflow
        │
        ▼
  browser preview — whole team, no install

Your CI (or a small webhook receiver) downloads the finished artifact and uploads it to tapflow automatically, so wiring it to an EAS Build webhook turns every green build into a browser-testable preview the whole team can open, before TestFlight or an internal APK share.

On bare React Native, there’s no EAS step to think about: point tapflow at the simulator .app / .apk your existing react-native run-ios or Gradle build already produces.

This is a complement, not a replacement. EAS builds, signs, and ships your app; tapflow slots in right after the build so everyone can see it without installing anything.

Metro stays. This is for the build, not the dev loop

React Native developers will reasonably ask: does this replace Metro / Fast Refresh?

No — and it isn’t trying to. Your inner dev loop (edit → Fast Refresh → repeat on your own machine) stays exactly as it is. tapflow covers the other half: the built artifact that the rest of the team needs to review — the staging build, the EAS build, the “does the sandbox behave right” check.

Metro is for the developer writing the code. tapflow is for the ten other people who need to see the result without becoming React Native developers first.

Why self-hosted (and why we didn’t use a cloud lab)

Cloud simulator services solve the browser-access problem too. We evaluated them seriously before building anything, and stopped at two blockers:

  • Cost. Per-seat, per-minute pricing scales badly for a whole team just reviewing builds.
  • Data. They require uploading your app binary to an external service. For a proprietary app, that’s a non-starter.

tapflow runs on Macs you already own. The architecture keeps everything in your network:

Browser (your team)  ←─ WebSocket ─→  Relay  ←─ WebSocket (outbound) ─→  Mac Agent
                                    (Linux/Mac)                        (iOS · Android)

The Mac Agent connects outbound to the relay, so there’s no firewall or NAT setup. The relay runs on the Mac you already own — or another machine on the same network — so there’s nothing extra to buy, and your app binary and test data stay on infrastructure you control. It’s MIT-licensed and fully self-hosted.

The feature that comes up most in real QA sessions maps directly onto something React Native leans on heavily — deep links.

RN navigation, Linking, notification payloads, OAuth redirects — verifying a specific app state usually means firing a deep link. The old workflow always pulled in a developer: trigger it from their machine, or build a debug menu into the app just for testing.

In tapflow you fire a deep link straight from the QA session toolbar. Hit ⌘K, paste the URL, and it runs on the active device:

Browser ──open-url──► Relay ──open-url──► Mac Agent
                                             │
                          iOS:     xcrun simctl openurl booted 
                          Android: adb shell am start -a VIEW -d 
Browser ◄──open-url:done/error── Relay ◄─────┘

Under the hood it’s a symmetric openUrl(url) on the device interface, so iOS and Android behave the same way and the dashboard shows a toast either way. A PM can now reproduce the exact screen behind a myapp://product/42 link without touching a terminal.

The same session toolbar covers the rest of the repetitive QA actions with keyboard shortcuts:

Shortcut Action
⌘K Open deep link dialog
⌘S Take screenshot
⌘⇧Y Start / stop recording
⌘⇧O Rotate simulator

Screenshots are also exposed as an API, so a designer doing layout review across screen sizes can capture without asking anyone.

Where it’s headed

There’s an experimental MCP server that gives an LLM agent eyes and hands on the simulator — it can see the screen and drive taps directly. It’s opt-in and completely separate from the manual testing path, so it doesn’t change anything above. If that’s interesting, it has its own write-up.

Getting started

npm install -g tapflow
tapflow start

On Expo, produce a tapflow-ready build with the profile from earlier:

eas build --profile tapflow --platform all

Then drop the build in and share the dashboard URL with your team.

If your team ships React Native, the build was never the hard part. Letting everyone see it was. That’s the part tapflow removes.

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

The Demand for Integrating Cybersecurity into Aerospace Quality

Related Posts