API reference
@fixback/expo reference
@fixback/expo. For a narrative walkthrough, see the Expo & React Native guide.Exports
import { FixbackProvider, useFixback, Fixback } from "@fixback/expo";// in a component:const { present, trackScreen } = useFixback();// or module-level, anywhere:Fixback.present();| Export | Description |
|---|---|
<FixbackProvider options={…}> | Wrap your app once. Takes the options below. |
useFixback() | Hook returning status, canSubmit(), present(), trackScreen(name), and signIn() / signOut() / identity() / onIdentity(fn). |
Fixback | Module-level object: the same members as the hook (status reads live from the mounted provider) — call from anywhere. |
Provider options
| Option | Default | What 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. |
apiUrl | https://api.fixback.dev | Self-hosted Fixback API base. |
enabled | true | Master 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. |
anonymousId | a persisted per-install id | A stable id for an anonymous reporter, if you would rather supply your own. |
capture | server 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 sent | Your 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. |
autoCapture | true | Automatic uncaught-error reports. |
screenshots | true | Capture a screenshot when the composer opens. |
replay | off | Session-replay tuning — { fps?, maxEdge?, frameQuality? }. Passing it also turns replay on; see below. |
beforeSend | — | Reshape or drop (null) any report before transport. |
scrub | true | The built-in URL / PII scrubbers. |
beforeBreadcrumb | — | Filter / edit trace entries at the source. |
shake | on | The shake gesture — see below. |
shake options
Passed as shake: { … }. Set enabled: false to turn the gesture off entirely.
| Key | What it does |
|---|---|
enabled | Turn the shake gesture on or off. |
thresholdG | The acceleration (in g) that counts as a shake peak. |
minPeaks | How many peaks make a deliberate shake. |
windowMs | The window the peaks must fall within. |
minGapMs | Minimum gap between counted peaks. |
cooldownMs | How long to wait before another shake can fire. |
sampleIntervalMs | Accelerometer sampling interval. |
useFixback()
| Member | Description |
|---|---|
status | The 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.
// 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 SecureStoreSession 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 areplaytuning 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.
<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>| Key | Default | What it does |
|---|---|---|
fps | 1 | Frames per second. Each step up multiplies both the per-second cost on the JS thread and the payload. |
maxEdge | 960 | Longest edge of the encoded video in pixels. A smaller window is never scaled up. |
frameQuality | 0.6 | JPEG 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.
<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'spropagateTo. 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. fetchis covered. React Native'sfetchruns onXMLHttpRequest, 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
traceparentyour 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.