API reference

@fixback/expo reference

The complete API of @fixback/expo. For a narrative walkthrough, see the Expo & React Native guide.

Exports

tsx
import { FixbackProvider, useFixback, Fixback } from "@fixback/expo";// in a component:const { present, trackScreen } = useFixback();// or module-level, anywhere:Fixback.present();
ExportDescription
<FixbackProvider options={…}>Wrap your app once. Takes the options below.
useFixback()Hook returning status, canSubmit(), present(), trackScreen(name), and signIn() / signOut() / identity() / onIdentity(fn).
FixbackModule-level object: the same members as the hook (status reads live from the mounted provider) — call from anywhere.

Provider options

OptionDefaultWhat it does
key—The publishable key of the environment this build reports into (required). It decides where reports land and whose Gate applies — there is no environment option.
origin—Optional. The origin sent on every request. A native app sends no Origin header and ingest demands none, so omit it unless you want mobile reports to carry an origin — then allowlist the same value on the Project.
apiUrlhttps://api.fixback.devSelf-hosted Fixback API base.
enabledtrueMaster switch — false arms nothing and captures nothing.
release—The build identifier stamped on every capture and shown on the Issue. Not yet symbolicated on this platform — a React Native bundle map is not discovered by the uploader, and Hermes frames need handling the symbolicator does not do yet. Web and Node are unaffected.
returnUrl—Where a Connect your app starts returns in place, through an in-app auth session — a custom scheme (myapp://fixback-connect) or a universal link your app handles. Its origin must be on the Project's allowed origins (add it under App link); a development build's exp:// URL is a separate origin and needs its own entry. Optional: without it, signIn opens the connect page in an in-app browser and comes back through an app link the Project lists — the way a claimed invite always arrives. With it set, the SDK reads a Connect code only off inbound links on its origin.
hostIdentity—A server-minted Host identity JWT, signed with a secret key of the same environment as key — tier the user from your own backend without Connect.
anonymousIda persisted per-install idA stable id for an anonymous reporter, if you would rather supply your own.
captureserver config{ console?, network?, replay? } per-stream toggles. Console and network arm when the provider mounts, before the boot answer lands, so startup logging is in the trace; a stream the Project turns off is then uninstrumented and what it recorded is dropped. replay is the exception — it is off unless you set it (see below).
propagateTo[] — nothing sentYour own APIs, as origins — e.g. ["https://api.example.com"] — whose requests carry the Correlation id. A request to any other origin is never touched.
autoCapturetrueAutomatic uncaught-error reports.
screenshotstrueCapture a screenshot when the composer opens.
replayoffSession-replay tuning — { fps?, maxEdge?, frameQuality? }. Passing it also turns replay on; see below.
beforeSend—Reshape or drop (null) any report before transport.
scrubtrueThe built-in URL / PII scrubbers.
beforeBreadcrumb—Filter / edit trace entries at the source.
shakeonThe shake gesture — see below.

shake options

Passed as shake: { … }. Set enabled: false to turn the gesture off entirely.

KeyWhat it does
enabledTurn the shake gesture on or off.
thresholdGThe acceleration (in g) that counts as a shake peak.
minPeaksHow many peaks make a deliberate shake.
windowMsThe window the peaks must fall within.
minGapMsMinimum gap between counted peaks.
cooldownMsHow long to wait before another shake can fire.
sampleIntervalMsAccelerometer sampling interval.

useFixback()

MemberDescription
statusThe live lifecycle state — idle, starting, ready, disabled. ready only once boot said a submission would be accepted.
canSubmit()Whether a submission would be accepted right now — the server's answer, so app code needs no Gate logic.
present()Open the feedback composer programmatically.
trackScreen(name)Record a navigation crumb; the active screen names the report's URL.
signIn()Start a Connect — open the platform's connect page in an in-app auth session and bind the Account. Resolves to the resulting identity.
signOut()Clear the Reporter session — revoke it and forget the token.
identity()The current identity — anonymous, or a connected Account with its tier.
onIdentity(fn)Subscribe to identity changes (boot, sign in, sign out); returns an unsubscribe. What keeps a settings row current, since signing in does not always change status.

Connect — reporting as an account

A Reporter is a Fixback Account. The composer's identity row shows “Anonymous · Sign in”; tapping it opens Fixback's connect page (Google, GitHub, Sign in with Apple, magic link) — in an in-app auth session that returns in place when you declare a returnUrl in the provider options, otherwise in an in-app browser, which comes back through an app link the Project lists. The SDK stores the resulting Reporter session in Expo SecureStore and the composer then shows the Account and tier. A Member of the owning Org reports at the internal tier. Behind an Invited or Internal Gate the shake gesture stays disarmed until a Connect makes the Account eligible — enter it with Fixback.signIn() from your own UI.

A Connect can also start outside the app. Someone invited to the Project claims the invite in their email, on Fixback's claim page, and is sent back to the app through an app link the Project lists, carrying a one-time code — no returnUrl needed. The SDK reads that code off the link the app was opened with — or one delivered while it is running — and signs them in as they arrive, so an invited tester needs no separate signIn(). It redeems a given code once, and when you declare a returnUrl it acts only on links whose origin matches it.

ts
// Connect the signed-in Account (e.g. from a settings row):await Fixback.signIn();   // opens the platform's connect page in an auth sessionFixback.identity();       // { status: "anonymous" } | { status: "connected", name, email, tier }Fixback.canSubmit();      // whether reporting is live for this Reporter, per bootawait Fixback.signOut();  // revokes the session and clears SecureStore

Session replay

Mobile replay is a buffered window of your app's screen — 30–60 seconds at one frame a second — encoded into a single H.264/MP4 when a report is sent, and played back in the Issue's Replay tab beside the merged console / network timeline. The encoder ships with the SDK as @fixback/expo-replay-encoder; you never install or call it yourself.

Two things are required, and both are deliberate:

  • You opt in, in code. Pass capture: { replay: true }, or simply a replay tuning object. The recording is not masked — it is the screen as your app drew it — so updating the SDK never starts one.
  • The Project enables replay in its capture settings. That toggle is the kill switch: with it off, nothing is recorded whatever your code asks for.

It also needs a development build. The encoder is native code, which Expo Go cannot load: run npx expo prebuild and build with EAS or locally. In Expo Go the SDK logs why and reports without replay — nothing breaks.

tsx
<FixbackProvider  options={{    key: "pk_…",    // Opt in — and enable replay for the Project in its capture settings.    capture: { replay: true },    // Optional tuning; passing this object is itself an opt-in.    replay: { fps: 1, maxEdge: 960 },  }}>  <App /></FixbackProvider>
KeyDefaultWhat it does
fps1Frames per second. Each step up multiplies both the per-second cost on the JS thread and the payload.
maxEdge960Longest edge of the encoded video in pixels. A smaller window is never scaled up.
frameQuality0.6JPEG quality of each captured frame, 0–1. The frames are an intermediate the encoder discards, so this trades capture cost against detail surviving into the video.

The Correlation id

Every request your app makes to an origin listed in propagateTo goes out with a freshly minted W3C traceparent header (00-<32-hex id>-<16-hex parent>-01), and the request's network entry records that 32-hex id. When that backend runs @fixback/node, it adopts the same id for any error the request causes, so the app's Issue for a failed request and the server Issue behind it show the same Correlation id and link to each other — exactly as the web SDK's do.

tsx
<FixbackProvider  options={{    key: "pk_…",    // Your own APIs: requests to them carry the Correlation id.    propagateTo: ["https://api.example.com"],  }}>  <App /></FixbackProvider>
  • Nothing is sent unless you list it. The web SDK always stamps requests to the page's own origin; an app has no origin of its own, so on mobile the list is the whole rule, and a third-party API your app calls never sees a header it did not ask for.
  • Entries are bare origins — scheme://host[:port], the same shape as the web SDK's propagateTo. A path, a query, or a wildcard makes an entry mean something the SDK does not do, so it is ignored with a warning in development builds.
  • fetch is covered. React Native's fetch runs on XMLHttpRequest, which is what the SDK instruments, so both carry the header. With network capture off (capture: { network: false }, or the Project's setting) nothing is sent.
  • Never breaks a request. The SDK never reads a header value and never overrides one: a traceparent your app or its tracing library sets is the one that goes out, and that request records no id. A request whose header cannot be set simply goes out without it.
  • The sampled flag is 01, so a parent-based OpenTelemetry sampler on your server records these requests rather than dropping them.
  • Repeats keep their ids. A captured error that happens again is counted and sent later — when the app leaves the foreground — as a light update with no Trace; that update carries just the Correlation ids of the requests made before the repeats, so Fixback records every occurrence's requests, not only the first one's.
  • The id is random: it identifies one request, never a person or a session.