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

    • Initialize
    • SDKConfig
    • Sending Messages
    • Generating Images
    • Conversation State
    • Locale
    • Status
    • Teardown
    Question? Give us feedback Edit this page 
    GuidesHeadless SDK

    Headless SDK

    Use Qafka’s backend without the built-in <Qafka> widget — bring your own chat UI and drive the SDK directly.

    Initialize

    import { QafkaSDK } from '@qafka/react-native' const sdk = QafkaSDK.getInstance() await sdk.initialize({ projectId: 'proj_abc123' }) // End-user identity is set separately, after initialize() — see below sdk.setEndUser(currentUser?.id ?? 'anonymous')

    QafkaSDK is a singleton — getInstance() always returns the same instance. getSDK() is a shorthand for the same call:

    import { getSDK } from '@qafka/react-native' const sdk = getSDK()

    projectId is required in production (keyless) builds — it’s sent with device attestation so the backend can resolve your project. In development, before attestation is set up, authenticate with a TEST key instead by passing apiKey:

    await sdk.initialize({ projectId: 'proj_abc123', apiKey: __DEV__ ? 'your-test-key' : undefined, })

    The devConfig prop that resolves a TEST key automatically is specific to the <Qafka> component’s useSDK hook — headless code reads the key itself (e.g. from your own config, or the same .qafka/qafka-runtime.js file the CLI writes) and passes it as apiKey. See API Key Security for how key types and attestation fit together.

    SDKConfig

    FieldTypeDescription
    projectIdstringTarget Qafka project. Required in production.
    apiKeystring | nullDevelopment API key (TEST key). Omit or leave null in production.
    subProjectIdstringSub-project identifier.
    apiUrlstringAdvanced — leave unset for production.
    localestringBCP 47 locale (e.g. "tr", "en-US"), forwarded as sdkContext.locale on every chat request. Explicit only — never derived from device language.
    navigationRefanyReact Navigation ref, used when the SDK navigates on your behalf.
    debugbooleanEnable verbose dev logging.
    timeoutnumberRequest timeout in ms.
    onStatusChange(status: SDKStatusType) => voidFires as the SDK moves through 'uninitialized' | 'initializing' | 'ready' | 'unavailable' | 'error'. This is how a headless caller finds out about an initialization failure or a suspended project — see Status below.
    onNavigationSuggest(suggestion) => voidFires whenever the backend suggests navigation.
    onError(error: Error) => voidDeclared on the config type, but initialize() does not currently call it — rely on onStatusChange (status 'error') instead, and wrap initialize() in try/catch since it also rejects.

    SDKConfig doesn’t take endUserId/endUserData — call setEndUser after initialize(), and whenever the identity changes:

    sdk.setEndUser(currentUser.id, { email: currentUser.email, plan: currentUser.plan })

    The first argument groups conversations, action logs, and analytics per user and is never forwarded to the LLM prompt. The second is optional structured profile data, also never forwarded to the LLM — unless a tool’s Description references either with {{endUser.*}} — both are reachable in dashboards/tool templates via {{endUser.id}} / {{endUser.data.<key>}}. See Context for the full context vs. endUserData split.

    Sending Messages

    // Single response const response = await sdk.sendMessage('Hello', context, contextDescription) // Streaming await sdk.sendMessageStream( 'Hello', (chunk) => console.log('Chunk:', chunk), (fullResponse) => console.log('Complete:', fullResponse), (error) => console.error('Error:', error), context, contextDescription, )

    sendMessage returns one complete reply but doesn’t run Server, Static Data or Calendar tools — those only execute on the streaming path. If your project uses any of them, send with sendMessageStream.

    Both throw if the SDK isn’t in the 'ready' status yet, or if the message is empty. context and contextDescription follow the same rules as the <Qafka> widget props — see Context.

    Generating Images

    const result = await sdk.generateImage({ description: 'product photo reframed to 16:9 landscape', aspectRatio: '16:9', quality: 'standard', })

    Requires the SDK to be 'ready'. See the package README  for the full parameter and result reference.

    Conversation State

    const history = await sdk.getConversationHistory() await sdk.clearConversation() const newSessionId = await sdk.startNewConversation()

    All three require the SDK to be 'ready'.

    Locale

    sdk.setLocale('tr') // or null to clear

    A no-op if called before initialize() — pass locale in SDKConfig for the initial value instead.

    Status

    const status = sdk.getStatus() // 'uninitialized' | 'initializing' | 'ready' | 'unavailable' | 'error'

    'unavailable' means the project is suspended — this is treated as an expected, recoverable state rather than an error; onStatusChange fires with 'unavailable'.

    Teardown

    await sdk.destroy()

    Tears down the current instance’s services and clears the shared singleton slot if this instance still owns it. Call it when your headless session ends (e.g. user signs out).

    Last updated on October 1, 2026
    React Native WidgetTheming

    © 2026 Qafka Labs OÜ