Skip to Content
    QAFKA
    CTRL K
    CTRL K
    • Introduction
      • Quick Start
      • Configuration
      • React Native Widget
      • Theming
      • Context
      • Navigation
      • External Navigation
      • Handling Tools
      • Voice Chat
      • Sub-Projects
      • Error Handling
      • CLI
      • Dashboard
      • Invitations
      • Settings
        • Project
        • Overview
        • Conversations
        • Chat Test
        • Sub-Projects
        • Analysis
        • Configuration
        • Members
        • Documents
        • Tools
        • Action Logs
        • Navigation Rules
        • External Destinations
        • Chat Theme
        • API Keys
      • API Key Security
    • Introduction
      • Quick Start
      • Configuration
      • React Native Widget
      • Theming
      • Context
      • Navigation
      • External Navigation
      • Handling Tools
      • Voice Chat
      • Sub-Projects
      • Error Handling
      • CLI
      • Dashboard
      • Invitations
      • Settings
        • Project
        • Overview
        • Conversations
        • Chat Test
        • Sub-Projects
        • Analysis
        • Configuration
        • Members
        • Documents
        • Tools
        • Action Logs
        • Navigation Rules
        • External Destinations
        • Chat Theme
        • API Keys
      • API Key Security

    On This Page

    • When to Use Sub-Projects
    • The SDK Contract
    • Identifying a Sub-Project
    • Switching at Runtime
    • Voice and Sub-Projects
    • Patterns
    • Location Switcher
    • Auth-Driven Tenant Routing
    • Single-Project Fallback
    • Errors
    Question? Give us feedback Edit this page 
    GuidesSub-Projects

    Sub-Projects

    Sub-projects let one parent project serve multiple tenants from the same SDK install — same parent project, but the SDK passes a subProjectId to route each session to the right child. The mobile codebase stays the same; the AI configuration (greeting, tools, theme, conversations) varies by tenant.

    This page covers the SDK side — the prop, the runtime behavior, and the cross-feature limits. For dashboard-side configuration (creating sub-projects, inheritance, per-sub-project conversations), see Dashboard › Sub-Projects.

    When to Use Sub-Projects

    Sub-projects are the right answer when one mobile app serves multiple distinct tenants that each need their own AI personality, knowledge base, or branding — but you don’t want the engineering cost of running multiple builds or multiple integrations.

    Concrete examples:

    • Multi-location app — same app for every branch, but each branch’s AI knows its own offerings and promotions (works for a restaurant chain, a clinic network, a bank, a gym franchise)
    • Multi-brand retail — same shopping app for several brand partners, each with its own tone and product catalog
    • White-label deployment — one codebase you ship to multiple customer organizations, each with their own assistant
    • Regional variants — same app worldwide, but the AI varies by country’s documents and rules

    If your app serves a single tenant, don’t use sub-projects — they add a layer of indirection (the parent + the child) that buys nothing in single-tenant cases. Use one project.

    The SDK Contract

    Sub-project routing is a top-level prop, not part of the runtime context:

    <Qafka subProjectId="branch-london" />

    This is a deliberate API decision — putting subProjectId inside context would make it look like one more piece of optional metadata, when in reality it’s a routing key that changes which project the SDK is talking to. Mistakes here ripple silently: a misnamed key in context would be ignored; a wrong subProjectId prop produces a clear Sub-project not found error.

    Identifying a Sub-Project

    The subProjectId value can be either:

    • The sub-project’s UUID (immutable, generated by the dashboard) — e7f2a4b8-3c5d-4f1a-9d8b-2e1f5c4a7b6d
    • A human-readable identifier you set in the dashboard — branch-london, branch-nyc, tenant-acme

    The backend tries UUID first, then falls back to identifier match within the parent. Prefer human-readable identifiers — they’re easier to debug from the conversations view, easier to thread through your app’s existing branch/tenant ID model, and stable across environments.

    Switching at Runtime

    When subProjectId changes, the SDK fully tears down the current session and reinitializes against the new sub-project. This means:

    • The active conversation ends — the user starts fresh in the new sub-project
    • Any in-flight message is dropped
    • Theme, greeting, tools, and instructions all reload from the new sub-project
    • The voice session, if active, is closed (see voice limitation below)

    Practically, this is what you want — switching tenants mid-conversation almost never makes semantic sense (“show me Branch A’s menu — actually no, Branch B’s”). But be deliberate about when you change the prop:

    // User picks a different branch from a location switcher → re-mount with new ID <Qafka subProjectId={selectedBranch.identifier} />

    If you wrap <Qafka /> in your own location-switcher UI, don’t pipe a frequently-changing value into subProjectId. Memoize or settle on the chosen tenant before passing it in.

    Voice and Sub-Projects

    Voice chat currently does not respect subProjectId — voice sessions always land on the parent project regardless of which child the rest of the SDK is configured for. This is a known gap on the voice roadmap (sub-project-aware voice routing is on the roadmap alongside Tool V2 and userContext personalization for voice).

    If sub-project-specific voice configuration is critical for your launch, fall back to text chat for sub-project flows, or hide the voice page on sub-project screens via the voiceEnabled={false} prop until the gap is closed.

    Patterns

    Location Switcher

    User picks a branch from a list, the chat for that branch opens:

    function BranchChatScreen({ branch }) { return <Qafka subProjectId={branch.identifier} /> }

    When the user navigates between branch screens, the parent component remounts <Qafka /> with the new identifier and the chat re-initializes against that branch’s sub-project.

    Auth-Driven Tenant Routing

    User signs in; their tenant is on the user record:

    function ChatScreen() { const { user } = useAuth() if (!user) return <LoginPrompt /> return ( <Qafka subProjectId={user.tenantId} isAuthenticated context={{ userId: user.id, role: user.role }} /> ) }

    Notice userId and role go in context — those are runtime metadata. tenantId is subProjectId because it’s a routing key.

    Single-Project Fallback

    If subProjectId is undefined (or omitted), the SDK falls through to the parent project — the same behavior as a single-tenant app. This is useful when your app is gradually migrating to multi-tenancy:

    <Qafka subProjectId={tenant?.identifier} /> {/* undefined for users not yet assigned to a tenant */}

    Users on the parent fallback see the parent’s greeting, tools, and documents. Users with a sub-project assigned see their sub-project’s overrides on top.

    Errors

    The SDK surfaces sub-project resolution errors through onError. The most common ones:

    ErrorWhat it means
    Sub-project not foundThe subProjectId value didn’t match any active child of the active parent project. Check the value against the dashboard.
    Project not foundYou passed subProjectId for a project that’s already a sub-project (sub-projects can’t have sub-projects of their own).

    If the subProjectId is missing or empty, the SDK silently uses the parent — that is not an error.

    Last updated on June 3, 2026
    Voice ChatError Handling

    MIT 2026 QAFKA