← All posts
Background · 5 min read · 2026-04-18

Why we built DroidFleet

I started DroidFleet after a particularly bad week.

I was shipping an Android app to a small but real audience. The app worked on my Pixel 7. It worked in the emulator. It crashed on a friend's Samsung A-series. I spent four hours debugging the crash with screenshots they sent me over WhatsApp, then another two trying to reproduce it on a borrowed S10 from a colleague. The fix took twelve minutes. The whole loop took six hours.

This is the normal state of mobile testing. Everyone I know has a drawer of phones — old daily drivers, hand-me-downs from family, a few bought specifically for QA — and almost no way to use them as a coordinated test surface. Plug them into USB? Sure, one at a time, hope ADB doesn't drop. Send the APK to your friend? Hope they have time to install it, run it, and tell you the right thing happened. Pay for cloud test farms? They have phones you'll never touch and behaviors that may or may not match the real device.

The middle option that doesn't exist

The market sells you exactly two extremes:

What's missing is the middle: the phones you own, used as a coordinated grid, accessible over the internet, with the speed of local hardware and the convenience of "just hit deploy".

That's the gap DroidFleet fills.

The naïve version (which doesn't work)

Step zero was the obvious thing: write a small server, expose it on my home network, point my phones at it. This works for about six minutes, until:

Anyone who's tried to "just self-host" a developer tool has run this same wall. The phones can't initiate inbound. Your laptop can't accept inbound. So we need a third party.

The relay model

The trick is a tiny stateless relay with a public IP. Both your server and your phones connect outbound to a private "room" on the relay. The relay just forwards messages between them, like a pipe. Neither end opens any inbound port. Everything works on every network.

This is the same pattern Tailscale uses for NAT traversal, that ngrok uses for development tunnels, that Stripe uses for webhook delivery. The relay isn't doing anything clever — it's just there to be reachable from both sides of the NAT chasm.

Once we accepted that this was the architecture, everything else fell into place: pairing becomes a server-minted ID stamped on every message, FCM lets us wake sleeping phones to receive new APKs, the Cloudflared tunnel lets us serve the agent's APK over HTTPS without owning a domain.

The features came from real frustration

Every feature in DroidFleet was, at some point, me getting annoyed at something. A non-exhaustive list:

"Why do I have 17 identical NullPointerException tickets when it's clearly the same crash?" → Stack-trace deduplication.
"Which of these three identical phones on my desk is the one that just installed v2?" → The "ping" feature — vibrate + Toast on demand.
"This regression definitely started in the last commit. But which one?" → Git-SHA stamping on every install session.
"I want to ship v2 to one phone and keep v1 on the others to compare." → A/B rollout cohorts.
"Did v2 get slower? I think it's slower. Maybe." → Cold-start + memory snapshot diffs between sessions.
"Wait, why is the new build hitting an analytics endpoint I didn't add?" → Network traffic recording.

Every one of these existed in some form somewhere — in proprietary tools, in expensive cloud platforms, in academic prototypes. None of them existed together, in a tool you could install in five minutes and run on your own hardware.

Where we go next

iOS is obvious. Test recording / replay is obvious. Bluetooth simulation is less obvious but I want it. SOC 2 is annoying but real customers ask. The roadmap is public and I update it as priorities shift.

For now: I shipped the version of this tool I would have killed for that bad week. If you have phones on a desk, give it five minutes. If you've ever been blocked debugging a phone-specific crash, give it ten.

If it doesn't make your life easier, tell me and I'll figure out why. If it does, tell me that too — that's how I know to keep going.

droidfleet.dev · [email protected]