# Buoy documentation > Documentation pages from the Buoy navigation index. Platform and build support vary by tool. Each section lists its canonical URL. Interactive components may require the website. The curated index is https://buoy.gg/llms.txt. # Overview Source: https://buoy.gg/buoy/latest/docs/overview Buoy puts devtools inside your React Native app. Inspect requests, storage, state and performance on the phone, in Buoy Desktop or from your coding agent. ## Start here The quickest way in is to let your coding agent install it: To install by hand, follow the [Quick Start](./quick-start). It goes from install to your first captured request. ## Where it runs - **In your app.** A floating button opens the tools over your app, so QA and support can use them on the device that hit the bug. See [FloatingDevTools](./floating-devtools). - **On your desktop.** [Buoy Desktop](./desktop) shows every connected app in one window. It's free with a Buoy account. - **In your coding agent.** The [MCP server](./mcp) lets Claude Code, Cursor or Codex read and control the running app. Requires Pro. - **In a chat inside the app.** [Ask Buoy](./tools/ask-buoy) (beta) drives the other tools in plain English, on the model endpoint you configure. Requires Pro. ## Pick your framework - **[React Native and Expo](./quick-start)** has the full tool set. - **[Flutter](./flutter/overview)** is in beta. It runs in debug builds only, and tool coverage differs from React Native. - **[TV](./tv/overview)** is in beta for Apple TV and Android TV. Nothing renders on the TV screen; the desktop dashboard is the interface. ## What you can do - **Inspect** requests, storage, React Query, Redux, Zustand and Jotai state, navigation, console output, image loads and re-renders. - **Change** the running app: edit storage, refetch queries, dispatch actions, restore a [Time Machine](./tools/time-machine) snapshot, or switch to a test user through [Impersonate](./tools/impersonate). - **Measure** FPS, CPU, memory and JavaScript thread time with [Bench](./tools/perf-monitor) and [JS Top](./tools/js-top). Every tool is its own package, so you only install what you use. [Installation](./installation#available-packages) lists them all. Some tools need app integration. Impersonation needs your backend to authorize the selected user, and state tools need access to the stores you want to inspect. Buoy doesn't bypass your app's authentication. ## For AI agents - [buoy.gg/install.md](https://buoy.gg/install.md) holds the install instructions the prompt points to. - [llms.txt](https://buoy.gg/llms.txt) indexes the docs, and [llms-full.txt](https://buoy.gg/llms-full.txt) has every page in one file. - Add `.md` to any docs URL to get the page as Markdown. - The [MCP server](./mcp) gives your agent tools to call against the running app. ## Build your own tools Register any React component as a [custom tool](./custom-tools), such as a feature-flag panel or an order-state switcher. It appears in the same menu as the built-in tools. ## Next steps - [Quick Start](./quick-start): install Buoy and inspect your first request - [Installation](./installation): packages, account keys and troubleshooting - [AI / MCP Server](./mcp): connect your coding agent - [Custom Tools](./custom-tools): build a tool for your app # Quick Start Source: https://buoy.gg/buoy/latest/docs/quick-start Install Buoy in a React Native or Expo app, then open Network Monitor and inspect a request your app made. ## Before you start - A React Native app on 0.70 or newer, or an Expo app, with React 18 or newer. - A debug build. Core and Network are JavaScript only, so Expo Go works. - A Buoy account. Step 1 creates a free one if you don't have one yet. ## Let your agent do it Claude Code, Cursor and Codex can do the whole install. Copy the prompt, paste it into your agent and review its changes. Then do the check in step 3. To install by hand, follow the steps below. ## 1. Install Install the core menu and Network Monitor from your app's directory: Then sign in to your Buoy account: ```bash npx --package=@buoy-gg/core buoy login ``` The command opens your browser, writes your key to an env file and adds that file to `.gitignore`. In Expo, a free key goes to `.env.development.local` as `EXPO_PUBLIC_BUOY_KEY`. That file is only read in development, so the key never ends up in a release build. A paid key goes to `.env.local`. React Native CLI apps get `BUOY_KEY` in `.env.local`. [Installation](./installation#get-your-key) has the details. ## 2. Mount the menu Pick your setup. In all three, keep `FloatingDevTools` inside the same providers as your screens, so tools such as React Query can reach them. #### Expo Router Add Buoy to your root layout, `app/_layout.tsx` (or `src/app/_layout.tsx`). This example uses a Stack. Keep whichever navigator you already have. ```tsx import { Stack } from "expo-router"; import { Buoy, FloatingDevTools } from "@buoy-gg/core"; Buoy.init({ licenseKey: process.env.EXPO_PUBLIC_BUOY_KEY }); export default function RootLayout() { return ( <> ); } ``` #### Expo Render `FloatingDevTools` next to your existing `App` content, inside any providers. ```tsx import { Buoy, FloatingDevTools } from "@buoy-gg/core"; Buoy.init({ licenseKey: process.env.EXPO_PUBLIC_BUOY_KEY }); export default function App() { return ( <> ); } ``` #### React Native CLI Mount the menu in your root component. React Native doesn't load `.env.local` into `process.env` by itself, so pass `BUOY_KEY` in through the environment setup your app already uses. ```tsx import { Buoy, FloatingDevTools } from "@buoy-gg/core"; // Read BUOY_KEY with the env loader your app already uses. Buoy.init({ licenseKey: yourConfiguredKey }); export default function App() { return ( <> ); } ``` Restart the dev server so Metro picks up the new packages. In Expo: ```bash npx expo start --clear ``` Open the app and tap the floating button. If Buoy asks you to set up an account, check that your key reached `Buoy.init`. ## 3. See your first request Open **Network**, go back to your app and do something that makes an HTTP request, such as refreshing a list. Open Network again and select the request. You should see its URL, status, timing and response body. If the list is empty, make sure the action sent a new request and didn't read cached data. [Network Monitor](./tools/network) lists the supported capture paths and overrides. ## 4. Add more tools Each tool is its own package. Install the ones you want and restart the dev server, and Buoy adds them to the menu. [Installation](./installation#available-packages) lists every package. A few tools need to be pointed at your app's data: - **Zustand:** pass the stores you want to inspect through `zustandStores`. See the [Zustand setup](./tools/zustand). - **Jotai:** register named atoms with `watchAtoms`, using your app's own store if it has a custom provider. See the [Jotai setup](./tools/jotai). ## Control who sees devtools Render `FloatingDevTools` only for the users who should inspect your app. Use your app's existing authorization checks for internal users, QA, or support. A Buoy account key controls Buoy access; your app decides which users can reach the menu. Start in development. Before enabling access in a shipped app, review the [component reference](./floating-devtools) and your plan's production restrictions. ## Next steps - [Buoy Desktop](./desktop): see your connected apps in a desktop dashboard. Desktop is free to use. React Native apps need `@buoy-gg/external-sync` to connect. - [AI / MCP Server](./mcp): let Claude Code, Cursor or Codex inspect and control the running app. Requires Pro. - [Ask Buoy](./tools/ask-buoy): an in-app assistant that runs on the model endpoint you configure. Requires Pro. - [Custom Tools](./custom-tools): add a tool that's specific to your app. - [FloatingDevTools](./floating-devtools): component options and access controls. ## FAQ ### Do I need a license key to use React Buoy? Use a Free or Pro Buoy account key for this setup. Run `npx --package=@buoy-gg/core buoy login` from your app's directory. Plan limits and paid features are listed on [pricing](https://buoy.gg/pricing). ### Does Buoy phone home? Buoy makes account and license requests. Development telemetry is described in [Telemetry](./telemetry); disable that telemetry with `Buoy.init({ licenseKey: process.env.EXPO_PUBLIC_BUOY_KEY, telemetry: false })`. Disabling telemetry does not disable account validation or connections you configure for Desktop, MCP, or Ask Buoy. ### How do I add a tool to the menu? Install its package and restart the development server. Check that tool's setup page for required integration, such as registering stores or placing the menu inside a provider. ### Will the devtools ship to my users? The menu renders where you mount `FloatingDevTools`. Control access in your app. Desktop sync is disabled by default outside development; production sync requires explicit configuration and a Pro license. See [FloatingDevTools](./floating-devtools). # Installation Source: https://buoy.gg/buoy/latest/docs/installation This is the reference for installing Buoy: packages, your account key, Desktop and MCP, and fixes for common problems. New to Buoy? [Quick Start](./quick-start) walks you through a first install and ends with a captured request. ## Requirements Core and Network are JavaScript only and run in Expo Go. A few tools ship native code and need a development build, such as Bench's native CPU and memory metrics. Each tool's page says what it needs. ## Install with your agent Paste the prompt into Claude Code, Cursor or Codex. The agent reads your `package.json`, installs the tools that match your app and mounts the menu. Review its changes before you commit them. ## Install by hand Install the core menu and your first tool: To install several tools at once, pick them here and copy the command: ## Available Packages Each package adds one tool to the floating menu. Install only the ones you need. ## Register Your License Key Buoy needs a Free or Pro account key. The plans have different history limits and features, and production access, MCP and Ask Buoy require Pro. See [pricing](https://buoy.gg/pricing) for details. ### Get your key ```bash npx --package=@buoy-gg/core buoy login ``` This opens your browser, signs you in and writes the key to an env file, adding the file to `.gitignore` if it isn't there already. The variable name depends on your setup: `EXPO_PUBLIC_BUOY_KEY` on Expo and `BUOY_KEY` on bare React Native. The prefix matters, because Expo only inlines `EXPO_PUBLIC_` variables into the bundle. On Expo, a free key goes to `.env.development.local`. Expo reads that file for `expo start` only, so the key never ends up in a release build. A paid key goes to `.env.local` so it can also reach a TestFlight or QA build if you want the tools there. Bare React Native always gets `.env.local`. Read the key in your app and keep the menu inside the same providers as your screens. In React Native CLI, use your app's env loader to read `BUOY_KEY`, because writing an env file doesn't put it in `process.env`. ```tsx import { Buoy, FloatingDevTools } from "@buoy-gg/core"; Buoy.init({ licenseKey: process.env.EXPO_PUBLIC_BUOY_KEY }); export default function App() { return ( <> ); } ``` ### Or pass it directly ```tsx ``` This is fine for a solo project. On a team, use the env var instead. A key committed to a shared repo is shared by everyone who clones it, so it stops identifying a person and starts identifying a repository. ## Desktop & AI (optional) The packages above power the in-app menu. Desktop is free with a Buoy account. MCP requires Pro. - **Buoy Desktop** is a dashboard for macOS, Windows and Linux. Install the sync client in your app with `npm install @buoy-gg/external-sync`. It ships separately so apps that never use Desktop don't carry it. Then [download Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop/releases/latest) and launch it. Your app finds it on its own, because the broker address comes from the Metro host. See [Buoy Desktop](./desktop). - **AI / MCP Server** lets Claude Code, Cursor or any MCP editor drive your app: ```bash npx -y @buoy-gg/mcp@latest init ``` See [AI / MCP Server](./mcp) for the full setup. ## TypeScript Support All packages include TypeScript definitions. You don't need any `@types` packages. ## Monorepos & Enterprise Setups - **`unstable_enablePackageExports: false` works.** Big monorepos often turn off Metro's package-exports resolution for older dependencies. Buoy's packages ship legacy resolution shims, so they resolve either way. - **Physical devices find Desktop on their own.** The broker address comes from the Metro host, so devices on the same Wi-Fi reach your machine. `socketURL` overrides it for tunnels or a broker on another machine. - **Scoped registries.** Every package lives under the `@buoy-gg` scope, so a proxy registry only needs a `.npmrc` scope rule (`@buoy-gg:registry=…`). - **No on-device UI for end users.** Pass `headless` to `FloatingDevTools` for builds where only the desktop dashboard should see the session. See [FloatingDevTools](./floating-devtools). ## Troubleshooting ### The floating button doesn't appear Check that `FloatingDevTools` renders, including any access condition you wrapped it in, and that you restarted the dev server after installing. ### An installed tool is missing from the menu Restart Metro with `--clear`. Metro caches the "optional package missing" result from before you installed the package. ```bash npx expo start --clear ``` ### Buoy asks for account setup Your key didn't reach `Buoy.init`. On Expo, check the variable starts with `EXPO_PUBLIC_` and reload the app after changing it. On React Native CLI, check your env loader passes `BUOY_KEY` through. ### An Android device over USB can't reach Desktop Forward the broker port: ```bash adb reverse tcp:42831 tcp:42831 ``` ### Network shows no requests Make sure the action sent a new request and didn't read cached data. [Network Monitor](./tools/network) lists the supported capture paths. ## Next Steps - [Quick Start](./quick-start): a first install, start to finish - [FloatingDevTools](./floating-devtools): configuration options - [Buoy Desktop](./desktop): the desktop dashboard - [AI / MCP Server](./mcp): drive your app from your AI editor - [Custom Tools](./custom-tools): build your own debugging tools --- ## FAQ ### Which React Buoy package do I install first? `@buoy-gg/core` — it renders the floating menu. Every tool is a separate package (`@buoy-gg/network`, `@buoy-gg/storage`, and so on) that registers itself in the menu once installed, so you only ship the tools you actually use. ### Do I have to configure each tool after installing it? No. Auto-discovery finds installed tool packages and adds them to the floating menu with no wiring. Only tools that need to reach into your app — passing your Zustand stores, or wiring impersonation to your user-search API — take extra props. # Overview Source: https://buoy.gg/buoy/latest/docs/flutter/overview Buoy provides tools for inspecting Flutter apps: network requests, storage, state, navigation, and performance. Use the in-app menu or connect the app to [Buoy Desktop](../desktop). An AI editor can access supported tools through the [MCP server](../mcp) with Pro. Flutter support is in beta. `BuoyDevTools` runs in debug mode; it does not enable tools in profile or release builds. ## Who It's For Developers can inspect a failed request alongside the app state that produced it. QA can use configured tools to edit test data and exercise error states. Support teams can collect debugging context when your app grants them access. Some tasks need app integration. Impersonation requires your backend to authorize the selected user, and state tools need access to the stores or providers you want to inspect. Buoy does not bypass your app's authentication. ## What You Get | Tool | What It Does | |------|--------------| | **Network** | Inspect supported HTTP requests — `package:http`, dio, image loads, GraphQL | | **Storage** | Browse and edit `shared_preferences` in real-time | | **Environment** | Validate env/config with type checking and a health score | | **Console** | A Chrome-DevTools-style console for every `print` / `debugPrint` / `log` | | **Perf Monitor** | Live on-device HUD — FPS, jank, CPU, and memory | | **Images** | Captured image loads with cache verdict, timing, oversize audit & failure diagnosis | | **Riverpod** | Inspect provider state, live values, diffs, and history | | **Route Inspector** | Track go_router navigation and browse your route structure | | **Events Timeline** | Unified timeline across all tools with LLM-ready export | | **Impersonate** | Inject configured headers for backend-authorized impersonation | | **Image Overlay** | Overlay design mockups on your app for pixel-perfect comparison | ## Why Buoy Install the tools you need and inspect the running app without adding a separate debug screen for each task. Desktop gives those tools more screen space, and MCP exposes supported actions to your AI editor. Follow each tool's setup instructions for app-specific configuration. ## Quick Start ```dart import 'package:buoy/buoy.dart'; MaterialApp( builder: (context, child) => BuoyDevTools( licenseKey: 'YOUR_LICENSE_KEY', child: child ?? const SizedBox.shrink(), ), ) ``` The umbrella registers its bundled tools. Individual packages require explicit registration. Get your license key at [buoy.gg/pricing](https://buoy.gg/pricing). ## Build Your Own Tools Need something specific to your app? Add custom tools via the `tools` prop on `BuoyDevTools`. Build internal debugging utilities, feature flag toggles, or team-specific inspectors that integrate with the floating menu. ## Next Steps - [Installation](./installation) — Add Buoy to your project - [Quick Start](./quick-start) — Install and inspect your first request - [AI / MCP Server](../mcp) — Let AI agents drive your running app - [Custom Tools](./custom-tools) — Build your own debugging tools - [Tools Reference](./tools/network) — Detailed docs for each tool # Quick Start Source: https://buoy.gg/buoy/latest/docs/flutter/quick-start Open Buoy in a Flutter debug build, then inspect a request. You need a Free or Pro account key. Profile and release builds do not show the widget or start its tools. ## 1. Install the core ```bash flutter pub add buoy ``` The `buoy` umbrella pulls in the whole suite. Prefer à la carte? See [Installation](./installation). ## 2. Add to your app Wrap your app via `MaterialApp.builder` (or `CupertinoApp.builder`): ```dart import 'package:flutter/material.dart'; import 'package:buoy/buoy.dart'; MaterialApp( builder: (context, child) => BuoyDevTools( deviceName: 'My App', licenseKey: const String.fromEnvironment('BUOY_KEY'), child: child ?? const SizedBox.shrink(), ), ) ``` A floating button appears in the corner of your app. Tap it to open the menu. Get a key from your Buoy account and run `flutter run --dart-define=BUOY_KEY=YOUR_LICENSE_KEY`. See [Installation](./installation) for a complete app example and SDK requirements. ## 3. Add tools The umbrella registers its bundled Flutter tools. Perform an action that makes an HTTP request, then open Network and select the new row. Check the URL and response. If no row appears, confirm that the action made a fresh request and uses a supported client. Individual packages require explicit registration. Follow the standalone Network example in [Installation](./installation#available-packages). ### Riverpod providers If you use Riverpod, add the Buoy observer to your `ProviderScope`: ```dart import 'package:flutter/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:buoy_riverpod/buoy_riverpod.dart'; void main() { registerBuoyRiverpod(); runApp( ProviderScope( observers: const [buoyRiverpodObserver], child: const MyApp(), ), ); } ``` The observer reports provider changes to the Riverpod tool. See [Riverpod](./tools/riverpod) for package requirements and complete integration. ### go_router If you use go_router, pass your router once at registration: ```dart import 'package:buoy_routes/buoy_routes.dart'; registerBuoyRoutes(router: myGoRouter); ``` ## Available tools Use the umbrella for the bundled suite, or register a smaller set of individual packages. ## Control who sees devtools Mount `BuoyDevTools` only when your app allows the current tester to inspect its data. Use your existing authorization checks. Omitting the widget also omits the initialization and connection it manages; it is not a desktop-only mode. ## Take it further You can also connect this debug build to Desktop or MCP: - **[Buoy Desktop](../desktop)** — mirror every tool to a full dashboard on macOS, Windows, or Linux, with a live performance HUD and multi-device switching. - **[AI / MCP Server](../mcp)** — let Claude Code, Cursor, or any MCP editor inspect and control your running app. One command to wire it up: ```bash npx -y @buoy-gg/mcp@latest init ``` Buoy Desktop is free to use; the MCP server is a Pro feature. Both connect to the same app you just set up — Flutter devices appear next to React Native ones. ## What's next - [BuoyDevTools](./buoy-devtools) — Core widget reference - [Buoy Desktop](../desktop) — The full desktop dashboard - [AI / MCP Server](../mcp) — Drive your app from your AI editor - [Custom Tools](./custom-tools) — Build your own debugging tools --- ## FAQ ### How do I add Buoy devtools to a Flutter app? Run `flutter pub add buoy`, then wrap your app in `BuoyDevTools` via `MaterialApp.builder`. A floating button appears in the corner — tap it to open the menu. With the umbrella install, every Flutter tool is already registered. ### Do I need a license key to try it? Use a Free or Pro account key. Pro enables paid capabilities such as MCP, but does not enable the Flutter widget in profile or release mode. # Installation Source: https://buoy.gg/buoy/latest/docs/flutter/installation Install Buoy in an existing Flutter app and open its floating tool menu. The `BuoyDevTools` widget runs in debug mode; in profile and release builds it returns only your app's child widget. ## Requirements The package manifests require Dart `^3.9.0` and Flutter `>=3.27.0`. Use a Flutter SDK that includes Dart 3.9 or a compatible newer Dart 3 release. Check your installed versions with: ```bash flutter --version ``` ## Quick Start For the full suite, run this from your Flutter app's directory: ```bash flutter pub add buoy ``` Wrap your app through `MaterialApp.builder`. A complete minimal `lib/main.dart` looks like this: ```dart import 'package:flutter/material.dart'; import 'package:buoy/buoy.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( builder: (context, child) => BuoyDevTools( licenseKey: const String.fromEnvironment('BUOY_KEY'), child: child ?? const SizedBox.shrink(), ), home: const Scaffold( body: Center(child: Text('Open the Buoy menu to inspect this app.')), ), ); } } ``` Get your account key as described below, then start a debug build: ```bash flutter run --dart-define=BUOY_KEY=YOUR_LICENSE_KEY ``` Tap the floating button. Confirm that the menu opens and includes Network. To check capture, perform an action in your app that makes a new HTTP request, then open Network and inspect it. The minimal app above opens the menu but does not make a request. ## Available Packages The `buoy` umbrella registers its bundled tools. Some tools still need app-specific setup, such as connecting a router or supplying environment values. Their pages describe those steps. To install only Network and the core widget: ```bash flutter pub add buoy_core buoy_network ``` Use these imports in place of the umbrella import: ```dart import 'package:buoy_core/buoy_core.dart'; import 'package:buoy_network/buoy_network.dart' show registerBuoyNetwork; ``` Register Network before `runApp`; keep the `MyApp` widget from the example above: ```dart void main() { WidgetsFlutterBinding.ensureInitialized(); registerBuoyNetwork(); runApp(const MyApp()); } ``` Individual tool packages need their registration calls. Adding a dependency alone does not register it with the core widget. ## Register Your License Key Use a Free or Pro Buoy account key. Visit [pricing](https://buoy.gg/pricing) for account options and plan limits. Pass the key through `--dart-define=BUOY_KEY=...` as shown above; the widget reads it with `String.fromEnvironment`. If the widget shows account setup, confirm that the build received the key and complete the prompt. A Pro key does not enable this widget in profile or release mode. ## Desktop & AI (optional) - [Buoy Desktop](../desktop) provides a free desktop dashboard for connected apps. - [AI / MCP Server](../mcp) lets Claude Code, Cursor, or another MCP editor inspect and control your app. MCP requires Pro. For MCP configuration, run: ```bash npx -y @buoy-gg/mcp@latest init ``` Keep the Flutter app running in debug mode with `BuoyDevTools` mounted. Follow the connection guide for your chosen surface. ## Devices - iOS Simulator uses `localhost`; Android Emulator uses `10.0.2.2` to reach the computer running Desktop or the MCP broker. - On a physical device, set `socketUrl` to your computer's LAN address, for example `BuoyDevTools(socketUrl: 'http://192.168.1.20:42831', child: child)`. Replace the address with your computer's address and keep the device on a network that can reach it. Allow local network access if iOS asks. If the device does not appear, confirm that the broker is running, the address is correct, and the network or firewall allows the connection. ## Dart Support Buoy's Flutter implementation is Dart. Its dependencies may include Flutter plugins, so follow any platform setup required by the packages you install. ## Monorepos & Enterprise Setups After adding packages or changing tool registration, stop and restart the app. For individual packages, call each tool's registration function before using it. Flutter and React Native devices can connect to the same Desktop or MCP broker. Physical Flutter devices need an explicit reachable `socketUrl`. Keep `BuoyDevTools` mounted for the setup on this page. Removing it also removes the initialization and connection it manages; this guide does not provide a separate headless setup. ## Not on Flutter (yet) React Query, Redux, Zustand, render highlighting, debug borders, and JS Top are React Native tools. Check each Flutter tool page for supported features; a matching tool name does not imply complete feature parity. See the [roadmap](https://buoy.gg/roadmap) for proposed additions. ## Next Steps - [Quick Start](./quick-start): Flutter setup and usage - [BuoyDevTools](./buoy-devtools): widget reference - [Buoy Desktop](../desktop): desktop connection setup - [AI / MCP Server](../mcp): connect your AI editor - [Custom Tools](./custom-tools): add an app-specific tool ## FAQ ### What's the difference between the `buoy` umbrella and the individual packages? `buoy` imports and registers its bundled tools. Individual packages let you choose a smaller set, with explicit registration for each tool. Both use a `BuoyDevTools` widget, but the umbrella exports its own wrapper around the core widget. ### Where do I mount BuoyDevTools in a Flutter app? Use `MaterialApp.builder` or `CupertinoApp.builder` to wrap the child so the menu appears above your screens. Keep it inside any providers needed by your tools. # Overview Source: https://buoy.gg/buoy/latest/docs/tv/overview TV is React Native — the same packages, the same install. What changes is the **surface**. A TV has no touch, so Buoy mounts **headless** and renders nothing on the screen, and [Buoy Desktop](../desktop) becomes the whole interface. TV support is in beta. The documented target set includes Apple TV simulators and Android TV emulators. Check [Known limits](#known-limits) and test your app on its actual target hardware; these pages are not a test record for every device and build. **Two ways to reach your running TV app:** - **On your desktop** — Buoy Desktop, a free dashboard for macOS, Windows & Linux. Your TV device appears in the same switcher as your phones, with the same panels. - **Through your AI** — the [MCP server](../mcp) lets Claude Code, Cursor, or any MCP editor inspect your live TV app (Pro). There is no third way on TV: the in-app floating menu is deliberately absent. ## Why there is no floating menu on TV TV uses D-pad navigation. A focusable debug overlay can enter that focus order and affect the behavior under test. Mount Buoy headless to keep its controls on Desktop and leave the app screen available for inspection. ## The two TV tools These exist *because* of TV. Both are desktop surfaces — the packages you install only capture. | Tool | Package | What it does | |---|---|---| | [TV Remote](../tools/tv-remote) | `@buoy-gg/tv-remote` | Press the D-pad, Select, Menu, holds, media keys and typed text from Buoy Desktop; record a macro and replay it with per-step confirmation. | | [Focus Inspector](../tools/focus-inspector) | `@buoy-gg/focus-inspector` | Every focus move with its direction, the full focusable inventory, and flags for focus that gets **stuck**, **vanishes**, or is **never reached**. | Use the remote event history and focus transitions together to record the sequence leading to a focus problem. ### Presses come from your Mac, not from inside the app Buoy Desktop injects with `adb shell input keyevent` on Android TV and `idb ui key` on the Apple TV simulator. Both travel the platform's real input pipeline, so focus moves through the same engine a physical remote drives. The installed package only **observes** — it reports which events your app actually received, which is what tells "the app handled that press" apart from "something swallowed it." The app package observes input events; host tools inject supported presses. A JavaScript handler call alone does not reproduce the platform focus-navigation path. ### What works where | Target | Capture | Replay presses | How | |---|---|---|---| | Android TV emulator | ✅ | ✅ everything | `adb -s shell input keyevent` | | Android TV device | ✅ | ✅ everything | the same, over `adb connect :5555` | | Apple TV simulator | ✅ | ✅ except media keys | `idb ui key` / `ui button` / `ui text` | | Apple TV device | ✅ | ❌ **record only** | no supported host-side injection exists | Capture is pure JavaScript, so **recording works everywhere, including retail hardware.** That is 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 runs against emulators and simulators. ## The rest of the suite None of these needed TV-specific code — they are the same tools the phone examples use, available for inspection through the corresponding installed packages: [Network](../tools/network) · [Storage](../tools/storage) · [Console](../tools/console) · [Env](../tools/env) · [Routes](../tools/routes) · [Events](../tools/events) · [React Query](../tools/react-query) · [Redux](../tools/redux) · [Zustand](../tools/zustand) · [Jotai](../tools/jotai) ## Known limits - **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. - **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. - **No media transport keys on a tvOS simulator.** `idb ui key` speaks the HID *keyboard* page, which has no usages for play/pause, rewind, fast-forward, next or previous. Those steps report `skipped-unsupported`, never silently pass. They work on Android. - **Typed text never echoes.** It rides the platform's keyboard path and reaches the native text field without touching the app's TV event pipe, so a text step is fire-and-wait. - **Swipes and pans replay nowhere.** There is no touch surface on either platform, so a swipe recorded from a physical Siri remote has no step that can reproduce it. - **Tools beyond the list above are untested on TV.** Not blocked — just not device-verified yet. ## Coming soon - MCP tools for the remote, so an agent can press the D-pad and replay macros. - An XCUITest lane for retail Apple TV — the one target replay cannot reach today. - Macros in CI, with each step's echo as the assertion. Next: [Quick Start](./quick-start). # Quick Start Source: https://buoy.gg/buoy/latest/docs/tv/quick-start Connect a React Native TV app to Buoy Desktop, then inspect remote input and focus. Buoy uses the same JavaScript packages as its phone integration. ## 1. Install the core For plain Markdown readers, the command is: ```bash npm install @buoy-gg/core @buoy-gg/external-sync ``` Configure a Free or Pro key with `npx --package=@buoy-gg/core buoy login`. The examples use Expo's `EXPO_PUBLIC_BUOY_KEY`; React Native CLI apps must supply the key through their own environment configuration. ## 2. Mount it headless ```tsx import { FloatingDevTools } from "@buoy-gg/core"; export default function App() { return ( <> {/* your app */} {/* 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 shipped for field builds where only the desktop should see the session. See [Overview](./overview#why-there-is-no-floating-menu-on-tv) for why that is the right call on TV rather than a compromise. Buoy adds **no native dependencies** to a TV app. Restart Metro after adding the packages. Follow the requirements of any other dependencies you add. ## 3. Add the TV tools The TV tools register when installed. Other tools may need app-specific configuration. Add any other tool the same way (`@buoy-gg/network`, `@buoy-gg/storage`, …) and it appears in the desktop dashboard. ## 4. Connect Buoy Desktop Open [Buoy Desktop](../desktop) and your TV appears in the device switcher next to your phones. An **Android TV emulator** needs the broker port forwarded once per device: ```sh adb -s reverse tcp:42831 tcp:42831 ``` Pass `-s ` explicitly — a physical phone is often attached at the same time, and `adb` will otherwise pick the wrong one. An **Apple TV simulator** connects on its own. ## 5. Press the remote from your desktop Open **TV Remote** in Buoy Desktop, pair the device with an injection target, and press. Presses go through the platform's real input pipeline, so they move focus exactly like a physical remote. Injection needs `adb` on your `PATH` (Android SDK platform-tools) and, for the Apple TV simulator, `idb` — which does not ship with Xcode: ```sh brew tap facebook/fb && brew install idb-companion pipx install fb-idb ``` Without it the Apple TV lane is disabled and the panel says so. A retail Apple TV can be **recorded but not driven** — see the target table in the [Overview](./overview#what-works-where). Then open **Focus** and drive the app: reported focus moves can be compared with observed direction inputs. Review flags against actual device behavior. ## Requirements - `react-native-tvos` and the New Architecture (Fabric). - Restart Metro after adding JavaScript tools. Your TV runtime and host input tools have separate setup requirements. - Headless has **no license entry UI**. Configure your Free or Pro account key before mounting the headless tools. The desktop dashboard works at the free tier; the MCP server requires Pro. More detail in [Installation](./installation). # Installation Source: https://buoy.gg/buoy/latest/docs/tv/installation Buoy on TV is the ordinary React Native install with one prop changed. This page is the complete version of [Quick Start](./quick-start). ## Requirements | | | |---|---| | React Native | `react-native-tvos` (the TV fork) | | Architecture | New Architecture / Fabric | | App type | Expo TV (`@react-native-tvos/config-tv`) or bare RN TV — both verified | | Native deps added by Buoy | **None** — no podspecs, no gradle changes, no prebuild | | Host tooling | `adb` for Android TV; `idb` for the Apple TV simulator (remote injection only) | Expo Go cannot run a TV app at all — TV is always a prebuild + `expo run:*` app. That is a property of TV, not of Buoy. ## Packages Install the core, then any tools you want. Installed tools register themselves; there is no list to maintain. For plain Markdown readers, the command is: ```bash npm install @buoy-gg/core @buoy-gg/external-sync ``` Configure a Free or Pro key with `npx --package=@buoy-gg/core buoy login`. The examples use Expo's `EXPO_PUBLIC_BUOY_KEY`; React Native CLI apps must supply the key through their own environment configuration. The two TV-specific tools: Everything else installs exactly as it does on a phone — [Network](../tools/network), [Storage](../tools/storage), [Console](../tools/console), [Env](../tools/env), [Routes](../tools/routes), [Events](../tools/events), [React Query](../tools/react-query), [Redux](../tools/redux), [Zustand](../tools/zustand), [Jotai](../tools/jotai) are all device-verified on both TV platforms. ## Mounting ```tsx import { FloatingDevTools } from "@buoy-gg/core"; export default function App() { return ( <> {/* your app */} ); } ``` `headless` is required on TV in practice: without it the floating bubble renders, and on Android TV its focusable views join your app's D-pad focus order. See [Overview](./overview#why-there-is-no-floating-menu-on-tv). `deviceName` is what shows in Buoy Desktop's switcher. Give each TV a distinct one — an Apple TV simulator and an Android TV emulator running the same app are otherwise hard to tell apart. ## Connecting to the desktop | Device | What it needs | |---|---| | Apple TV simulator | Nothing — it connects on its own. | | Android TV emulator | `adb -s reverse tcp:42831 tcp:42831`, once per boot. | | Physical TV device | A `socketURL` pointing at your machine's LAN address. | Pass `-s ` to `adb` explicitly. A physical phone is often attached alongside the emulator, and an unqualified `adb reverse` forwards the wrong device. ## Host tooling for the TV Remote Replay is injected from your machine, so the binaries have to be findable: - **Android** — `adb`, part of the Android SDK platform-tools. - **Apple TV simulator** — `idb`, which does **not** ship with Xcode: ```sh brew tap facebook/fb && brew install idb-companion pipx install fb-idb ``` Buoy looks for both on your `PATH` and in the usual install locations, so the packaged desktop app finds them even though a GUI app inherits a minimal `PATH`. If `idb` is missing, the Apple TV lane is disabled and the panel says so rather than failing silently. Recording needs none of this — capture is pure JavaScript and works on retail hardware. ## License keys A verified Free or Pro account is required. Desktop is free to use; MCP and production access require Pro. **Headless has no license entry UI** — there is no on-device screen to type into. On TV a key can be supplied through initialization or the `licenseKey` prop, typically from your environment configuration. The desktop dashboard works at the free tier; the [MCP server](../mcp) requires Pro and will refuse a TV device with no admitted account. Don't have a key yet? Grab one at [buoy.gg/pricing](https://buoy.gg/pricing). # FloatingDevTools Source: https://buoy.gg/buoy/latest/docs/floating-devtools The `FloatingDevTools` component is the entry point for React Buoy. It renders a draggable floating button that opens a menu containing all your installed debugging tools. The dial shows the most recently opened tool first. Tools you haven’t opened keep their registration order. The order updates when you reopen the dial. ## Basic Usage ```tsx import { FloatingDevTools } from "@buoy-gg/core"; function App() { return ( <> ); } ``` Pass your account key and install the tools you need. Keep `FloatingDevTools` inside the providers those tools use. Don't have a key yet? Grab one at [buoy.gg/pricing](https://buoy.gg/pricing). Without a verified account, the launcher shows **Sign in**. Open it to copy `npx buoy login`, run the command in your project, then reload your app. **Check connection** retries verification and shows feedback if your account is still disconnected. The sign-in card and launcher share their design across native and web. ## Environment Badge The floating button automatically displays your current environment based on `NODE_ENV`, helping your team instantly know where they are. No configuration needed. You can override it explicitly if your environment name doesn't match `NODE_ENV`: ```tsx ``` Supported values: `"local"`, `"dev"`, `"staging"`, `"qa"`, `"prod"` ## How Tools Auto-Register When you install a Buoy tool package (like `@buoy-gg/network` or `@buoy-gg/storage`), it automatically registers itself with the floating menu. Some tools need additional registration or app configuration. ```bash npm install @buoy-gg/network ``` Restart Metro after installing the package, then open Network to confirm discovery. ## Custom Tools Need something specific to your app? Add your own tools: ```tsx import { FloatingDevTools } from "@buoy-gg/core"; import { View, Text } from "react-native"; const FeatureFlagTool = () => ( Toggle feature flags here ); function App() { return ( ); } ``` See [Custom Tools](./custom-tools) for more details on building your own debugging tools. ## Draggable Button The floating button can be dragged anywhere on screen. It remembers its position between sessions, so it stays where your team likes it. ## Beyond the in-app menu `FloatingDevTools` is also the source of truth for Buoy's other surfaces. The same tools you see in the menu sync out over a local broker, after you install `@buoy-gg/external-sync` and configure the connection. You can then: - open the [Buoy Desktop](./desktop) dashboard and inspect the same live app on a full screen, or - point an AI agent at your app with the [MCP server](./mcp). Just connect either one to your running app. The broker address is derived automatically from the Metro dev server that served the bundle, so physical devices reach your machine with zero config (Android over USB: run `adb reverse tcp:42831 tcp:42831` once); pass `socketURL` in the `externalSync` prop only for tunnels or a broker on another machine. The current sync target and connection state show up in the menu's Settings tab under **DESKTOP SYNC**. Each install identifies itself with a per-device id minted on first connect, so a phone and a simulator (or a whole QA team) on the same build show up as separate devices; pass `deviceName`/`deviceId` in `externalSync` only to pin a label, and never the same `deviceId` on two devices. Sync is dev-only unless you ask for it — see [release builds](./desktop#release-builds) to profile a release build you own. ## Headless (sync-only) mode For builds that ship to non-developers — field or associate builds where the desktop dashboard is the only debugging surface — mount the tools with no on-device UI at all: ```tsx ``` `headless` keeps every tool's sync adapter and route tracking running (so Buoy Desktop and the MCP server see the full session) but renders no floating button, dial, or overlays. Headless mode still requires a verified account. Supply the key through initialization or `licenseKey`; it has no on-device account entry screen. `requireLicense: false` does not bypass account admission. Sync still follows the same rule as any other build: on in dev, and in a release build only with [`externalSync.enableInRelease`](./desktop#release-builds) plus a Pro license — which is exactly what a field build wants. ## Next Steps - [Custom Tools](./custom-tools) — Build team-specific debugging tools - [Buoy Desktop](./desktop) — Inspect the same app on a full dashboard - [AI / MCP Server](./mcp) — Drive your app from your AI editor - [Quick Start](./quick-start) — Full setup walkthrough ## Web support (unreleased) Register this package’s /web namespace in FloatingDevTools modules to use its shared panels and actions in a browser app. The browser build is available in this checkout and has not been published yet. See the [web setup guide](./web-preview.md) for registration, dependencies, and browser boundaries. The browser dial supports Tab, arrow keys between tools, Enter to activate controls, and Escape to close. Its center button opens settings. Drag panel backgrounds or handles to move them; tabs and inputs keep their normal mouse behavior. Minimized tools stay above the floating bar and scroll when needed. They open below only when there is not enough room above for one row. The web dial follows the shared Background selection in Settings, including changes made while the dial is open. # Custom Tools Source: https://buoy.gg/buoy/latest/docs/custom-tools Register a React component through `FloatingDevTools.apps` to add an app-specific tool. Start with the counter below, then connect the component to your own state. ## The component toolkit Custom tools don't start from a blank screen — `@buoy-gg/core` ships the same UI kit our first-party tools are built from: theme tokens, badges, buttons, list rows, JSON viewers, diff viewers and more. Everything below is the **real component rendered live** (via react-native-web) — search or filter to find the pieces your tool needs, then import them straight from `@buoy-gg/core`. ## Basic Custom Tool ```tsx import { useState } from "react"; import { FloatingDevTools } from "@buoy-gg/core"; import { View, Text, Button } from "react-native"; const CounterDebugger = () => { const [count, setCount] = useState(0); return ( Count: {count}