{"id":50017684,"url":"https://github.com/jo-duchan/tapflow","last_synced_at":"2026-06-13T05:01:06.022Z","repository":{"id":358700081,"uuid":"1232101800","full_name":"jo-duchan/tapflow","owner":"jo-duchan","description":"Self-hosted iOS \u0026 Android simulator streaming for the whole team","archived":false,"fork":false,"pushed_at":"2026-06-10T08:19:06.000Z","size":23406,"stargazers_count":45,"open_issues_count":15,"forks_count":4,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T08:23:07.866Z","etag":null,"topics":["android","android-emulator","app-testing","appetize-alternative","browserstack-alternative","developer-tools","emulator","flutter","ios","ios-simulator","macos","mcp","mobile-qa","mobile-testing","open-source","qa-tools","react-native","self-hosted","simulator","testing"],"latest_commit_sha":null,"homepage":"https://www.tapflow.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jo-duchan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-07T15:34:29.000Z","updated_at":"2026-06-10T08:19:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jo-duchan/tapflow","commit_stats":null,"previous_names":["jo-duchan/tapflow"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/jo-duchan/tapflow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jo-duchan%2Ftapflow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jo-duchan%2Ftapflow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jo-duchan%2Ftapflow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jo-duchan%2Ftapflow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jo-duchan","download_url":"https://codeload.github.com/jo-duchan/tapflow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jo-duchan%2Ftapflow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34272603,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-emulator","app-testing","appetize-alternative","browserstack-alternative","developer-tools","emulator","flutter","ios","ios-simulator","macos","mcp","mobile-qa","mobile-testing","open-source","qa-tools","react-native","self-hosted","simulator","testing"],"created_at":"2026-05-20T05:13:05.330Z","updated_at":"2026-06-13T05:01:05.984Z","avatar_url":"https://github.com/jo-duchan.png","language":"TypeScript","funding_links":[],"categories":["Software"],"sub_categories":["UI \u0026 End-to-End Testing"],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"docs/public/logo-hero.svg\" height=\"72\" alt=\"tapflow\" /\u003e\n\n  \u003ch3\u003eA self-hosted Appetize / BrowserStack alternative for mobile QA teams\u003c/h3\u003e\n\n  \u003cp\u003e\n    Run iOS simulators and Android emulators in any browser — no toolchain setup, no device pool, no cloud uploads.\u003cbr /\u003e\n    Your builds, streams, and recordings stay on infrastructure you control.\n  \u003c/p\u003e\n\n  \u003cp\u003e\n    \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"MIT License\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://nodejs.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/node-%3E%3D20-brightgreen\" alt=\"Node.js ≥ 20\" /\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/platform-macOS%20agent-lightgrey\" alt=\"macOS Agent\" /\u003e\n    \u003ca href=\"https://github.com/jo-duchan/tapflow/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/jo-duchan/tapflow?include_prereleases\u0026sort=semver\" alt=\"Latest release\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/jo-duchan/tapflow/commits/main\"\u003e\u003cimg src=\"https://img.shields.io/github/last-commit/jo-duchan/tapflow\" alt=\"Last commit\" /\u003e\u003c/a\u003e\n    \u003ca href=\"ROADMAP.md\"\u003e\u003cimg src=\"https://img.shields.io/badge/roadmap-v0.x→v1.0-blueviolet\" alt=\"Roadmap\" /\u003e\u003c/a\u003e\n  \u003c/p\u003e\n\n  \u003cp\u003e\n    \u003ca href=\"https://www.tapflow.dev\"\u003e📖 Docs\u003c/a\u003e\n    \u0026nbsp;·\u0026nbsp;\n    \u003ca href=\"https://www.tapflow.dev/guide/getting-started\"\u003e🚀 Quick Start\u003c/a\u003e\n    \u0026nbsp;·\u0026nbsp;\n    \u003ca href=\"https://www.tapflow.dev/guide/introduction\"\u003e🎥 Demo\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\u003cvideo src=\"https://github.com/user-attachments/assets/75652346-93cb-4261-9210-6a24b883d44a\" controls width=\"100%\"\u003e\u003c/video\u003e\n\n\u003e **v0.x**: tapflow is under active development. Breaking changes may appear in minor versions until v1.0.0. See [ROADMAP](./ROADMAP.md) for the full plan.\n\n---\n\n## Why tapflow?\n\nMobile QA usually depends on access to simulators, emulators, or physical devices — and that access is uneven across a team.\n\nFor mobile developers it means opening Xcode or Android Studio on a Mac. For everyone else, it often means asking a mobile developer every single time:\n\n\u003e **Backend developer** — \"How do I install the sandbox build to check what was deployed?\"\n\u003e\n\u003e **Product manager** — \"I keep installing and removing versions just to compare behavior.\"\n\u003e\n\u003e **Designer** — \"I need to check the layout across screen sizes, but I don't have the right devices.\"\n\nPhysical devices add their own overhead — OS-version coverage, availability, charging, storage, handoff. Cloud simulator services solve access, but they require uploading internal builds to a third-party service and paying for remote devices while your own Macs can already run the same simulators.\n\nWe hit this exact problem, so we built tapflow.\n\n| Solution | The catch |\n|----------|-----------|\n| Appetize / BrowserStack | Recurring cost — and app builds are uploaded to a third-party cloud |\n| Physical devices | Cost, availability, OS coverage, management overhead |\n| Xcode / Android Studio | Each teammate needs a Mac and a full mobile toolchain |\n| **tapflow** | Reuse your own Macs — data stays on infrastructure you control, and the whole team does QA from a browser |\n\n## What tapflow does\n\ntapflow connects three parts:\n\n1. A **self-hosted relay** server (Linux or Mac)\n2. A **macOS agent** that drives iOS simulators and Android emulators\n3. A **browser dashboard** for the rest of the team\n\nThe agent connects outbound to the relay. Teammates open the dashboard, pick an available device, and interact with it remotely — while the simulators and emulators keep running on your own Macs.\n\n## What tapflow is not\n\ntapflow doesn't replace native mobile development tools. Mobile developers still use Xcode, Android Studio, and their build tooling. tapflow makes the *running* simulators and emulators accessible to the rest of the team through a browser — it isn't an automation framework or a device farm.\n\n## How it works\n\n```\nBrowser (your team)  ←─ WebSocket ─→  Relay Server  ←─ WebSocket (outbound) ─→  Mac Agent\n                                    (Linux / Mac)                           (iOS · Android)\n```\n\n1. The **Mac Agent** connects *outbound* to the relay — no inbound firewall rules needed.\n2. Anyone on the team opens the **dashboard** in any browser and sees all available devices.\n3. Touch events are forwarded in real time; the screen streams back to the browser.\n4. The **relay** also serves the dashboard SPA on the same port — no separate web server needed.\n\n## Quick Start\n\n### 1. Install\n\n```sh\nnpm install -g tapflow\n# or: yarn global add tapflow  |  pnpm add -g tapflow\n```\n\n### 2. Start relay + agent\n\n```sh\ntapflow start\n# ✓ Relay started on http://localhost:4000\n# ✓ iOS Agent connected (3 simulators available)\n```\n\nThis starts both the relay and the agent on the same Mac (local mode).\n\n### 3. Create the first admin account\n\nOpen `http://localhost:4000` in your browser. tapflow redirects you to `/setup` to create the admin account.\n\n\u003e **Headless server?** Use `tapflow admin init` to create the admin account via CLI instead.\n\n### 4. Open the dashboard\n\nNavigate to `http://localhost:4000` and sign in with the account you just created.\n\n\u003e **Having issues?** Run `tapflow doctor` to auto-diagnose Node.js, the iOS toolchain, `adb`, and other prerequisites.\n\n## Requirements\n\n| Component | Requirements |\n|-----------|-------------|\n| **Relay server** | Node.js ≥ 20, any OS (Linux/macOS), ~512 MB RAM |\n| **iOS Agent** | macOS, Xcode with the iOS Simulator runtime, Node.js ≥ 20 |\n| **Android Agent** | macOS, Android SDK (`adb` in `$PATH` or `$ANDROID_HOME` set), an AVD with `google_apis/arm64-v8a` (android-34), Node.js ≥ 20 |\n| **Browser (QA)** | Any modern browser — Chrome, Firefox, Safari, Edge |\n\n\u003e Agents run on **macOS only** (they drive the iOS Simulator and Android emulator on a Mac). The relay runs anywhere.\n\n## Features\n\n- **No mobile toolchain for QA users** — teammates test from a browser without installing Xcode, Android Studio, or local simulator tooling.\n- **Self-hosted by default** — app builds, device streams, recordings, and account data stay on infrastructure you control.\n- **Use your existing Mac setup** — run agents on Macs that already have the iOS Simulator or Android emulator available.\n- **API-first** — REST endpoints and Personal Access Tokens support CI/CD and AI-agent workflows.\n\nWhat's included:\n\n- **Browser streaming** — iOS \u0026 Android at ~30 fps, no extra app on the device. Both stream H.264 through a 2-tier decoder (WebCodecs on secure contexts, WASM/tinyh264 on plain HTTP), which removes the media-element buffer from the decode path. Resolution adapts to the connection — native on a secure context, downscaled on plain-HTTP LAN.\u003csup\u003e[1](#latency-note)\u003c/sup\u003e\n- **Codec fallback** — the stream negotiates the codec per client and falls back to JPEG when a hardware or WASM decoder isn't available, so older browsers still work.\n- **Touch, swipe \u0026 pinch** — real-time input forwarded to the simulator or emulator.\n- **Deeplink toolbar** — open supported deeplinks directly from the QA toolbar.\n- **Keyboard shortcuts** — trigger simulator toolbar actions from the keyboard.\n- **App Center** — upload `.app.zip` / `.apk` and track builds by status (Backlog / In Progress / Done / Rejected).\n- **Session recordings** — record and share QA sessions, kept on the relay for ~72 hours, then purged automatically.\n- **Screenshot REST endpoint** — `GET /api/v1/sessions/:sessionId/screenshot` for CI and AI agents.\n- **Mac resource monitoring** — CPU \u0026 RAM per agent, to spot overloaded hosts before assigning sessions.\n- **Team management** — invite links, roles (Admin / Developer / QA / Viewer), and Personal Access Tokens.\n- **MCP Server** *(experimental)* — `@tapflowio/mcp-server` lets Claude Code and other LLM agents control simulators as native tools.\n\n\u003ca name=\"latency-note\"\u003e\u003c/a\u003e\n\u003e \u003csup\u003e1\u003c/sup\u003e On a real LAN, decode-to-present measures in the low tens of milliseconds (p50 ~11–17 ms with the WASM software decoder; faster with WebCodecs on HTTPS); end-to-end \"glass-to-glass\" latency adds your network's round trip on top. See the [performance \u0026 latency reference](https://www.tapflow.dev/reference/performance) for the full measurements, conditions, and known limitations.\n\n## Security \u0026 Privacy\n\ntapflow is self-hosted by design — build files, device streams, and session recordings stay on infrastructure you control, never sent to a third-party service.\n\n| Data | Where it stays |\n|------|----------------|\n| App binaries (`.app.zip` / `.apk`) | Relay storage |\n| Device streams (video · touch) | The relay ↔ browser path you host |\n| Session recordings | Relay storage; expire after 72h, then purged |\n| Account \u0026 team data | The relay's SQLite DB |\n| Third-party simulator cloud | Not required |\n\n- **LAN-first** — the agent ↔ relay leg is internal traffic; the device stream never transits a third party.\n- **PAT + roles** — Personal Access Tokens carry scopes (e.g. `builds:write` for CI uploads), and team roles (Admin / Developer / QA / Viewer) govern dashboard access.\n\nFound a vulnerability? See [SECURITY.md](SECURITY.md). For the full model, read [Security \u0026 Privacy](https://www.tapflow.dev/guide/security).\n\n## Self-Hosting\n\n### Local (single Mac)\n\nRelay and agent on the same machine — ideal for a single developer or small team.\n\n```sh\ntapflow start\n```\n\n### Team (separate relay server)\n\nRun the relay on a Linux server or dedicated Mac. Each Mac with simulators runs the agent.\n\n**Relay server:**\n\n```sh\n# Recommended: PM2 for automatic restarts\nnpm install -g pm2 tapflow\nJWT_SECRET=$(openssl rand -hex 32) pm2 start tapflow --name relay -- relay start\npm2 save \u0026\u0026 pm2 startup\n```\n\n**Each Mac agent:**\n\n```sh\ntapflow agent start --relay wss://your-relay-url\n```\n\n\u003e For nginx / Caddy reverse proxy setup and external access, see [Self-Hosting the Relay](https://www.tapflow.dev/guide/self-hosting).\n\n## CLI Reference\n\n| Command | Description |\n|---------|-------------|\n| `tapflow start` | Start relay + agent together (local mode) |\n| `tapflow relay start` | Start relay only |\n| `tapflow agent start --relay \u003curl\u003e` | Start agent and connect to a relay |\n| `tapflow init` | Scaffold `tapflow.config.json` |\n| `tapflow admin init` | Create the first admin account (CLI fallback) |\n| `tapflow doctor` | Diagnose environment (Node, iOS toolchain, adb…) |\n| `tapflow devices` | List available simulators and emulators |\n| `tapflow boot \u003cname\\|udid\u003e` | Boot a simulator or emulator |\n| `tapflow status` | Show connected agents, devices, active sessions |\n| `tapflow reset` | Shut down all simulators and emulators |\n| `tapflow logs` | Show recent relay log entries |\n\nFull reference → [CLI docs](https://www.tapflow.dev/reference/cli)\n\n## Documentation\n\n**[www.tapflow.dev](https://www.tapflow.dev)**\n\n**Getting Started**\n- [Introduction](https://www.tapflow.dev/guide/introduction)\n- [Quick Start](https://www.tapflow.dev/guide/getting-started)\n- [Requirements](https://www.tapflow.dev/guide/requirements)\n\n**Setup**\n- [Self-Hosting the Relay](https://www.tapflow.dev/guide/self-hosting)\n- [Security \u0026 Privacy](https://www.tapflow.dev/guide/security)\n- [Agent Setup](https://www.tapflow.dev/guide/agent)\n- [Uploading Builds (CI/CD)](https://www.tapflow.dev/guide/upload-builds)\n- [Scaling Mac Resources](https://www.tapflow.dev/guide/scaling)\n\n**Dashboard**\n- [First-time Setup](https://www.tapflow.dev/dashboard/setup)\n- [Dashboard Overview](https://www.tapflow.dev/dashboard/overview)\n\n**AI Agent**\n- [MCP Server](https://www.tapflow.dev/guide/mcp-server) *(experimental)*\n\n**Reference**\n- [CLI Reference](https://www.tapflow.dev/reference/cli)\n- [Configuration](https://www.tapflow.dev/reference/configuration)\n- [REST API](https://www.tapflow.dev/reference/api)\n\n**[Troubleshooting](https://www.tapflow.dev/guide/troubleshooting)**\n\n## Contributing\n\ntapflow is actively developed and PRs are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for branch strategy, commit conventions, and an architecture overview. For deep dives, the [contributor notes](CONTRIBUTING.md#technical-internals) cover the SimulatorKit reverse-engineering and the streaming render pipeline.\n\n**Requirements**: Node.js ≥ 20, pnpm ≥ 9\n\n```sh\ngit clone https://github.com/jo-duchan/tapflow.git\ncd tapflow\npnpm install\npnpm dev\n```\n\n## License\n\n[MIT](LICENSE) — Copyright © 2026-present tapflow contributors\n\n\u003e tapflow bundles [scrcpy-server](https://github.com/Genymobile/scrcpy) (Apache-2.0) for Android screen streaming. See [NOTICE](NOTICE) for full attribution.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjo-duchan%2Ftapflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjo-duchan%2Ftapflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjo-duchan%2Ftapflow/lists"}