Graine AI

Going live

The in-app agent from the dashboard to a monitored launch — every setting, every step in the app, how to prove it works, and what each failure means.

One path, in order. Each step links to the page that covers it in full.

1. The dashboard

SettingWhereWhy
An agent for this surfaceAgentsAn app's agent has different tools and a different prompt from your phone agent — one agent per surface
The publishable keyAgent → Embed & Widgetspk_live_…. Public by design: it names the agent and cannot place a call on its own
Allowed domainsAgent → Embed & Widgetsapp:// for a native app (an app sends no web address, and this entry is how it is let in); your own domains for a website. Never Graine's own domain — anyone could then use your key
Call audioAgent → Embed & Widgets → Appearance → SetupHigh quality (WebRTC) for Opus, a jitter buffer and the device's echo canceller. It needs WebRTC enabled for your organisation — ask Graine; a relay for mobile networks is included. If WebRTC cannot connect, calls move to the standard path by themselves
The lookAgent → Embed & Widgets → AppearanceA design from the Garage, your logo (drawn whole, on your brand colour or white) and your loader's words — Your design
App actionsAgent → Embed & WidgetsEvery action your app registers must be declared here, or the agent cannot call it — Actions
ComponentsAgent → Embed & Widgets, then picked per agentThe cards, lists and choices the agent may show — Components → Turning one on

2. The app

StepReact NativeAndroidiOSFlutterWebsite
Install@graineai/inapp-react-native 0.41.0 or later; for calls, @graineai/inapp-react-native-calls 0.2.0ai.graine:inapp-android:0.7.0inapp-ios from 0.7.0graine_inapp: ^0.7.0the loader, or your own page
MicrophoneDeclare RECORD_AUDIO and MODIFY_AUDIO_SETTINGS (Android) and NSMicrophoneUsageDescription (iOS) — with Expo, in app.json. The SDK asks on Android when a call starts; iOS asks the first time the call uses itIn the library's manifest. The SDK asks at start(); forward onRequestPermissionsResult to itNSMicrophoneUsageDescription. The SDK asks at start()Android manifest and Info.plist; your app asks, through requestMicrophone in GraineConfigThe frame's allow="microphone"
Camera purpose string (with WebRTC)NSCameraUsageDescription under ios.infoPlist (webrtc: true)—NSCameraUsageDescription with GraineInAppRTCNSCameraUsageDescription in Info.plist with GRAINE_WEBRTC—
Engine loaded earlylauncher mounted at start with active={false}voice.attach(activity) in your first activitythe bar, or voice.attach()GraineEngine around the navigatoridle=1, then graine:warm on graine:ready

Then, on every platform:

  1. Who the customer is — identify() with the signed-in customer, so the agent greets them by name. Screen context → Who the customer is
  2. What is on screen — one screen name per screen, the fields and their status. Screen context
  3. What it may do — one handler per declared action; answer within six seconds and say what actually happened. Actions
  4. The call UI — the SDK's bar, or your own with every state drawn.

3. Prove it works

Place one test call per platform and open it from Call History → the call → Open full logs (Execution Logs). Under What happened in the app you should see:

RowMeans
transport: WebRTCThe call ran on WebRTC. fell back to WebSocket (reason) names why not — see below
connect: warm · 0.6s (setup 0.1s, answer 0.5s)How long the tap took. warm means the engine had registered ahead of the tap; a cold connect on every call means the engine is not loaded early
recovery: …The engine replaced a line the network had dropped, or placed the call again on a fresh connection — and still connected
connection quality: …The line got worse or better during the call, with the numbers
The screen, and your actionThe agent saw the screen you were on, and called your action with the answer you returned

Then try the four things customers do: deny the microphone, lose the network mid-call, call from mobile data, and hang up from both sides. The dashboard's Playground checks the rest from your desk: the key, that an unlisted site is refused, and that the agent can call its components.

4. Watch it in production

  • Execution Logs, per call, as above.
  • Your own analytics: the launcher says where every connect is (connectStage, slowConnect, callFailed), and counting them shows how calls connect on your customers' real networks — see Voice → While it connects.
  • onTransport on every SDK: a fallback is not a failure, but a not_configured one never fixes itself. Send it to your error reporting.

When something is wrong

What you seeCauseFix
Every session refused in an app, no_originapp:// is not in Allowed domainsAdd it — Voice → When rtc cannot be used
A website always falls back, not_configuredYour page did not vouch for its siteUse the loader, or answer graine:need-ticket — Your own UI → Website. Do not add Graine's domain
"Connecting…" for long on mobile dataA line the network dropped, being replaced — or the engine is not loaded earlyLook for recovery and cold rows; mount the engine at launch
The call answers and nobody hears anythingThe network blocks the media pathThe engine moves the call within seconds (reason: media); if it is every call, ask Graine to check the relay
The agent cannot see the screenNo screen named, or the screen channel never joined (screen_channel)Screen context; the engine restarts such a call on the standard path
"The agent is not configured to call" an actionIt is registered in the app but not declaredDeclare it under Embed & Widgets
The design or typeface did not changeThe app draws its own bar, or an older SDKYour design → When the phone does not match
The logo is cut offAn SDK older than React Native 0.40.0 / native 0.5.0Update; choose the logo's background under the upload
The agent greets with a blank nameidentify() not called before the callScreen context → Who the customer is
The microphone is refusedThe customer said no, the permission is not declared, or (Flutter) requestMicrophone is not setDeclare it — the usage string on iOS, RECORD_AUDIO on Android — and draw the refusal with the way to Settings: the SDK does not ask again by itself
The call ends when the screen locks or the app is put awayThe assistant bar's call (voice) ends on purpose when the app leaves the screen (endOnBackground)For calls that go on with the screen off, use the native calls — calls on iOS and Android, @graineai/inapp-react-native-calls on React Native, GraineCalls on Flutter — see In-app calling
A call push does not ringiOS: not a VoIP push, the wrong APNs host, or enableVoIPPushes not called at launch. Android: a notification block in the FCM message, or handlePush not calledIn-app calling → Troubleshooting

On this page