Navigation
The AI can suggest screens for the user to visit inside your app. The widget renders a button for each suggestion; tapping it triggers your navigation logic.
For navigation to work, the AI needs two pieces of information:
- Which screens exist — uploaded from your codebase via the CLI as a navigation schema.
- Where the user is right now — passed at runtime via Context (the
currentScreenkey is conventional but not required).
Handling Suggestions
Two callbacks are involved:
<Qafka
onNavigationSuggest={(suggestion) => {
// Always fires when the AI suggests a destination, even if the user ignores it
analytics.track('nav_suggested', { screen: suggestion.screenName })
}}
onNavigationAction={(suggestion) => {
// Fires when the user taps the navigation button.
// Omit this prop to let the SDK navigate automatically via Expo Router.
navigation.navigate(suggestion.route)
}}
/>A NavigationSuggestion has the following shape:
{
screenName: string // Display name (e.g. "Cart")
route: string // Route key for your navigator
deeplink?: string | null // Optional deeplink URL
confidence?: number // 0–1 — AI's confidence in the suggestion
confirmed?: boolean // True if AI already confirmed user intent
message?: string // Optional natural-language label
}If you don’t pass onNavigationAction, the SDK auto-navigates via expo-router’s router.push(suggestion.route ?? suggestion.screenName) (the route is normalized to start with /). When expo-router isn’t installed, the call is a silent no-op — wire onNavigationAction to your own navigator in that case.
Customizing the Button
Three levels of customization, from light to heavy:
1. Just change the label text:
<Qafka navigationLabelFormat={(screen) => `Go to ${screen}`} />2. Replace the entire button:
import { TouchableOpacity, Text } from 'react-native'
<Qafka
NavigationButtonComponent={({ screenName, suggestion, onPress, theme, label, icon }) => (
<TouchableOpacity onPress={onPress} style={myStyles(theme)}>
{icon ? <Icon name={icon} /> : null}
<Text>{label}</Text>
</TouchableOpacity>
)}
/>The component receives { screenName, suggestion, onPress, theme, style, label, icon } — label is the already-formatted text (after navigationLabelFormat), suggestion is the full NavigationSuggestion object.
3. Skip the button entirely by listening to onNavigationSuggest and rendering your own UI elsewhere in the app — chips, banner, push notification, anything.
Filtering by Auth State
Each screen in your navigation schema can be tagged with one of four accessType values from the dashboard’s navigation rules editor:
accessType | Meaning |
|---|---|
public | Anyone — default |
authenticated | Only suggested when the user is signed in |
unauthenticated | Only suggested when the user is signed out (e.g. Login, Sign Up) |
restricted | Never suggested — useful for admin-only or deprecated screens |
Pass isAuthenticated to the widget so the AI knows which side of the gate the user is on:
<Qafka isAuthenticated={!!user} />true—authenticatedandpublicscreens eligible;unauthenticatedhiddenfalse—unauthenticatedandpublicscreens eligible;authenticatedhidden- omitted — backward-compatible default: every non-
restrictedscreen is eligible
The widget forwards this flag automatically inside the context payload — no extra wiring needed.
Navigation Schema
The AI only suggests screens it knows about. Generate the schema from your codebase and upload it:
npx qafka analyze
npx qafka uploadanalyze scans your project and writes navigation-schema.json. upload sends it to your project’s backend after you’ve authenticated with qafka login.
Choosing the right analyze mode
| Command | What it does | When to use |
|---|---|---|
qafka analyze | Deterministic parsing — uses the dedicated Expo Router analyzer or the React Navigation Babel parser. No LLM calls. | Default. Fast, free, deterministic — the right starting point for most projects. |
qafka analyze --ai | Skips the deterministic parser; sends source files to an LLM for analysis. | When the deterministic parser misses screens (custom navigation patterns, dynamic registration, non-standard libraries). |
qafka analyze --deep | First runs the normal analyze, then asks the AI to extract per-screen metadata — descriptions, prop types, usage hints. Requires qafka login. Costs tokens. | When you want the AI to give richer, more accurate navigation suggestions. The extra metadata becomes part of every navigation prompt. |
qafka analyze --auto | Try deterministic first; fall back to --ai automatically on empty results. | CI pipelines where you don’t want the interactive “should I use AI?” prompt. |
qafka analyze --deep --incremental | Only re-extract metadata for screens that changed since the last --deep run. | Re-running --deep periodically without paying full token cost each time. |
For most projects the recommended workflow is: start with qafka analyze, add --deep once when you’re happy with the schema, and rerun with --deep --incremental after big screen-level changes. See CLI for the full flag surface.
Editing in the Dashboard
After upload, you can edit per-screen rules (auth requirement, descriptions, deeplinks, navigation hints) from the dashboard’s navigation editor — including overriding any accessType the AI inferred during --deep analysis.