
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
@everframe/react-native
Advanced tools
React Native SDK for Everframe — AI-ready in-app bug reporting, bridging the native iOS and Android reporter to your RN app. Supports phone, Apple TV, and Android TV.
Everframe 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).
pnpm add @everframe/react-native
Peer 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 install
Wrap your app with <EverframeProvider> at the highest practical level
(above any navigator / focus engine root):
import { EverframeProvider, useEverframe } from '@everframe/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.
<EverframeProvider
config={{
apiKey: 'txx_live_xxxxxxxxxxxxxxxx',
// Recommended in RN/Expo development: shake also opens the dev menu.
shakeToReport: { enabled: !__DEV__ },
}}
>
<RootNavigator />
</EverframeProvider>
);
}
Trigger the reporter from any host UI:
function HelpButton() {
const { open } = useEverframe();
return <Button title="Report a bug" onPress={() => open()} />;
}
For non-component contexts, use the top-level open re-export
(throws EverframeNotMountedError if the provider is not yet mounted):
import { open } from '@everframe/react-native';
await open();
open() returns a ReporterResult with { status: 'submitted' | 'queued' | 'cancelled', ... }.
For handled JavaScript exceptions, call captureException(error) from the
provider context and attach any non-sensitive context needed for diagnosis.
The source API requires matching rebuilt native components; published 0.7.0
artifacts are not evidence of support.
<EverframeProvider 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 Everframe'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:
addEverframeInterceptor() (see
packages/sdk-android/android/README.md). Without that interceptor, no
network capture — and therefore no bodies — happens regardless of this
option.Do not enable this option expecting RN's own network calls to show up in reports — that capability doesn't exist yet.
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 { useEverframeScreen } from '@everframe/react-native';
import { useIsFocused, useRoute } from '@react-navigation/native';
function DetailScreen() {
useEverframeScreen(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() {
useEverframeScreen('Desk');
...
}
Screen names should be route identifiers, never user content.
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 '@everframe/react-native/integrations/console';
import { reactNavigationIntegration } from '@everframe/react-native/integrations/react-navigation';
import { createNavigationContainerRef } from '@react-navigation/native';
const navigationRef = createNavigationContainerRef();
const txNav = reactNavigationIntegration({ navigationRef });
<EverframeProvider config={{ apiKey, integrations: [consoleIntegration(), txNav] }}>
<NavigationContainer ref={navigationRef} onReady={txNav.onReady}>
...
consoleIntegration({ levels? }) — forwards console.log/info/warn/error
(configurable) to the breadcrumb trail with real severity. Originals always
run first.reactNavigationIntegration({ navigationRef }) — records every route
change via recordScreen; also covers expo-router. Pass txNav.onReady
to the container so the initial route is recorded.Using another navigator? Any stack is a ~5-line adapter over
recordScreen — the useEverframeScreen recipes above cover Wix RNN and
hand-rolled navigation, and a custom integration is just
{ name, setup() { ...subscribe...; return unsubscribe } }.
Native capture again: every RN app automatically gets background CPU/memory sampling and a session id stamped on reports and crashes as soon as the host app's project has vitals enabled on the dashboard — no JS change required.
What JS adds is player tracking, because in RN the player instance lives inside a native view and never reaches JS.
<EverframeProvider config={{ apiKey, vitals: { enabled: true, sampleRate: 0.5, captureSourceQuery: false } }}>
enabled — absent follows the dashboard toggle; false opts out locally;
true never forces vitals on if the dashboard has them off.sampleRate — [0, 1], min()'d with the server-configured rate.captureSourceQuery — keep the query string on source_change.src
(default false: signed CDN URLs carry tokens in the query).Reconfiguring. A Provider remount with the same config does not restart the SDK: both native sides compare the incoming config against the installed one and skip the start entirely. A changed config does restart it — and a start supersedes the running SDK, detaching every player integration it had announced. Limitation: players tracked before that restart stay untracked until their screens remount; nothing re-registers them automatically. Two React instances in one process are not coordinated either: if a second one starts the SDK under the first, the first instance's players stay untracked until its own screens remount.
import { useVideoPlayer, VideoView } from 'react-native-video';
import { useVideoPlayerVitals } from '@everframe/react-native/integrations/react-native-video';
function Player() {
const player = useVideoPlayer(source);
useVideoPlayerVitals(player, { name: 'main', libraryVersion: '7.0.0' });
return <VideoView player={player} />;
}
libraryVersion is a host-supplied option — react-native-video does not
expose it at runtime.
To measure INITIAL startup, defer the load:
// Module scope: the latch belongs to the PLAYER, not to the component. A
// replacement instance (StrictMode's double-mount, a source change) is a
// different object and gets its own initialize; the same instance never
// gets a second one, which would restart playback under the user.
const initialised = new WeakSet<object>();
const player = useVideoPlayer({ uri: SOURCE, initializeOnCreation: false });
useVideoPlayerVitals(player, { name: 'main', libraryVersion: '7.0.0' });
useEffect(() => {
if (initialised.has(player)) return;
initialised.add(player);
void player.initialize();
}, [player]);
Why: on Android react-native-video v7 emits onLoadStart synchronously from
inside the native player constructor — before any effect runs, so before the
adapter has subscribed — and onLoadStart is what arms the adapter's startup
clock, so the first source's startup latency is simply never seen. Deferring
the load until after the adapter subscribed puts the first onLoadStart back
where it can be observed. Without this, everything else still works; only the
first startup measurement is missing (later source changes are fine).
Options: name, libraryVersion, and captureErrors (default false — see
Limitations). onBandwidthUpdate is read per platform: on iOS its bitrate
is the rendition's declared bitrate and drives bitrate_change plus the
bitrate stat; on Android it is ExoPlayer's bandwidth estimate, reported as
the bandwidthEstimate stat (with quality_change for the accompanying
rendition size) and never as a bitrate.
onProgress is read per platform too. The bufferAheadMs stat is always the
media time buffered ahead of the playhead: on Android bufferDuration is
already that, on iOS it is the buffered range's absolute end position, so the
adapter subtracts currentTime from it.
import { attachTheoPlayerVitals } from '@everframe/react-native/integrations/theoplayer';
<THEOplayerView onPlayerReady={(player) => attachTheoPlayerVitals(player, { name: 'main' })} />
Both adapters are pure translators: neither library is imported at runtime or added as a dependency of this package.
import { trackVitals } from '@everframe/react-native';
trackVitals('ad_break', { pod: 1 });
trackPlayerLibraries without an adapter above (or a player object outside a component tree) can drive the same pipeline directly:
import { trackPlayer } from '@everframe/react-native';
const handle = trackPlayer({ library: 'my-player', libraryVersion: '1.2.0', name: 'main' });
handle.emit('play');
handle.emit('buffer_start');
handle.emit('buffer_end', { durationMs: 800 });
handle.updateStats({ bufferAheadMs: 4200, bitrate: 2_500_000 });
handle.track('ad_break', { pod: 1 });
handle.detach();
useTrackPlayer(opts) is the hook form — tracks on mount, detaches on
unmount, mints a fresh token on remount (Fast Refresh-safe).
Event vocabulary for emit: source_change, drm, startup, play,
pause, buffer_start, buffer_end, seek, rate_change,
bitrate_change, quality_change, dropped_frames, error, stats.
player_attach and player_detach are reserved for the native lifecycle
markers the registry emits itself — passing either to emit is silently
dropped, not forwarded.
PlayerHandle.emit is void
(fire-and-forget across the bridge), so JS cannot know whether native
admitted an entry; an error refused over there still spends a slot.captureErrors changes react-native-video's own behaviour, so it is
off by default. With it on, errors carry the library's code
('source/invalid-uri', …). But v7 only throws synchronously from
play() / pause() / seekBy() / seekTo() / selectTextTrack() /
getAvailableTextTracks() when NO onError listener is registered — so
merely subscribing makes those calls stop throwing for the whole app, and
a host relying on try { player.play() } catch would silently lose its
errors. Off by default, fatal errors are still reported (via
onStatusChange('error')), just without a code.captureErrors keeps swallowing after detach. react-native-video's
listener removal leaves an EMPTY onError listener set rather than no set
at all, and the library's "throw synchronously when nobody is listening"
check only asks whether the set exists. So once captureErrors: true has
been attached even once, that player keeps suppressing the synchronous
play() / seek*() throws for the rest of its lifetime — detaching the
vitals adapter does not give them back. A library bug, not an adapter one;
there is nothing to fix on our side, which is the second reason
captureErrors is off by default.rate_change was not observed from react-native-video v7 on Android in
our Android emulator smoke — onPlaybackRateChange never arrived there.
Note that the library does forward ExoPlayer's
onPlaybackParametersChanged, so this is a "not seen in our smoke run"
result, not a proven library gap; a host that changes playback speed
explicitly may well see it. Nothing on the adapter side gates it either way.7.0.0-beta.11
there is no tvOS podspec/target, so it cannot be used on Apple TV at all.
Use THEOplayer, or a custom trackPlayer/PlayerHandle adapter, on Apple
TV hosts.@everframe/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.
<EverframeProvider> 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 / :everframe-tv ReporterActivity
on Android), so React Native's focus engine never sees it — the native VC
manages focus on its own UIWindow / Activity.
<EverframeProvider config={{ apiKey }}>
<NavigationContainer>{/* focus engine root */}</NavigationContainer>
</EverframeProvider>
Everframe installs shake-to-report on Android and iOS phones/tablets through the
native SDKs. It is enabled by default, requires no permission, safely no-ops on
Android devices without an accelerometer, and never runs on Android TV or tvOS.
The dashboard is authoritative: local enabled: true cannot override a
dashboard disable.
In React Native and Expo development builds, use
shakeToReport: { enabled: !__DEV__ } because the React Native development
menu also uses shake. Production remains enabled by default.
All other gestures and keys are host-owned. The host app
calls useEverframe().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).
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.
import { Platform, TVEventHandler } from 'react-native';
import { useEverframe } from '@everframe/react-native';
import { useEffect } from 'react';
function useAppleTVReporterTrigger() {
const { open } = useEverframe();
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. Everframe'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).
import { Platform, TVEventHandler } from 'react-native';
import { useEverframe } from '@everframe/react-native';
import { useEffect } from 'react';
function useAndroidTVReporterTrigger() {
const { open } = useEverframe();
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.
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 emulator
That example's own README covers prebuild details and the known pitfalls of the TV targets.
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.
MIT
FAQs
React Native SDK for Everframe — AI-ready in-app bug reporting, bridging the native iOS and Android reporter to your RN app. Supports phone, Apple TV, and Android TV.
The npm package @everframe/react-native receives a total of 0 weekly downloads. As such, @everframe/react-native popularity was classified as not popular.
We found that @everframe/react-native demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.