Skip to Content
    Qafka
    CTRL K
    CTRL K
    • Introduction
      • Quick Start (React Native)
      • Quick Start (Website)
      • React Native Configuration
      • Overview
      • npm & React
      • Options Reference
      • WordPress
      • React Native Widget
      • Headless SDK
      • Theming
      • Context
      • Navigation
      • External Navigation
      • Handling Tools
      • Voice Chat
      • Sub-Projects
      • Error Handling
      • CLI
      • Dashboard
      • Onboarding
      • Invitations
      • Billing
      • Usage
      • Settings
      • Sign-in & Account
      • Dashboard Assistant
        • Project
        • Overview
        • Conversations
        • Chat Test
        • Sub-Projects
        • Analysis
        • Unanswered Questions
        • Insights
        • Configuration
        • AI Behavior
        • Members
        • Documents
          • Overview
          • Create with AI
          • Versions
          • Response Channel
        • Action Logs
        • Navigation Rules
        • External Destinations
        • Chat Theme
        • PII Masking
        • Websites
        • Mobile Apps
        • API Keys
        • Project Settings
      • API Key Security
    • Introduction
      • Quick Start (React Native)
      • Quick Start (Website)
      • React Native Configuration
      • Overview
      • npm & React
      • Options Reference
      • WordPress
      • React Native Widget
      • Headless SDK
      • Theming
      • Context
      • Navigation
      • External Navigation
      • Handling Tools
      • Voice Chat
      • Sub-Projects
      • Error Handling
      • CLI
      • Dashboard
      • Onboarding
      • Invitations
      • Billing
      • Usage
      • Settings
      • Sign-in & Account
      • Dashboard Assistant
        • Project
        • Overview
        • Conversations
        • Chat Test
        • Sub-Projects
        • Analysis
        • Unanswered Questions
        • Insights
        • Configuration
        • AI Behavior
        • Members
        • Documents
          • Overview
          • Create with AI
          • Versions
          • Response Channel
        • Action Logs
        • Navigation Rules
        • External Destinations
        • Chat Theme
        • PII Masking
        • Websites
        • Mobile Apps
        • API Keys
        • Project Settings
      • API Key Security

    On This Page

    • Why External Navigation Exists
    • Destination Types
    • The Suggestion Shape
    • Default Behavior
    • Customizing the Action
    • Tracking Analytics
    • In-App WebView for website
    • Confirmation Modal Before Leaving
    • Handling Missing Target Apps
    • Media Destinations (embed / document)
    • Voice Mode
    • Configuring Destinations
    Question? Give us feedback Edit this page 
    GuidesExternal Navigation

    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 upA screen in your React Native appA different app on the device, or a web URL
    What you configureNavigation rules per screenDestinations per project
    What the SDK receivesNavigationSuggestion via onNavigationSuggestExternalSuggestion via onExternalSuggestion
    What happens by defaultRoutes via Expo RouterOpens via Linking.openURL

    Destination Types

    Eleven 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”).

    TypeUsed for
    whatsappDirect chat with a customer support number
    phoneCall a phone number (dialer)
    smsOpen the SMS composer pre-filled with a number
    emailOpen the mail composer pre-filled with an address (and optional subject)
    websiteOpen an external web URL (help center, blog, landing page)
    mapOpen the device’s map app at a specific address (platform-aware: Apple Maps on iOS, Google Maps elsewhere)
    app_storeOpen the right store URL for the device (iOS App Store / Play Store)
    socialOpen a social media app or profile (Instagram, X, TikTok, LinkedIn, YouTube)
    deeplinkGeneric catch-all — any custom URL scheme the typed list doesn’t cover (Uber, Spotify, niche apps)
    embedShare a video or social post (e.g. YouTube, Instagram) inline
    documentShare a link to a document (e.g. a PDF)

    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. embed and document are media types — instead of redirecting, they carry a media payload (title, description, image) meant to be rendered as an in-chat card. See Media Destinations below for how each SDK handles them today.

    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' | 'sms' | 'email' | 'website' | 'map' | 'app_store' | 'social' | '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 React Native SDK’s ExternalSuggestion type does not carry a media field — see Media Destinations.

    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 device’s platform.

    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 // projectId, endUserId, … 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 // projectId, endUserId, … 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 // projectId, endUserId, … 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 // projectId, endUserId, … 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).

    Media Destinations (embed / document)

    embed and document destinations carry a media payload — the backend resolves a video/social-post embed or a document link into a title, description and optional image, meant to be rendered as an in-chat card instead of a plain redirect button.

    • Web widget — renders embed/document suggestions as in-chat media cards. It announces this at request time via an inline_media client capability. On the web SDK, ExternalSuggestion carries an optional media field for these two types: kind: 'embed' (with provider, providerLabel, embedUrl, and optional aspectRatio/height) or kind: 'document', both with title and optional description, imageUrl, siteName. An embed card plays in the chat when clicked; a document card opens its link in a new tab.
      • Not forwarded to onExternalSuggestion. The widget draws media suggestions itself, so they never reach your onExternalSuggestion callback — only regular destinations (WhatsApp, phone, links, …) do. If you render your own external buttons from that callback, you won’t get a duplicate button for a video the widget is already showing, but you also can’t intercept or restyle media cards there.
      • At most one video/post card per reply. A single answer shows at most one embed card; when several match, the best-scoring one is kept. document cards aren’t subject to this limit.
    • React Native SDK — never receives embed/document suggestions at all. The backend filters both types out server-side for any client that hasn’t declared inline-media support, before the AI even sees them as candidates; the React Native SDK doesn’t declare it, so these destinations are effectively web-only. (The ExternalSuggestion type also doesn’t include a media field, and there’s no special-cased handling for the two types, so even a suggestion that somehow arrived would just fall through to the default Linking.openURL path — but in practice it never arrives.)

    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.

    If your project relies heavily on external suggestions, surface those flows from text chat.

    Configuring Destinations

    The AI can only suggest destinations you’ve defined in the dashboard’s External Destinations page. Matching is driven by each destination’s Purpose (an AI instruction), Keywords, and Example User Questions — not its Description, which is an internal note never shown to the AI. A destination that doesn’t match any of the three for a given message is never suggested for it, so fill in more than just a one-line Purpose. Without configured destinations, no external event ever fires regardless of what the user types.

    Last updated on October 1, 2026
    NavigationHandling Tools

    © 2026 Qafka Labs OÜ