React Native Integration Examples

Production-ready examples showing how to combine multiple Agentforce SDK features in real-world scenarios.

These examples demonstrate integrating multiple features together. For single-feature examples, see:

Using All Delegates Together 

This example shows how to register logger, navigation, and view provider delegates in a single component with proper cleanup.

1import React, { useEffect, useRef } from "react";
2import { View, Button, Linking, Alert, StyleSheet } from "react-native";
3import {
4  AgentforceService,
5  LogLevel,
6  NavigationRequest,
7} from "@salesforce/react-native-agentforce";
8
9export default function AllDelegatesExample() {
10  const logBufferRef = useRef<Array<{ level: LogLevel; message: string; time: Date }>>([]);
11
12  useEffect(() => {
13    // 1. Logger Delegate
14    AgentforceService.setLoggerDelegate({
15      onLog(level, message, error) {
16        logBufferRef.current.push({ level, message, time: new Date() });
17        // Keep buffer manageable
18        if (logBufferRef.current.length > 500) {
19          logBufferRef.current = logBufferRef.current.slice(-250);
20        }
21
22        // Forward errors to your analytics
23        if (level === "error") {
24          console.error(`[Agentforce ERROR] ${message}`, error);
25        }
26      },
27    });
28
29    // 2. Navigation Delegate
30    AgentforceService.setNavigationDelegate({
31      onNavigate(request: NavigationRequest) {
32        console.log("Navigation request:", JSON.stringify(request));
33
34        switch (request.type) {
35          case "link":
36            if (request.uri) {
37              Linking.openURL(request.uri as string).catch((err) =>
38                console.error("Failed to open URL:", err),
39              );
40            }
41            break;
42
43          case "record":
44            Alert.alert(
45              "Record Navigation",
46              `Open ${request.objectType} record: ${request.recordId}`,
47            );
48            break;
49
50          case "quickAction":
51            Alert.alert("Quick Action", `Execute action: ${request.actionName}`);
52            break;
53
54          case "objectHome":
55            Alert.alert("Object Home", `Navigate to ${request.objectType} list`);
56            break;
57
58          default:
59            console.log("Unhandled navigation type:", request.type);
60        }
61      },
62    });
63
64    // 3. View Provider Delegate (async)
65    AgentforceService.setViewProviderDelegate({
66      componentMap: {
67        "copilot/richText": "CustomAgentforceView",
68      },
69    }).catch((err) => console.error("View provider registration failed:", err));
70
71    // Cleanup on unmount
72    return () => {
73      AgentforceService.clearLoggerDelegate();
74      AgentforceService.clearNavigationDelegate();
75      AgentforceService.clearViewProviderDelegate();
76    };
77  }, []);
78
79  const handleConfigure = async () => {
80    try {
81      await AgentforceService.configure({
82        type: "service",
83        serviceApiURL: "https://mycompany-support.my.salesforce-scrt.com",
84        organizationId: "00Dxx0000001234EAA",
85        esDeveloperName: "My_Service_Agent",
86        featureFlags: {
87          enableMultiAgent: true,
88          enableMultiModalInput: false,
89          enablePDFUpload: false,
90          enableVoice: false,
91          enableCustomViewProvider: true,
92        },
93      });
94      Alert.alert("Success", "SDK configured");
95    } catch (error) {
96      Alert.alert("Config Error", String(error));
97    }
98  };
99
100  const handleLaunch = async () => {
101    try {
102      await AgentforceService.launchConversation();
103    } catch (error) {
104      Alert.alert("Launch Error", String(error));
105    }
106  };
107
108  const handleShowLogs = () => {
109    const recent = logBufferRef.current.slice(-10);
110    const text = recent.map((l) => `[${l.level}] ${l.message}`).join("\n");
111    Alert.alert(`Last ${recent.length} Logs`, text || "No logs yet");
112  };
113
114  return (
115    <View style={styles.container}>
116      <Button title="1. Configure" onPress={handleConfigure} />
117      <View style={styles.spacer} />
118      <Button title="2. Launch Conversation" onPress={handleLaunch} />
119      <View style={styles.spacer} />
120      <Button title="Show Recent Logs" onPress={handleShowLogs} />
121    </View>
122  );
123}
124
125const styles = StyleSheet.create({
126  container: { flex: 1, justifyContent: "center", padding: 24 },
127  spacer: { height: 16 },
128});

Feature Flag Management 

This example shows a complete settings screen for managing feature flags with UI toggles.

1import React, { useState, useEffect } from "react";
2import { View, Text, Switch, Button, Alert, StyleSheet } from "react-native";
3import { AgentforceService, FeatureFlags } from "@salesforce/react-native-agentforce";
4
5const DEFAULT_FLAGS: FeatureFlags = {
6  enableMultiAgent: true,
7  enableMultiModalInput: false,
8  enablePDFUpload: false,
9  enableVoice: false,
10  enableCustomViewProvider: false,
11};
12
13export default function FeatureFlagManager() {
14  const [flags, setFlags] = useState<FeatureFlags>(DEFAULT_FLAGS);
15  const [dirty, setDirty] = useState(false);
16
17  useEffect(() => {
18    loadFlags();
19  }, []);
20
21  const loadFlags = async () => {
22    const stored = await AgentforceService.getFeatureFlags();
23    setFlags(stored);
24    setDirty(false);
25  };
26
27  const toggleFlag = (key: keyof FeatureFlags) => {
28    setFlags((prev) => ({ ...prev, [key]: !prev[key] }));
29    setDirty(true);
30  };
31
32  const handleSave = async () => {
33    await AgentforceService.setFeatureFlags(flags);
34    setDirty(false);
35    Alert.alert(
36      "Flags Saved",
37      "Feature flags have been saved. They will take effect the next time configure() is called.",
38    );
39  };
40
41  const handleSaveAndReconfigure = async () => {
42    try {
43      await AgentforceService.setFeatureFlags(flags);
44
45      const info = await AgentforceService.getConfigurationInfo();
46      if (info.configured && info.mode === "service") {
47        const config = await AgentforceService.getConfiguration();
48        if (config) {
49          await AgentforceService.configure({
50            ...config,
51            featureFlags: flags,
52          });
53          Alert.alert("Applied", "Feature flags saved and applied immediately.");
54        }
55      } else if (info.configured && info.mode === "employee") {
56        Alert.alert("Saved", "Feature flags saved. Restart the conversation to apply.");
57      } else {
58        Alert.alert("Saved", "Flags saved. Configure the SDK to apply them.");
59      }
60      setDirty(false);
61    } catch (error) {
62      Alert.alert("Error", String(error));
63    }
64  };
65
66  const flagEntries: Array<{ key: keyof FeatureFlags; label: string; description: string }> = [
67    {
68      key: "enableMultiAgent",
69      label: "Multi-Agent",
70      description: "Allow SDK to pick from available agents when no agentId is set",
71    },
72    {
73      key: "enableMultiModalInput",
74      label: "Multi-Modal Input",
75      description: "Enable camera and image attachments",
76    },
77    {
78      key: "enablePDFUpload",
79      label: "PDF Upload",
80      description: "Enable PDF file upload in conversations",
81    },
82    {
83      key: "enableVoice",
84      label: "Voice Input",
85      description: "Enable microphone for voice input",
86    },
87    {
88      key: "enableCustomViewProvider",
89      label: "Custom View Provider",
90      description: "Enable custom React Native views for SDK output",
91    },
92  ];
93
94  return (
95    <View style={styles.container}>
96      <Text style={styles.title}>Feature Flags</Text>
97
98      {flagEntries.map(({ key, label, description }) => (
99        <View key={key} style={styles.flagRow}>
100          <View style={styles.flagInfo}>
101            <Text style={styles.flagLabel}>{label}</Text>
102            <Text style={styles.flagDesc}>{description}</Text>
103          </View>
104          <Switch value={flags[key]} onValueChange={() => toggleFlag(key)} />
105        </View>
106      ))}
107
108      {dirty && (
109        <View style={styles.actions}>
110          <Button title="Save (Apply on Next Configure)" onPress={handleSave} />
111          <View style={styles.spacer} />
112          <Button title="Save and Apply Now" onPress={handleSaveAndReconfigure} />
113        </View>
114      )}
115    </View>
116  );
117}
118
119const styles = StyleSheet.create({
120  container: { flex: 1, padding: 16 },
121  title: { fontSize: 22, fontWeight: "bold", marginBottom: 16 },
122  flagRow: {
123    flexDirection: "row",
124    alignItems: "center",
125    paddingVertical: 12,
126    borderBottomWidth: 1,
127    borderBottomColor: "#eee",
128  },
129  flagInfo: { flex: 1 },
130  flagLabel: { fontSize: 16, fontWeight: "600" },
131  flagDesc: { fontSize: 12, color: "#666", marginTop: 2 },
132  actions: { marginTop: 24 },
133  spacer: { height: 12 },
134});

Employee Agent with Mobile SDK Auth 

Full Employee Agent integration using the Salesforce Mobile SDK for OAuth authentication, with state management for login/logout flows.

1import React, { useState, useEffect } from "react";
2import { View, Button, Text, Alert, ActivityIndicator, StyleSheet } from "react-native";
3import {
4  AgentforceService,
5  isEmployeeAgentAuthSupported,
6  hasEmployeeAgentSession,
7  loginForEmployeeAgent,
8  logoutEmployeeAgent,
9  getEmployeeAgentCredentials,
10  AuthCredentials,
11} from "@salesforce/react-native-agentforce";
12
13const AGENT_ID = "0Xxxx0000001234AAA";
14
15export default function EmployeeAgentWithAuth() {
16  const [authSupported, setAuthSupported] = useState(false);
17  const [loggedIn, setLoggedIn] = useState(false);
18  const [loading, setLoading] = useState(true);
19  const [credentials, setCredentials] = useState<AuthCredentials | null>(null);
20
21  useEffect(() => {
22    checkAuthState();
23  }, []);
24
25  const checkAuthState = async () => {
26    setLoading(true);
27    try {
28      const supported = await isEmployeeAgentAuthSupported();
29      setAuthSupported(supported);
30
31      if (supported) {
32        const session = await hasEmployeeAgentSession();
33        setLoggedIn(session);
34        if (session) {
35          const creds = await getEmployeeAgentCredentials();
36          setCredentials(creds);
37        }
38      }
39    } catch (error) {
40      console.error("Auth check failed:", error);
41    } finally {
42      setLoading(false);
43    }
44  };
45
46  const handleLogin = async () => {
47    try {
48      setLoading(true);
49      const creds = await loginForEmployeeAgent();
50      setCredentials(creds);
51      setLoggedIn(true);
52    } catch (error) {
53      Alert.alert("Login Failed", String(error));
54    } finally {
55      setLoading(false);
56    }
57  };
58
59  const handleLogout = async () => {
60    try {
61      await AgentforceService.closeConversation();
62      await logoutEmployeeAgent();
63      await AgentforceService.resetSettings();
64      setCredentials(null);
65      setLoggedIn(false);
66    } catch (error) {
67      Alert.alert("Logout Failed", String(error));
68    }
69  };
70
71  const handleLaunch = async () => {
72    if (!credentials) {
73      Alert.alert("Error", "Not logged in");
74      return;
75    }
76
77    try {
78      await AgentforceService.configure({
79        type: "employee",
80        instanceUrl: credentials.instanceUrl,
81        organizationId: credentials.organizationId,
82        userId: credentials.userId,
83        agentId: AGENT_ID,
84        accessToken: credentials.accessToken,
85      });
86
87      await AgentforceService.launchConversation();
88    } catch (error) {
89      Alert.alert("Launch Failed", String(error));
90    }
91  };
92
93  if (loading) {
94    return (
95      <View style={styles.center}>
96        <ActivityIndicator size="large" />
97      </View>
98    );
99  }
100
101  if (!authSupported) {
102    return (
103      <View style={styles.center}>
104        <Text>Employee Agent auth is not available in this build.</Text>
105        <Text style={styles.hint}>Include the Mobile SDK to enable it.</Text>
106      </View>
107    );
108  }
109
110  return (
111    <View style={styles.container}>
112      <Text style={styles.title}>Employee Agent</Text>
113
114      {loggedIn ? (
115        <>
116          <Text style={styles.status}>Logged in as: {credentials?.userId}</Text>
117          <Text style={styles.status}>Org: {credentials?.organizationId}</Text>
118          <View style={styles.buttonRow}>
119            <Button title="Launch Agent" onPress={handleLaunch} />
120            <Button title="Logout" onPress={handleLogout} color="red" />
121          </View>
122        </>
123      ) : (
124        <>
125          <Text style={styles.status}>Not logged in</Text>
126          <Button title="Login with Salesforce" onPress={handleLogin} />
127        </>
128      )}
129    </View>
130  );
131}
132
133const styles = StyleSheet.create({
134  center: { flex: 1, justifyContent: "center", alignItems: "center" },
135  container: { flex: 1, padding: 24, justifyContent: "center" },
136  title: { fontSize: 24, fontWeight: "bold", marginBottom: 16 },
137  status: { fontSize: 14, color: "#666", marginBottom: 8 },
138  hint: { fontSize: 12, color: "#999", marginTop: 8 },
139  buttonRow: { flexDirection: "row", gap: 16, marginTop: 16 },
140});

Complete HomeScreen Integration 

A production-ready example combining Service Agent, Employee Agent, all delegates, context variables, and settings management in a single screen.

1import React, { useState, useEffect, useRef } from "react";
2import {
3  View,
4  Text,
5  Button,
6  Alert,
7  ScrollView,
8  Linking,
9  StyleSheet,
10  AppRegistry,
11} from "react-native";
12import {
13  AgentforceService,
14  isEmployeeAgentAuthSupported,
15  hasEmployeeAgentSession,
16  loginForEmployeeAgent,
17  logoutEmployeeAgent,
18  getEmployeeAgentCredentials,
19  AuthCredentials,
20  FeatureFlags,
21  LogLevel,
22  NavigationRequest,
23  ViewProviderComponentData,
24} from "@salesforce/react-native-agentforce";
25
26// Custom View Component
27function CustomAgentforceView({ componentData }: { componentData: ViewProviderComponentData }) {
28  return (
29    <View style={{ padding: 8, backgroundColor: "#e8f0fe", borderRadius: 6, margin: 4 }}>
30      <Text style={{ fontWeight: "bold" }}>[Custom] {componentData.definition}</Text>
31      <Text>{JSON.stringify(componentData.properties, null, 2)}</Text>
32    </View>
33  );
34}
35
36AppRegistry.registerComponent("CustomAgentforceView", () => CustomAgentforceView);
37
38// Config
39const SERVICE_CONFIG = {
40  type: "service" as const,
41  serviceApiURL: "https://mycompany-support.my.salesforce-scrt.com",
42  organizationId: "00Dxx0000001234EAA",
43  esDeveloperName: "My_Service_Agent",
44};
45
46export default function HomeScreen() {
47  // State
48  const [configured, setConfigured] = useState(false);
49  const [mode, setMode] = useState<"service" | "employee" | null>(null);
50  const [authSupported, setAuthSupported] = useState(false);
51  const [loggedIn, setLoggedIn] = useState(false);
52  const [credentials, setCredentials] = useState<AuthCredentials | null>(null);
53  const [flags, setFlags] = useState<FeatureFlags | null>(null);
54  const logCount = useRef(0);
55
56  // Initialize
57  useEffect(() => {
58    initializeApp();
59    return () => {
60      AgentforceService.clearLoggerDelegate();
61      AgentforceService.clearNavigationDelegate();
62    };
63  }, []);
64
65  const initializeApp = async () => {
66    // Set up delegates first
67    setupDelegates();
68
69    // Check current state
70    const info = await AgentforceService.getConfigurationInfo();
71    setConfigured(info.configured);
72    setMode(info.mode);
73
74    const storedFlags = await AgentforceService.getFeatureFlags();
75    setFlags(storedFlags);
76
77    // Check Employee Agent auth
78    const supported = await isEmployeeAgentAuthSupported();
79    setAuthSupported(supported);
80    if (supported) {
81      const session = await hasEmployeeAgentSession();
82      setLoggedIn(session);
83      if (session) {
84        setCredentials(await getEmployeeAgentCredentials());
85      }
86    }
87  };
88
89  const setupDelegates = () => {
90    // Logger
91    AgentforceService.setLoggerDelegate({
92      onLog(level: LogLevel, message: string, error?: string) {
93        logCount.current++;
94        if (level === "error") {
95          console.error(`[SDK ERROR] ${message}`, error || "");
96        }
97      },
98    });
99
100    // Navigation
101    AgentforceService.setNavigationDelegate({
102      onNavigate(request: NavigationRequest) {
103        switch (request.type) {
104          case "link":
105            if (request.uri) Linking.openURL(request.uri as string);
106            break;
107          case "record":
108            Alert.alert("Record", `${request.objectType}: ${request.recordId}`);
109            break;
110          default:
111            console.log("Navigation:", request.type, request);
112        }
113      },
114    });
115
116    // View Provider
117    AgentforceService.setViewProviderDelegate({
118      componentMap: {
119        "copilot/richText": "CustomAgentforceView",
120      },
121    }).catch(console.error);
122  };
123
124  // Service Agent
125  const handleConfigureService = async () => {
126    try {
127      await AgentforceService.configure({
128        ...SERVICE_CONFIG,
129        featureFlags: flags || undefined,
130      });
131      setConfigured(true);
132      setMode("service");
133      Alert.alert("Configured", "Service Agent ready");
134    } catch (error) {
135      Alert.alert("Error", String(error));
136    }
137  };
138
139  // Employee Agent
140  const handleLogin = async () => {
141    try {
142      const creds = await loginForEmployeeAgent();
143      setCredentials(creds);
144      setLoggedIn(true);
145    } catch (error) {
146      Alert.alert("Login Failed", String(error));
147    }
148  };
149
150  const handleConfigureEmployee = async () => {
151    if (!credentials) {
152      Alert.alert("Error", "Login first");
153      return;
154    }
155    try {
156      const agentId = await AgentforceService.getEmployeeAgentId();
157      await AgentforceService.configure({
158        type: "employee",
159        instanceUrl: credentials.instanceUrl,
160        organizationId: credentials.organizationId,
161        userId: credentials.userId,
162        agentId: agentId || undefined,
163        accessToken: credentials.accessToken,
164        featureFlags: flags || undefined,
165      });
166      setConfigured(true);
167      setMode("employee");
168      Alert.alert("Configured", "Employee Agent ready");
169    } catch (error) {
170      Alert.alert("Error", String(error));
171    }
172  };
173
174  // Conversations
175  const handleLaunch = async () => {
176    try {
177      await AgentforceService.launchConversation();
178    } catch (error) {
179      Alert.alert("Launch Error", String(error));
180    }
181  };
182
183  const handleNewConversation = async () => {
184    try {
185      await AgentforceService.startNewConversation();
186    } catch (error) {
187      Alert.alert("Error", String(error));
188    }
189  };
190
191  const handleSetContext = async () => {
192    try {
193      await AgentforceService.setAdditionalContext({
194        variables: [
195          { name: "screen", type: "Text", value: "HomeScreen" },
196          { name: "timestamp", type: "DateTime", value: new Date().toISOString() },
197          { name: "userAgent", type: "Text", value: "react-native-agentforce-example" },
198        ],
199      });
200      Alert.alert("Context Set", "3 variables sent to the agent");
201    } catch (error) {
202      Alert.alert("Error", String(error));
203    }
204  };
205
206  // Cleanup
207  const handleReset = async () => {
208    if (loggedIn) {
209      await logoutEmployeeAgent();
210    }
211    await AgentforceService.resetSettings();
212    setConfigured(false);
213    setMode(null);
214    setLoggedIn(false);
215    setCredentials(null);
216    Alert.alert("Reset", "All settings cleared");
217  };
218
219  return (
220    <ScrollView style={styles.container} contentContainerStyle={styles.content}>
221      <Text style={styles.title}>Agentforce Demo</Text>
222
223      {/* Status */}
224      <View style={styles.section}>
225        <Text style={styles.sectionTitle}>Status</Text>
226        <Text>Configured: {configured ? "Yes" : "No"}</Text>
227        <Text>Mode: {mode || "None"}</Text>
228        <Text>Log messages received: {logCount.current}</Text>
229      </View>
230
231      {/* Service Agent */}
232      <View style={styles.section}>
233        <Text style={styles.sectionTitle}>Service Agent</Text>
234        <Button title="Configure Service Agent" onPress={handleConfigureService} />
235      </View>
236
237      {/* Employee Agent */}
238      {authSupported && (
239        <View style={styles.section}>
240          <Text style={styles.sectionTitle}>Employee Agent</Text>
241          <Text>Logged in: {loggedIn ? "Yes" : "No"}</Text>
242          {!loggedIn ? (
243            <Button title="Login" onPress={handleLogin} />
244          ) : (
245            <Button title="Configure Employee Agent" onPress={handleConfigureEmployee} />
246          )}
247        </View>
248      )}
249
250      {/* Conversation Actions */}
251      {configured && (
252        <View style={styles.section}>
253          <Text style={styles.sectionTitle}>Conversation</Text>
254          <Button title="Launch Conversation" onPress={handleLaunch} />
255          <View style={styles.spacer} />
256          <Button title="New Conversation" onPress={handleNewConversation} />
257          <View style={styles.spacer} />
258          <Button title="Set Context Variables" onPress={handleSetContext} />
259        </View>
260      )}
261
262      {/* Reset */}
263      <View style={styles.section}>
264        <Button title="Reset Everything" onPress={handleReset} color="red" />
265      </View>
266    </ScrollView>
267  );
268}
269
270const styles = StyleSheet.create({
271  container: { flex: 1 },
272  content: { padding: 16, paddingBottom: 48 },
273  title: { fontSize: 28, fontWeight: "bold", marginBottom: 24 },
274  section: { marginBottom: 24 },
275  sectionTitle: { fontSize: 18, fontWeight: "600", marginBottom: 8 },
276  spacer: { height: 8 },
277});

See Also