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:

DelegatePurposeDirection
LoggerReceive SDK log messagesNative → JS
NavigationHandle navigation requests from the agentNative → JS
View ProviderOverride native SDK views with React Native componentsJS → 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 AgentforceConfiguration during configure(). 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.

ParameterTypeDescription
level'error' | 'warn' | 'info' | 'debug'The severity level of the log message.
messagestringThe log message from the SDK.
errorstring (optional)Stringified exception, present only for error/warn levels.
PlatformLog Levels Emitted
iOSerror, warn, info, debug
Androiderror, 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.

TypeDescriptionFields
recordNavigate to a Salesforce recordrecordId, objectType, pageReference?
linkOpen an external or internal URLuri, pageReference?
quickActionExecute a Salesforce quick actionactionName, recordId?, objectType?
pageReferenceNavigate to a Lightning page referencepageReference
objectHomeNavigate to an object's home/list pageobjectType, pageReference?
appNavigate to an app or external packagepackageName, uri?
unknownCatch-all for unrecognized typesraw

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/list
  • copilot/recordInfo
  • copilot/markdown
  • copilot/richText

When you register a View Provider, the following flow occurs:

  1. You register a componentMap mapping SDK definition strings to React Native component names.
  2. The native bridge stores this map in BridgeViewProvider.
  3. When the SDK needs to render a view, it calls canHandle(definition) on the view provider.
  4. If the definition matches a key in the map, the provider returns true.
  5. The SDK then calls view() (iOS) or GetView() (Android), which creates an RCTRootView (iOS) or ReactRootView (Android).
  6. Your React Native component is rendered, receiving componentData as its initial props containing the definition, name, properties, and any subComponents.

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: