React Native TV · Beta
Buoy for React Native TV: headless devtools for Apple TV & Android TV (beta)
Updated August 2026
Install
There is no separate TV SDK. Install Buoy the way you would in any React Native app, and mount it headless:
import { FloatingDevTools } from "@buoy-gg/core";
export default function App() {
return (
<>
{/* your app */}
<FloatingDevTools headless /> {/* TV apps run headless — no bubble */}
</>
);
}headless mounts every installed tool's sync adapter plus the route, console and store instrumentation, and renders no on-device UI at all — no bubble, no dial, no overlays. It is not a TV-specific flag; it is the same mode Buoy already shipped for field builds where only the desktop should see the session.
Requires react-native-tvos and the New Architecture. Buoy adds no native dependencies, so adding it to a TV app needs only a Metro restart — no pods, no gradle changes, no prebuild. An Android TV emulator needs one line to reach the desktop broker:
adb -s <serial> reverse tcp:42831 tcp:42831Why there is no floating menu on TV
A TV has no touch, so a draggable bubble is not merely awkward — it is unreachable. But rendering nothing is also the correct call, not just the easy one.
On Android TV, any focusable view inside an overlay becomes a D-pad stop in the host app's focus order. pointerEvents="box-none" gates touch and does nothing for the focus engine, so an on-device Buoy overlay would inject invisible focus stops into the very navigation it is supposed to be testing. A debugging tool that changes what it measures is worse than no tool.
Buoy's inertness on TV was measured, not assumed: an identical press sequence produces an identical focus order with the tools attached and with them removed.
Two tools that exist because of TV
TV bugs are the ones nobody can describe. "It gets stuck down there." "The highlight just disappears." "You can see that button, but you can't get to it." Both tools turn that into a record.
TV Remote
Press the D-pad, Select, Menu, holds, media keys and typed text from Buoy Desktop — then record what you pressed as a macro and replay it, step by step, with each step reporting whether the app actually received the press.
npm i @buoy-gg/tv-remote
Focus Inspector
Every focus move with the direction that caused it, the full focusable inventory in reading order, and flags for the three ways TV focus breaks: it gets stuck, it vanishes, or an element is never reached.
npm i @buoy-gg/focus-inspector
Full setup for each lives in the TV Remote and Focus Inspector docs, and the whole TV flow is in the TV guide.
Presses come from your Mac, not from inside the app
Buoy Desktop injects presses with adb shell input keyevent for Android TV and idb ui key for the Apple TV simulator. Both travel the platform's real input pipeline, so a press moves focus through the same engine a physical remote drives. The package you install only observes — it reports which events your app actually received, which is what lets a replay tell "the app handled that" apart from "something swallowed it."
Nothing is synthesized in-process, deliberately: on tvOS an app can fire the JS key event without moving focus, or move focus without firing the event — each is half a press, and the missing half is the half QA cares about. On Android, directional focus for unconsumed D-pad keys is resolved above the Activity, so an in-process dispatch would fire JS events without moving focus on exactly the screens that are broken.
What works where
Being exact about targets matters more on TV than anywhere else, because one of them cannot be driven at all:
| Target | Capture | Replay presses | How |
|---|---|---|---|
| Android TV emulator | Yes | Yes | adb shell input keyevent |
| Android TV device | Yes | Yes | adb connect <ip>:5555 |
| Apple TV simulator | Yes | No media keys | idb ui key |
| Apple TV device | Yes | No | Record only — no supported host-side injection exists |
Because capture is pure JavaScript, recording works everywhere, including retail hardware. That gives you the record-on-retail workflow: a tester presses the physical remote on a rack device, the macro is built from the app's own event stream, and replay then runs against emulators and simulators.
Injection needs adb (Android SDK platform-tools) and, for the Apple TV simulator, idb, which does not ship with Xcode — brew install idb-companion plus pipx install fb-idb. Without it the Apple TV lane is disabled and the panel says so.
The rest of the suite comes along
None of the tools below needed TV-specific code — they are the same ones the phone examples use, and they are device-verified on both an Apple TV simulator and an Android TV emulator:
Network
Every request your TV app makes, with headers, bodies, timing and status — captured from boot.
Storage
Browse and edit every persisted key while the app runs.
Console
Every log, warning and error in a filterable panel — instead of squinting at a Metro terminal.
Env
The config values the TV build actually resolved, validated against what you declared.
Routes
Your sitemap and live navigation stack — and you can jump the TV to any route from the desktop.
Events Timeline
Network, storage, state and navigation merged into one chronological stream.
React Query
Live cache, query states and refetches.
Redux
Every dispatched action and the state it produced.
Zustand
Store values and each change, live.
Jotai
Atom values and the graph of updates.
Same desktop, same MCP, same protocol
A TV device speaks the exact same protocol as a phone. That means:
- Buoy Desktop shows your Apple TV and Android TV devices in the same switcher as your phones — the same dashboards, the same panels, side by side.
- The Buoy MCP server reads and drives a TV app with the tools Claude Code and Cursor already use: list devices, read network, storage, state and console activity, navigate.
What's not there yet
This is a beta and the honest list is short and specific:
- No on-device UI, at all. Anything that draws on the app to do its job — render highlighting, debug borders, the image overlay — has nothing to draw into on TV. Desktop is the surface.
- No license entry on device. Headless has no UI, so a Pro key can only arrive as the
licenseKeyprop. The desktop dashboard works at the free tier; the MCP server needs Pro. - A retail Apple TV can be recorded, not driven. Apple's only supported path for pressing buttons on physical hardware is an XCUITest runner paired to the device.
- Swipes and pans replay nowhere. There is no touch surface on either platform, so a recorded swipe from a physical Siri remote has no step that can reproduce it.
- Tools beyond the list above are untested on TV. They are not blocked — they simply have not been device-verified on a TV yet, and we would rather say so than imply it.
Coming soon
- MCP tools for the remote — let an agent press the D-pad and replay macros, not just read the app.
- An XCUITest lane for retail Apple TV — the one target replay cannot reach today.
- Macros in CI — a recorded path as a regression check, with each step's echo as the assertion.
Does Buoy work on Apple TV and Android TV?
Is there a floating menu on the TV screen?
Can it press the remote for me?
Does it change my app’s focus behavior?
Does it need native code or a config plugin?
Is it free?
Try the TV beta today
Same packages, one headless prop. No native code, no config plugin, no bubble in your focus order.
npm i @buoy-gg/core