All but React Native are in beta.
All but React Native are in beta.

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.
This browser example runs the menu over a mock app. Drag the grip to reposition it and try the available controls.
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.
import { FloatingDevTools } from "@buoy-gg/core";
function App() {
return (
<>
<YourApp />
<FloatingDevTools />
</>
);
}
import { FloatingDevTools } from "@buoy-gg/core";
function App() {
return (
<>
<YourApp />
<FloatingDevTools />
</>
);
}
First, sign in. Run npx --package=@buoy-gg/core buoy login in your app's folder. It writes a dev token for dev builds. On Expo, Buoy reads it by itself. Other apps pass it in with the licenseKey prop. Your account key works there too, as a backup. Then install the tools you need. Keep FloatingDevTools inside the providers those tools use. See Sign in with Buoy.
Without a verified account, the launcher shows Sign in. Open it to copy npx --package=@buoy-gg/core 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.
TestFlight, QA and store builds have no dev token. Pass signIn so your testers can sign in with a code:
<FloatingDevTools signIn />
<FloatingDevTools signIn />
When Buoy isn't open, it shows Sign in. Tap it to see a QR code and a short code. Then a person signed in to buoy.gg allows it at buoy.gg/activate.
Buoy reads the app id from your Expo config. If it can't, pass it in: signIn={{ appId: "com.acme.shop" }}. Add app: and that id at buoy.gg/dashboard/sites. Only show FloatingDevTools to your own admins and testers.
On a live web site, signIn shows a Sign in button instead. See Sign in with Buoy.
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:
<FloatingDevTools environment="qa" />
<FloatingDevTools environment="qa" />
Supported values: "local", "dev", "staging", "qa", "prod"
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.
npm install @buoy-gg/network
npm install @buoy-gg/network
Restart Metro after installing the package, then open Network to confirm discovery.
Need something specific to your app? Add your own tools:
import { FloatingDevTools } from "@buoy-gg/core";
import { View, Text } from "react-native";
const FeatureFlagTool = () => (
<View>
<Text>Toggle feature flags here</Text>
</View>
);
function App() {
return (
<FloatingDevTools
apps={[
{
id: "flags",
name: "Flags",
component: FeatureFlagTool,
icon: "π©",
},
]}
/>
);
}
import { FloatingDevTools } from "@buoy-gg/core";
import { View, Text } from "react-native";
const FeatureFlagTool = () => (
<View>
<Text>Toggle feature flags here</Text>
</View>
);
function App() {
return (
<FloatingDevTools
apps={[
{
id: "flags",
name: "Flags",
component: FeatureFlagTool,
icon: "π©",
},
]}
/>
);
}
See Custom Tools for more details on building your own debugging tools.
The floating button can be dragged anywhere on screen. It remembers its position between sessions, so it stays where your team likes it.
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:
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 to profile a release build you own.
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:
<FloatingDevTools headless />
<FloatingDevTools headless />
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. It shows no sign-in screen, so run buoy login first. On Expo, Buoy reads the dev token by itself in dev builds. Other apps pass a token or key with Buoy.init or licenseKey. 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 plus a Pro license, which is what a field build wants.
Register this packageβs /web namespace in FloatingDevTools modules to use its shared panels and actions in a browser app. Import it from the package's /web entry (7.0.41 or later). See Web installation 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.
For plain Three.js, use mountBuoy from @buoy-gg/core/web. See Three.js for the boot file and full screen rules.