@traceitx/react-native
v0.6.3
Published
React Native SDK for TraceItX — AI-ready in-app bug reporting, bridging the native iOS and Android reporter to your RN app. Supports phone, Apple TV, and Android TV.
Maintainers
Readme
@traceitx/react-native
TraceItX React Native bridge — exposes the native iOS and Android reporter modal to RN host apps via a TurboModule + a thin React provider/hook API.
Phone, Apple TV, and Android TV are all supported when the host app is built against
react-native-tvos(see TV Host Integration).
Installation
pnpm add @traceitx/react-nativePeer dependencies: react ≥ 19, react-native (or react-native-tvos for
TV targets) ≥ 0.85.
Then install pods (iOS) / sync Gradle (Android) as usual:
cd ios && pod installUsage
Wrap your app with <TraceItXProvider> at the highest practical level
(above any navigator / focus engine root):
import { TraceItXProvider, useTraceItX } from '@traceitx/react-native';
export default function App() {
return (
// `apiKey` is the only required field. The ingest endpoint is a
// compile-time constant in the SDK and is not configurable in v1.
<TraceItXProvider config={{ apiKey: 'txx_live_xxxxxxxxxxxxxxxx' }}>
<RootNavigator />
</TraceItXProvider>
);
}Trigger the reporter from any host UI:
function HelpButton() {
const { open } = useTraceItX();
return <Button title="Report a bug" onPress={() => open()} />;
}For non-component contexts, use the top-level open re-export
(throws TraceItXNotMountedError if the provider is not yet mounted):
import { open } from '@traceitx/react-native';
await open();open() returns a ReporterResult with { status: 'submitted' |
'queued' | 'cancelled', ... }.
Network body capture (client veto)
<TraceItXProvider config={{ apiKey: '…', networkBodies: { disabled: true } }}>networkBodies.disabled: true is a client veto — it can only turn body
capture off locally; it can never turn it on. The server's per-app
captureBodies gate is still authoritative, and native network capture must
still be wired up on each platform (see below) before any body is ever
recorded.
This option does not, by itself, make React Native capture network
bodies. RN does not currently attach TraceItX's network capture to its own
HTTP clients (fetch, Axios, etc.) — that wiring is tracked separately and
is not part of this SDK yet. RN apps do still inherit the native SDK's own
auto-capture running underneath them, so networkBodies controls that
native capture — and even that requires the native side to actually be
capturing network traffic in the first place:
- Android: bodies are captured only for OkHttpClient instances the host
app explicitly builds with
addTraceItXInterceptor()(seepackages/sdk-android/android/README.md). Without that interceptor, no network capture — and therefore no bodies — happens regardless of this option. - iOS: equivalent native network capture wiring, if and when the host app uses it.
Do not enable this option expecting RN's own network calls to show up in reports — that capability doesn't exist yet.
Navigation breadcrumbs
Mark screens with one line; the native SDK derives from → to from a global
chain shared with native auto-capture. Works with any navigation approach.
react-navigation (screens stay mounted — pass focus):
import { useTXScreen } from '@traceitx/react-native';
import { useIsFocused, useRoute } from '@react-navigation/native';
function DetailScreen() {
useTXScreen(useRoute().name, { focused: useIsFocused() });
...
}…or whole-app in one place:
<NavigationContainer ref={navRef}
onStateChange={() => recordScreen(navRef.getCurrentRoute()?.name ?? '')}>Wix react-native-navigation:
componentDidAppear() { recordScreen(this.props.screenName); }Hand-rolled (conditional-render tabs, custom switchers):
function DeskTab() {
useTXScreen('Desk');
...
}Screen names should be route identifiers, never user content.
Opt-in JS integrations
Native capture (taps, screens, lifecycle, errors) is automatic. Two things live only in JS — console logs and navigator state — and are captured ONLY when you opt in:
import { consoleIntegration } from '@traceitx/react-native/integrations/console';
import { reactNavigationIntegration } from '@traceitx/react-native/integrations/react-navigation';
import { createNavigationContainerRef } from '@react-navigation/native';
const navigationRef = createNavigationContainerRef();
const txNav = reactNavigationIntegration({ navigationRef });
<TraceItXProvider config={{ apiKey, integrations: [consoleIntegration(), txNav] }}>
<NavigationContainer ref={navigationRef} onReady={txNav.onReady}>
...consoleIntegration({ levels? })— forwardsconsole.log/info/warn/error(configurable) to the breadcrumb trail with real severity. Originals always run first.reactNavigationIntegration({ navigationRef })— records every route change viarecordScreen; also covers expo-router. PasstxNav.onReadyto the container so the initial route is recorded.
Using another navigator? Any stack is a ~5-line adapter over
recordScreen — the useTXScreen recipes above cover Wix RNN and
hand-rolled navigation, and a custom integration is just
{ name, setup() { ...subscribe...; return unsubscribe } }.
TV Host Integration (Apple TV + Android TV)
@traceitx/react-native supports Apple TV + Android TV when consumed
from a host app built against react-native-tvos. This support is developed
against RN-tvos 0.85.3-0, Expo SDK 56.0.0-preview.7, and React 19.2.5;
the canonical example app below is kept building on that matrix.
Provider placement
<TraceItXProvider> MUST sit ABOVE the TV focus engine's root in the
component tree. The reporter is presented imperatively by the native side
(via TXTVReporterViewController on iOS / :traceitx-tv ReporterActivity
on Android), so React Native's focus engine never sees it — the native VC
manages focus on its own UIWindow / Activity.
<TraceItXProvider config={{ apiKey }}>
<NavigationContainer>{/* focus engine root */}</NavigationContainer>
</TraceItXProvider>Triggers are the host app's concern
TraceItX does NOT install gesture / key / shake listeners on any
platform. This is a deliberate Phase 5.1 contract — the SDK's trigger
machinery was removed so that hosts own their UX entirely. The host app
calls useTraceItX().open() (or the top-level open())
from whatever trigger makes sense for the target form factor.
For TV, the canonical pattern uses TVEventHandler (exposed by
react-native-tvos).
API shape ([email protected])
import { TVEventHandler } from 'react-native';
type HWEvent = {
eventType:
| 'menu' | 'playPause' | 'longPlayPause' | 'select'
| 'up' | 'down' | 'left' | 'right'
| 'longUp' | 'longDown' | 'longLeft' | 'longRight'
| 'pan' | string;
eventKeyAction?: -1 | 0 | 1 | number; // 0 = down, 1 = up, -1 = unknown
tag?: number;
body?: { state: 'Began' | 'Changed' | 'Ended'; x: number; y: number; velocityX: number; velocityY: number };
};
const subscription = TVEventHandler.addListener((evt: HWEvent) => { /* ... */ });
subscription?.remove();If you have seen the older
new TVEventHandler(); handler.enable(cmp, cb); handler.disable()shape elsewhere — that class-based API was removed in RN-tvos 0.85.x. Always read the version installed in yournode_modules.
Apple TV: long-press Play/Pause
import { Platform, TVEventHandler } from 'react-native';
import { useTraceItX } from '@traceitx/react-native';
import { useEffect } from 'react';
function useAppleTVReporterTrigger() {
const { open } = useTraceItX();
useEffect(() => {
if (!(Platform.isTV && Platform.OS === 'ios')) return;
const sub = TVEventHandler.addListener((evt) => {
if (evt.eventType !== 'longPlayPause') return;
if (Number(evt.eventKeyAction) !== 1) return; // key-up only
void open();
});
return () => sub?.remove();
}, [open]);
}Why
longPlayPauseinstead ofmenu?.menuis reserved by Apple as the system back-navigation gesture on the Siri Remote — apps that bind it for a non-navigation purpose are App Store-rejected. TraceItX's iOS SDK enforces this viaReservedKeysValidator; the same constraint applies on RN.longPlayPauseis a native long-press event emitted by the OS (no JS timing required).
Android TV: KEYCODE_MENU
import { Platform, TVEventHandler } from 'react-native';
import { useTraceItX } from '@traceitx/react-native';
import { useEffect } from 'react';
function useAndroidTVReporterTrigger() {
const { open } = useTraceItX();
useEffect(() => {
if (!(Platform.isTV && Platform.OS === 'android')) return;
const sub = TVEventHandler.addListener((evt) => {
if (evt.eventType !== 'menu') return;
if (Number(evt.eventKeyAction) !== 1) return; // key-up only
void open();
});
return () => sub?.remove();
}, [open]);
}KEYCODE_MENU is mapped to eventType === 'menu' by
ReactAndroidHWInputDeviceHelper (RN-tvos). It is the conventional
"settings / debug menu" key on Android TV remotes.
Canonical example
The dogfood sample app at
examples/react-native/src/screens/Home.tsx
implements both recipes side-by-side, gated by Platform.isTV +
Platform.OS. Cloned from the repo, build it with:
pnpm --filter examples-react-native ios:tv # Apple TV simulator
pnpm --filter examples-react-native android:tv # Android TV emulatorThat example's own README covers prebuild details and the known pitfalls of the TV targets.
What about the floating bubble?
The iPhone floating-bubble overlay shipped in Phase 04 is NOT exposed via the RN bridge today (and would not make sense on TV anyway — the focus engine is the input model, not a touch-positioned overlay). On phone RN hosts, add your own host-level button. On TV hosts, use the remote recipes above.
License
Apache-2.0
