External Navigation
External suggestions are buttons the AI offers under its messages that take the user outside your app — to WhatsApp, a phone dialer, the app store, a map, a website, or any other deeplink. They sit alongside in-app Navigation suggestions in the same chat surface; the user doesn’t have to think about which kind of action they’re tapping.
This page covers the SDK side — what suggestions look like at runtime, the SDK’s default tap behavior, and when to override it. For configuring which destinations the AI is allowed to suggest, see Dashboard › External Destinations.
Why External Navigation Exists
Most chatbots have to fudge “outside the app” actions: pretend WhatsApp is an in-app screen, jam phone numbers into a tool description, or write a custom rendering for every off-app destination. Qafka treats them as a first-class concept so the AI can suggest “talk to support on WhatsApp” or “open in Maps” with a real button — typed, validated, with predictable platform behavior.
The mental model parallels in-app navigation:
| In-app (Navigation) | Off-app (External Navigation) | |
|---|---|---|
| Where the user ends up | A screen in your React Native app | A different app on the device, or a web URL |
| What you configure | Navigation rules per screen | Destinations per project |
| What the SDK receives | NavigationSuggestion via onNavigationSuggest | ExternalSuggestion via onExternalSuggestion |
| What happens by default | Routes via Expo Router | Opens via Linking.openURL |
Destination Types
Nine typed destinations are supported. Each has its own validation, icon, and platform handling — the AI knows what kind of phrase to use for each (“message us on WhatsApp” vs “download the app” vs “open in Maps”).
| Type | Used for |
|---|---|
whatsapp | Direct chat with a customer support number |
phone | Call a phone number (dialer) |
sms | Open the SMS composer pre-filled with a number |
email | Open the mail composer pre-filled with an address (and optional subject) |
website | Open an external web URL (help center, blog, landing page) |
map | Open the device’s map app at a specific address (platform-aware: Apple Maps on iOS, Google Maps elsewhere) |
app_store | Open the right store URL for the device (iOS App Store / Play Store) |
social | Open a social media app or profile (Instagram, X, TikTok, LinkedIn, YouTube) |
deeplink | Generic catch-all — any custom URL scheme the typed list doesn’t cover (Uber, Spotify, niche apps) |
The first eight are “first-class”: admin sets one config field (phone number, URL), the system generates the right URL with the right platform handling. deeplink requires the admin to write the URL scheme and a fallback URL by hand.
The Suggestion Shape
When the AI suggests an external destination, the SDK receives it as:
interface ExternalSuggestion {
id: string // unique ID for the suggestion
type: ExternalType // 'whatsapp' | 'phone' | ... | 'deeplink'
label: string // button label (e.g. "Message on WhatsApp")
icon: string // icon key (e.g. "logo-whatsapp")
url: string // the resolved URL to open (already platform-aware)
fallbackUrl?: string // alternate URL when `url` isn't handleable
}The url is already resolved by the backend using the destination type’s platform-aware logic. You don’t need to translate whatsapp://send?phone=... to https://wa.me/... yourself — the backend gives you the right value for the request’s x-platform header.
Default Behavior
If you don’t pass an onExternalSuggestion prop, the SDK opens the URL via React Native’s Linking API, with a fallback for cases where the target app isn’t installed:
Linking.canOpenURL(url)
↓ true ↓ false
Linking.openURL(url) fallbackUrl ? Linking.openURL(fallbackUrl) : (no-op)Errors are silently swallowed by default. If you want to catch them — to log analytics, show a toast, or fall back to your own UI — provide the callback.
Customizing the Action
Pass onExternalSuggestion to take over what happens when the user taps a button. The callback receives the full ExternalSuggestion and you decide what to do with it.
Tracking Analytics
The most common reason to override — log every external tap so you can see which destinations are actually used:
import { Linking } from 'react-native'
<Qafka
onExternalSuggestion={(s) => {
analytics.track('external_nav_press', {
type: s.type,
destinationId: s.id,
label: s.label,
})
Linking.openURL(s.url)
}}
/>Note that providing the callback means you are now responsible for opening the URL — the SDK’s default handler doesn’t fire when you set this prop.
In-App WebView for website
Open external websites in your own in-app browser instead of bouncing the user to Safari/Chrome:
<Qafka
onExternalSuggestion={(s) => {
if (s.type === 'website') {
navigation.navigate('WebViewScreen', { url: s.url })
return
}
Linking.openURL(s.url) // everything else uses default behavior
}}
/>Confirmation Modal Before Leaving
For high-friction destinations (paid call lines, app store deeplinks during a checkout flow), confirm before leaving:
<Qafka
onExternalSuggestion={(s) => {
if (s.type === 'phone') {
Alert.alert(
'Call customer support?',
s.label,
[
{ text: 'Cancel', style: 'cancel' },
{ text: 'Call', onPress: () => Linking.openURL(s.url) },
],
)
return
}
Linking.openURL(s.url)
}}
/>Handling Missing Target Apps
The default handler checks canOpenURL and falls back automatically. If you take over, you’ll likely want to do the same:
<Qafka
onExternalSuggestion={async (s) => {
const canOpen = await Linking.canOpenURL(s.url)
if (canOpen) {
await Linking.openURL(s.url)
return
}
if (s.fallbackUrl) {
await Linking.openURL(s.fallbackUrl)
return
}
Toast.show('The required app is not installed')
}}
/>This is especially relevant for whatsapp (WhatsApp not installed → fall back to wa.me web link) and app_store (right store opens directly on the right OS, no fallback needed).
Voice Mode
External suggestions do not fire in voice chat today. Voice can speak about external destinations (“you can reach support on WhatsApp at…”), but the buttons aren’t rendered in the voice page. This is a known gap on the same roadmap that adds Tool Registry and navigation suggestions to voice.
If your project relies heavily on external suggestions, surface those flows from text chat — voice mode is currently best for narrative Q&A, not action-oriented prompts.
Configuring Destinations
The AI can only suggest destinations you’ve defined in the dashboard’s External Destinations page. Destinations carry a description and keywords that drive the AI’s matching — the better the description, the more accurate the suggestion. Without configured destinations, no external event ever fires regardless of what the user types.