Delegates in React Native
Learn how to use delegates to receive events and customize behavior from the Agentforce SDK in your React Native application.
Delegates allow your JavaScript code to receive events and override behavior from the native Agentforce SDK. The bridge supports three delegate types:
| Delegate | Purpose | Direction |
|---|---|---|
| Logger | Receive SDK log messages | Native → JS |
| Navigation | Handle navigation requests from the agent | Native → JS |
| View Provider | Override native SDK views with React Native components | JS → Native (registration) + Native → JS (rendering) |
All delegates use a NativeEventEmitter on the JS side to receive events from the native layer.
The recommended order is to register delegates before calling configure(). Here's why:
- Logger: The SDK may emit log messages during initialization. If registered after
configure(), those early messages are lost. - Navigation: The navigation bridge is passed to
AgentforceConfigurationduringconfigure(). Registering afterward still works because the bridge checks dynamically, but registering before is cleaner. - View Provider: Can be registered before or after
configure()without issue. The native view provider checks the component map dynamically.
The Logger delegate forwards log messages from the native Agentforce SDK to your JavaScript code. This is useful for debugging, analytics, and monitoring.
| Parameter | Type | Description |
|---|---|---|
level | 'error' | 'warn' | 'info' | 'debug' | The severity level of the log message. |
message | string | The log message from the SDK. |
error | string (optional) | Stringified exception, present only for error/warn levels. |
| Platform | Log Levels Emitted |
|---|---|
| iOS | error, warn, info, debug |
| Android | error, warn, info |
iOS emits the debug level; Android doesn't. Plan your log filtering accordingly.
The Navigation delegate lets your app handle navigation requests from the Agentforce SDK. When the agent presents a link, record reference, or other navigable element that the user taps, the SDK emits a navigation event.
| Type | Description | Fields |
|---|---|---|
record | Navigate to a Salesforce record | recordId, objectType, pageReference? |
link | Open an external or internal URL | uri, pageReference? |
quickAction | Execute a Salesforce quick action | actionName, recordId?, objectType? |
pageReference | Navigate to a Lightning page reference | pageReference |
objectHome | Navigate to an object's home/list page | objectType, pageReference? |
app | Navigate to an app or external package | packageName, uri? |
unknown | Catch-all for unrecognized types | raw |
The View Provider delegate allows you to replace native SDK output views with custom React Native components. When the SDK renders a component type that matches your registered map, your React Native component is rendered instead.
There are two parts to registering a custom view:
Part 1: Register the React Native component with AppRegistry
Part 2: Register the component map with the bridge
The keys are SDK component definition strings. The values are the names you registered with AppRegistry.registerComponent().
This example shows a full custom view component that handles all properties and sub-components:
Register the component and mapping in your App.tsx:
copilot/listcopilot/recordInfocopilot/markdowncopilot/richText
When you register a View Provider, the following flow occurs:
- You register a
componentMapmapping SDK definition strings to React Native component names. - The native bridge stores this map in
BridgeViewProvider. - When the SDK needs to render a view, it calls
canHandle(definition)on the view provider. - If the definition matches a key in the map, the provider returns
true. - The SDK then calls
view()(iOS) orGetView()(Android), which creates anRCTRootView(iOS) orReactRootView(Android). - Your React Native component is rendered, receiving
componentDataas its initial props containing thedefinition,name,properties, and anysubComponents.
The enableCustomViewProvider feature flag must be true:
Register delegates before calling configure() to ensure they're active when the SDK initializes:
Always clean up delegates when they're no longer needed:
Or call destroy() on app shutdown to clean up everything: