Qaid
ARTICLE

Quests in iOS and Android Apps

Show a quest inside a native app with real SwiftUI and Compose views, inline in a screen or as a sheet.

Qaid Team
TL;DR

Add the QaidQuests Swift package or dev.qaid:quests, configure it with your embed key, and drop QaidQuestView (SwiftUI) or QaidQuest (Compose) into a screen, or call QaidQuests.present. Answers save as they’re given, wait on the device when offline, and land under the quest’s Responses like web answers do.

The quests SDK draws a quest with the platform’s own controls: text fields, sliders, date pickers and option lists. It reads the same quest you built for the web, so one quest serves your site and your apps.

What you need

iOS Android
Package https://github.com/qaiddev/quests-native, product QaidQuests dev.qaid:quests:0.1.0 from Maven Central
Minimum iOS 15, SwiftUI or UIKit minSdk 26, compileSdk 35, Jetpack Compose
Key Your project’s embed key, under Settings → API Keys Same key

The quest must be live. A draft that was never saved as a version answers “Quest is not published”, and the view shows its load error.

The quest’s id is in the editor’s address, /dashboard/projects/…/quests/<quest id>, and in the “Embed loads from” strip as /api/quests/<quest id>/definition.

Add the package

  1. iOS: add the Swift package

    In Xcode choose File → Add Package Dependencies, paste https://github.com/qaiddev/quests-native, and add the QaidQuests product to your app target.

  2. Android: add the dependency

    Add implementation("dev.qaid:quests:0.1.0") to your app module. The library is built with Compose, so your app needs the Compose compiler plugin, as any Compose app has.

  3. Configure once at launch

    Call QaidQuests.configure in your app delegate, App init or Application.onCreate. Android also takes the application, so answers saved offline can send at the next launch.

import QaidQuests

QaidQuests.configure(QaidQuestsConfiguration(
    apiKey: "YOUR_EMBED_KEY",
    appName: "My App"
))
QaidQuests.configure(this, QaidQuestsConfig(
    apiKey = "YOUR_EMBED_KEY",
    appName = "My App",
))

Put a quest in a screen

Inline, the quest sits in your layout like any other view and grows to fit its questions.

QaidQuestView(questId: "QUEST_ID", screen: "Onboarding") { answers in
    showNextStep()
}
QaidQuest(
    questId = "QUEST_ID",
    screen = "Onboarding",
    onComplete = { answers -> showNextStep() },
)

A UIKit app embeds QaidQuestViewController(questId:) as a child controller. A View-based Android app adds QaidQuestView to its layout and sets questId on it.

Show it as a sheet

QaidQuests.present(questId: "QUEST_ID", screen: "Settings")
QaidQuests.present(activity, questId = "QUEST_ID", screen = "Settings")

The sheet has a close button. Answers given before closing are already saved on qaid; the response just never gets its submit.

How answers are saved

Each answer goes to qaid a moment after the person gives it, as on the web. When the network is down, or qaid answers with a server error, the SDK keeps the answers on the device and sends them in order later: at the next launch, when the app comes back to the front, or when the network returns. The thank-you screen says they will send later. Up to 20 unsent responses are kept for 7 days.

onComplete gets the submitted answers, keyed by question id, with hidden questions left out. It fires for saved-for-later answers too.

Problems that are not the person’s fault reach QaidQuests.onError, so you can log them:

QaidQuests.onError = { report in
    Logger.qaid.error("\(report.operation.rawValue) \(report.questId): \(String(describing: report.error))")
}

Say who answered

Each response carries your app’s name, version and device in its user agent. The thumbs and quests SDKs share one visitor id per install, so a quest and a feedback report from the same phone name the same visitor.

Match your app’s look

The SDK follows the system’s light or dark mode. Use a saved quest theme with themeId, or set colours, font and corner radius in code; code wins over the theme.

QaidQuestsConfig(
    apiKey = "YOUR_EMBED_KEY",
    appName = "My App",
    themeId = "THEME_ID",
    theme = QaidQuestTheme(accent = 0xFF0EA5E9.toInt(), cornerRadius = 12f),
)

A theme’s custom CSS has no meaning in a native view and is ignored. Every string the SDK draws or reads aloud, from Next to the validation messages, can be replaced through text, so the quest can match your app’s language. The questions themselves come from the quest you wrote.

Domain Restriction and testing

With no pageUrl, a response names the app as app://<bundle id>, and qaid reads the id back to front: com.example.myapp passes a Domain Restriction of example.com.

To test offline saving, answer a quest in airplane mode, finish it, then turn the network back on and bring the app to the front. The response appears under the quest’s Responses within a few seconds.

Full API lists live in the SDK repository.

Back to all articles