Quickstart

Flutter, from install to a grounded sandbox answer in ten minutes.

Rendel embeds a copilot into your app that answers with native UI components and executes registered actions behind risk-level guardrails. This page takes you from zero to a working copilot on a test key.

You need a Flutter app and a test key. You do not need a backend: an action can return a hardcoded map and the whole path still works.

1. Install the SDK

pubspec.yaml
dependencies:
  rendel:
    git:
      url: https://github.com/neon-apps/rendel.git
      path: sdk/flutter/rendel
      ref: v0.33.0

The package is in private pilot and not on pub.dev yet. Install the SDK covers access, the Dart and Flutter floors, and what you need ready — including the part that surprises people, which is that you need nothing on your backend.

2. Add the platform permissions

The composer's microphone and its "+" — Photos, Camera and Files — are built in. Photos and Files need no permission on either platform; the microphone and the camera need these.

iOS — required. Open ios/Runner/Info.plist and add these three lines inside the top-level <dict>, in your own words. Apple shows them to your users in your app's name, which is why no package can add them for you:

ios/Runner/Info.plist
<key>NSMicrophoneUsageDescription</key>
<string>Lets you speak to the assistant instead of typing.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>Turns what you say into text for the assistant.</string>
<key>NSCameraUsageDescription</key>
<string>Lets you take a photo to show the assistant.</string>

Skip them and the copilot still works, without a microphone or Camera: the SDK leaves them out rather than letting iOS close your app, and logs usage_description_missing.

Android — already done by the SDK. Its own manifest declares these, and the build merges them into android/app/src/main/AndroidManifest.xml. They are what your app will ask for; adding them inside <manifest>, above <application>, changes nothing:

android/app/src/main/AndroidManifest.xml
<!-- The SDK already declares both; adding them here changes nothing. -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

3. Initialize with your test key

Your app's key tells Rendel which app is asking. Get it from the console: open your app's Settings → API keys and press Copy beside the Test key (rd_pk_test_...) — the same key is on the app's Overview, in the SDK step. Without it the copilot cannot start. Publishable keys are safe to embed; they identify your app and environment, nothing more.

await Rendel.init(
  // Your app's key: Rendel console → Settings → API keys → Copy.
  appKey: 'rd_pk_test_...',
  theme: RendelTheme.paper(),
  config: RendelConfig(languages: ['tr']),
);

languages is what the copilot answers in. Name one and it answers only in that one, whatever the user writes in — Turkish here. Name several, ['tr', 'en'], and it answers in whichever of them the user writes or the phone is set to, and in the first for anything else. Leave it out and it answers in whatever it is addressed in. The same list can be set without a build under Experience → Persona in the console; the one in code wins.

The SDK talks to https://api.rendel.ai by default while the pilot runs. If your build needs to point elsewhere, pass RendelConfig(apiBaseUrl: ...) to init.

Swap paper() for your own tokens once it runs. See Theming.

4. Tell it who is signed in

The SDK cannot see your login. Until you tell it, a person is a device: one row per phone on the console's Users page, and nothing the copilot learns about them follows them to another phone. So, right after sign-in, hand it your own id for the person:

await Rendel.identify(
  userId: user.id,
  traits: {'plan': 'pro'},
);

userId is the id your own system uses for this person — the primary key in your database, or your auth provider's uid. Stable, and never an email or a phone number. traits is optional and yours to overwrite; what you put there the copilot knows about them, so their plan or the ids of their orders let it answer "my order" without asking.

Once is enough: the SDK remembers who is signed in across launches, so a restored session needs no second call. Every message carries that id, and two people who share a phone keep two histories. On sign-out, call Rendel.reset(): the next message is anonymous, never the last person's.

With identity verification on, the call also carries a signature from your backend, which is what stops one user asking about another's orders. See Context.

Let it reach your API as them

The copilot can answer from your own API — "my order", "my routine" — as the person asking, with no API key to issue. Give the SDK their current token from your own sign-in, and in the console set those endpoints to the signed-in user's token:

await Rendel.init(
  // Your app's key: Rendel console → Settings → API keys → Copy.
  appKey: 'rd_pk_test_...',
  config: RendelConfig(
    languages: ['tr'],
    userToken: () async => auth.accessToken,
  ),
);

It is asked for before every question, so return the current one — your auth library refreshes it when it runs out — and null when nobody is signed in. It goes with the question and on to your endpoints as Authorization: Bearer, is never stored, and each person reaches only what their own token opens.

5. Register your first action

Actions are the only things the copilot can do. Each one is typed, carries a risk level, and runs inside your app with the user's own session.

Rendel.registerAction(RendelAction(
  name: 'get_order_status',
  description: 'Fetch the delivery status of an order',
  params: RendelSchema.object({'order_id': RendelSchema.string()}),
  risk: RendelRisk.read,
  handler: (params) async {
    final order = await api.fetchOrder(params['order_id']);
    return RendelResult.ok(order.toJson());
  },
));

6. Open the copilot

Rendel.open(context);

Or drop const RendelLauncher() anywhere in your widget tree for a floating entry point that opens it.

Ask something your action can answer: "Where is my order 1042?" The copilot calls get_order_status, your handler runs, and the answer renders as an order_tracker component.

7. Add knowledge

Paste your FAQ or policies into the console under Knowledge. Once embeddings are switched on for the deployment, questions like "What is your return policy?" answer from your own content rather than from the model's general knowledge. The console tells you whether they are.