clariodesk 0.3.0 copy "clariodesk: ^0.3.0" to clipboard
clariodesk: ^0.3.0 copied to clipboard

ClarioDesk Flutter SDK — in-app customer support chat, bug reporting with auto screenshots, and feedback for mobile apps. Prebuilt UI or headless API.

clariodesk #

In-app support and bug reporting for Flutter apps. The native half of the ClarioDesk SaaS — drop the SDK in, get a hardware-bound device identity and a live ticket UI. Anonymous/device identity needs no host backend; verified cross-device identity uses a host token endpoint or pinned OIDC.

Integrating with an AI agent? (Claude Code, Cursor, Codex) Paste the install prompt and it does this whole README for you — detect, ask, install, verify. Machine-readable docs: llms.txt · rules for AI agents.

What ships #

  • ClarioDesk.init, ClarioDesk.identify, ClarioDesk.createTicket, ClarioDesk.sendMessage, ClarioDesk.ticketsStream, ClarioDesk.messagesStream, ClarioDesk.reset.
  • iOS Secure Enclave / Android Keystore-backed ECDSA P-256 keypair. Generated on first launch, never extractable.
  • Challenge-response device registration, per-request signatures, signed SSE handshakes.

Quick start #

import 'package:clariodesk/clariodesk.dart';

Future<void> main() async {
  // First call generates the hardware key + registers with the backend.
  // Subsequent launches reuse the existing key (no network).
  await ClarioDesk.init(apiKey: 'pk_live_…');

  runApp(const MyApp());
}

// Without a token/provider this is optional, unverified display metadata.
// externalId = your auth's stable user id (Firebase uid, Clerk user.id) —
// never an auth token, never an email.
// See "Lifecycle integration" below for the four host events you need
// to wire (especially case 1, which covers users who were already
// logged in before you installed the SDK).
await ClarioDesk.identify(
  externalId: hostUser.id,
  email: hostUser.email,
  traits: {'plan': 'pro'},
);

// File a ticket.
final t = await ClarioDesk.createTicket(
  subject: 'Upload broken',
  body: 'Tapping upload does nothing.',
);

// Reactive inbox — auto-primes + live updates.
StreamBuilder<List<Ticket>>(
  stream: ClarioDesk.ticketsStream(),
  builder: (_, snap) => /* … */,
);

Lifecycle integration #

Four host events touch the SDK. Wire each one and you're done.

1. App launch (every time, including for already-logged-in users) #

The most common integration miss: existing users who installed your app before you added ClarioDesk never go through the login flow again, so an "identify on login" hook alone leaves them as unlabeled devices.

Hydrate from your own persisted session on launch and identify unconditionally — identify() is idempotent (same values = no-op write) and cheap (one signed POST, ~5–25 ms).

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await ClarioDesk.init(apiKey: 'pk_live_…');

  final user = await yourAuth.currentUser();   // Firebase, Supabase,
                                                // your own session store, …
  if (user != null) {
    await ClarioDesk.identify(
      externalId: user.id,
      email: user.email,
      traits: {'plan': user.plan},
    );
  }

  runApp(const MyApp());
}

2. Fresh login or signup #

Right after your auth succeeds:

await yourAuth.signIn(email, password);
await ClarioDesk.identify(
  externalId: user.id,
  email: user.email,
  traits: {'plan': user.plan},
);

This overwrites the label on the existing device row — no new device gets registered, no new hardware key gets generated. The same device now carries the new user's metadata.

3. Logout #

await ClarioDesk.clearIdentity(); // when Verified identity is enabled
await yourAuth.signOut();

clearIdentity() preserves the key and advances the signed identity epoch. reset() is acknowledged one-installation deprovisioning, not logout or customer erase.

4. User switch (account A → account B without app restart) #

await ClarioDesk.clearIdentity();
await yourAuth.switchTo(userB);
await ClarioDesk.identify(identityMode: IdentityMode.host);

Create and await the clear intent before activating user B. Invalid proofs never fall back to label-only identity.

What if I never call identify()? #

Tickets still work. The device row exists, agents see a device id but no email — the dashboard shows an "Unverified device" badge. Useful for anonymous-feedback flows; otherwise call identify() from case 1 above and you're covered.

Auth model #

You ship one publishable API key (pk_live_…) in your app binary. Its only capability is letting a fresh install register a device with us — it cannot read tickets or impersonate users. Every authenticated call the SDK makes is signed by the device's hardware-bound private key.

If your key leaks, an attacker can register throwaway devices (rate- limited and bounded) but cannot touch any existing user's data. There is no separate "secure mode" to enable, no HMAC backend to build, no identity-verification setup. You ship the key, your users are secure by default.

Full documentation at docs.clariodesk.com.

Push notifications #

The host owns firebase_messaging and passes a PushTokenProvider to ClarioDesk.init; the SDK never imports Firebase. Route shared handlers with ClarioDesk.isClarioMessage(message.data).

On a notification tap in 0.3.0+, await ClarioDesk.resolvePushTarget(message.data) and route the returned TicketPushTarget or InboxPushTarget with your Navigator/GoRouter. The raw payload deliberately contains no ticket id: its opaque deliveryId is resolved only by the signed API. With the prebuilt UI, call ClarioDeskWidgets.openFromPush(context, message.data).

Custom screens mark only their focused support route:

await ClarioDesk.setVisibleSupportSurface(SupportSurface.inbox);
await ClarioDesk.setVisibleSupportSurface(SupportSurface.ticket(ticketId));
await ClarioDesk.clearVisibleSupportSurface(); // blur/pop

The prebuilt UI owns this automatically. A reply alerts immediately everywhere else; a stale visible-route lease can wait at most two seconds for the specific realtime render acknowledgement. Handle both FirebaseMessaging.onMessageOpenedApp and killed-app getInitialMessage() after ClarioDesk and your Navigator/GoRouter are ready.

See the push guide.

Platforms #

  • iOS — Secure Enclave when present (most iPhones since 5s), software-backed Keychain otherwise. Requires iOS 13+.
  • Android — StrongBox when supported (Pixel 3+, recent Samsung), TEE-backed Keystore otherwise. Requires API 23+ (Marshmallow).

Example app #

See example/. Runs against staging or local API:

cd example
flutter run --dart-define=CLARIODESK_API_KEY=pk_live_…
0
likes
140
points
214
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

ClarioDesk Flutter SDK — in-app customer support chat, bug reporting with auto screenshots, and feedback for mobile apps. Prebuilt UI or headless API.

Homepage
Repository (GitHub)
View/report issues

Topics

#support #customer-support #chat #bug-reporting #feedback

License

MIT (license)

Dependencies

centrifuge, connectivity_plus, crypto, device_info_plus, file_selector, flutter, flutter_secure_storage, http, image_picker, package_info_plus, share_plus, url_launcher

More

Packages that depend on clariodesk

Packages that implement clariodesk