React Native project requirements
The FlowX packages declare
react-native β₯ 0.83.0 and react β₯ 19.2.0 as peer dependencies. The validated target is React Native 0.85.3 with Expo SDK 56, which is what FlowX builds and tests against. Your react must also satisfy the peer dependency of your own React Native version (^19.2.3 for react-native@0.85.3). React Native 0.85.3 requires Node ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0.To install the npm libraries provided by FlowX.AI you will need access to the private FlowX.AI Nexus registry. Consult your project DevOps.
Installation
- Bare React Native CLI
- Expo (SDK 56)
For new projects, bootstrap with the official React Native template so For existing projects, ensure Then install iOS pods:
react and react-native ship as a matched pair that satisfies the peer dependency in the Warning above:react already satisfies your installed react-nativeβs declared peer (npm view react-native@<your-version> peerDependencies) before installing the FlowX SDK.Then install the FlowX SDK and peers:Babel plugin
react-native-worklets/plugin must be the last plugin in your Babel config.
- Expo
- Bare RN CLI
No manual config needed.
babel-preset-expo (SDK 54+) auto-adds the worklets plugin when react-native-worklets is in node_modules.Android Material 3 date picker (opt-in)
FlxDatePicker on Android renders the legacy AppCompat calendar by default. To use the Material 3 picker, the host appβs AppTheme must inherit from a Material 3 parent and the toolkit runtime flag material3 must be true. With the flag off, the legacy calendar renders and the theme change is irrelevant.
- Expo (managed / prebuild)
- Bare React Native CLI
Register the Then run
@flowx/react-native-ui-toolkit config plugin. It rewrites AppTheme to a Material 3 parent and injects extra.flxUiToolkit.material3 = true into the app config, so no JS opt-in is needed:npx expo prebuild --clean --platform android.The toolkit reads the injected
extra.flxUiToolkit.material3 value at runtime through expo-constants, which is already present in every Expo project. No JS opt-in call is needed.No Gradle changes required.
com.google.android.material:material is already on the classpath via androidx.appcompat. Skip both steps and FlxDatePicker keeps rendering the legacy calendar with no crash.App-root providers
The renderer expects safe-area and keyboard providers above it in the tree:The SDK mounts its own
NavigationContainer internally, wrapped in NavigationIndependentTree. A host NavigationContainer is not required. If your app already uses @react-navigation/native, keep its NavigationContainer at the root. The SDKβs internal navigator stays isolated from it.Authorization
The client app implements the authorization flow (using the OpenID Connect standard). The SDK expects a bearer token to be set via
FlowX.setAccessToken(token) before starting a process.setAccessToken again whenever the token is refreshed.
Configuring the SDK
FlowX.configure(cfg) sets global SDK config. Call it once at app bootstrap, before starting any process.
FlxConfig parameters
Starting a process
FlowX.startProcess(opts) starts a new process instance and returns a FlxProcessHandle. The handle exposes a ProcessView component that you mount inside a screen.
StartProcessOptions
Getting the process identifier
Open the FlowX Designer, navigate to the process, and copy the process name from the breadcrumbs. Use this value asprocessName.
The process handle
startProcess resolves to a FlxProcessHandle:
Resuming a process
FlowX.continueProcess(opts) resumes an existing process instance instead of starting a new one. Pass the processInstanceUuid of the instance you want to reattach to. Like startProcess, it resolves to a FlxProcessHandle you mount through its ProcessView.
ContinueProcessOptions
continueProcess reattaches to an already-started instance, so it takes no processName, params, or onProcessStarted. Those apply only when starting a new process. Configure the SDK with FlowX.configure(...) and set the access token before calling it, exactly as for startProcess.Starting a UI Flow
UI Flows are lightweight, screen-driven flows defined in the FlowX Designer. They run client-side on top of a data model, without requiring a BPMN process instance on the engine.FlowX.startUiFlow(opts) starts a UI Flow and returns a FlxUiFlowHandle. The handle exposes a UiFlowView component that you mount inside a screen.
StartUiFlowOptions
Getting the UI Flow name
Open the FlowX Designer and navigate to UI Flows. The flow name displayed in the list is the value to pass asuiFlowName.
The UI Flow handle
startUiFlow resolves to a FlxUiFlowHandle:
Custom components
Register host-authored custom components through thecomponents field of FlowX.configure(...). Each key is the component identifier defined in the FlowX process; the value is the React Native component that renders it. The registration is read when the process view mounts, so configure the SDK before starting or continuing a process.
React Native supports self-managed custom components only: components you author in your app and register by identifier. Bundled custom components (source compiled from the backend at runtime) are browser-only; on React Native they are skipped and a warning is logged in development. Re-author any bundled component as a self-managed one.
Component contract
Each custom component receives the same contract as the React SDK:Process data mapped through
inputKeys is available on input.data. Process actions are available on input.actionsFn, keyed by action name; calling one triggers the process action and returns a Promise that resolves when it completes.Example
Custom validators
Define custom validators on your form fields in the FlowX Designer, then pass their implementations through thevalidators field of FlowX.configure(...). The SDK honors the error messages configured on each field in the process.
Each key in the validators object is the validator name referenced in the Designer; the value is a factory that receives the validatorβs configured params and returns the predicate the SDK runs against the field value. Return true to pass or false to fail. When it fails, the message configured on that validator in the Designer is shown.
Example
Full example
Custom loader
The SDK provides a mechanism for container applications to customize the loader UI displayed during process execution. This allows you to replace the default FlowX loader with your own custom implementation based on different loading scenarios.Configuration
To configure custom loaders, pass them through thecustomLoader prop of the <FlxProcessRenderer /> component:
FlowX config (FlowX.startProcess() / FlowX.continueProcess()) instead of rendering <FlxProcessRenderer /> yourself, pass the same object through FlowX.configure():
API specification
ThecustomLoader prop accepts an object of type FlxCustomLoader:
Loader types
startProcess- Displayed when starting or resuming a processreloadProcess- Displayed when reloading a processdefaultAction- Default loader for actions whenloaderTypeis'action'. Used when no specific action loader is found in theactionsrecorddefaultUpload- Default loader for file uploads whenloaderTypeis'upload'actions- Record mapping specific action identifiers to custom loaders. When an action is executed, the SDK will first check for a matching entry in this record before falling back todefaultAction
Rendering behavior
Custom loaders on React Native differ from the web SDK in a few important ways:- The host owns every pixel. Your loader node is rendered full-screen with no SDK scrim, card, or spinner behind it. If you want a dimmed backdrop or a centered card, paint them yourself (see the
scrimstyle in the example above). - Size your root with absolute fill. The SDK centers your node inside the overlay, so a plain
flex: 1root collapses to its content size. UseStyleSheet.absoluteFillObjecton the outermost view to cover the whole screen. - The loader lives in a native modal. While visible it blocks all touch input, renders above native iOS page-sheet modals and Android dialogs, and swallows the Android hardware back button β the user cannot dismiss it.
- Android debounces the loader. On Android the loader appears only after ~250 ms, so fast responses never flash a loader; on iOS it appears immediately.
- Theming gate. Until the SDK finishes loading its theme resources (right after startup), an opaque placeholder is shown instead of any loader β default or custom β to avoid an unthemed flash.
Fallback behavior
If no custom loader is provided for a specific type, the SDK will automatically fall back to the built-in FlowX loader, themed with the active FlowX theme. This ensures your app continues to function even with partial custom loader configuration.
Public API methods
The SDK exposes a set of imperative helpers for reading CMS resources β enumerations, substitution tags, and media library items β from your own code, for example inside a custom component. Import them from@flowx/core-sdk:
These methods read the configuration of the active process session (API URL, language, project and build identifiers), so they can only be called after a process has been started β for example from a custom component rendered by the SDK. Results are resolved in the language the SDK was configured with and are cached for the duration of the session.
getEnumeration
Fetches the values of an enumeration by name.name- The name of the enumeration to fetchparentName- Optional name of the parent enumeration, used for hierarchical (parentβchild) enumerations
label and the enumeration code in id / value; for hierarchical enumerations, nomenclatorId holds the name of the child enumeration linked to that value.
getTag
Resolves a substitution tag β a localized UI string managed in the CMS β by its key.tag- The substitution tag key, with or without the@@localization prefix
undefined if the key does not exist.
getMediaItemURL
Resolves the download URL of a media library item by its key.mediaItemId- The media item key, as defined in the projectβs media library
undefined if no media item matches the key. Both the bare media item key and the fully qualified key (prefixed with the owning applicationβs UUID) are accepted.
Document caching
Documents downloaded by the SDK (for example when a process screen previews a generated file) are cached on disk, keyed by their URL, so re-renders and app relaunches skip the network round-trip. Caching is enabled by default.- The URL β file path index is persisted to AsyncStorage; the files themselves live in the OS cache directory, so the operating system may evict them at any time β the SDK simply re-downloads on a cache miss.
- Set
cacheDocuments: falseif your documents can change behind the same URL and must always be fetched fresh. - The flag can be toggled with a later
configure()call and applies to document loads performed after the change. - Mirrors
cacheDocumentson the iOS SDK anddocumentsCacheEnabledon the Android SDK.
Foreground state sync
When the app returns from background to foreground, the SDK re-fetches the root process status and rebuilds the process UI, catching up on anything that changed while the app was backgrounded. This is enabled by default.- Set
updateStateEnabled: falseto skip the state catch-up. SSE reconnection is unaffected β the SDK still re-establishes the event stream and continues to receive live updates. - Unlike
language/locale, this flag also applies to the live session: it is read on each background β foreground return, so callingconfigure()with a new value takes effect immediately β no process restart needed. - Mirrors
FXConfig.updateStateEnabledon the iOS SDK andConfig.updateStateEnabledon the Android SDK.
Custom headers
customHeaders lets the container app attach its own HTTP headers β correlation IDs, API-gateway keys, WAF cookies β to the requests the SDK sends to the FlowX backend: REST calls, SSE event streams, and document downloads from the FlowX download endpoint. They are sent in both authenticated and anonymous mode.
- Requests to public or external hosts never carry the custom headers: image and icon fetches, native font downloads, and image/document URLs outside the FlowX download endpoint. Those requests carry no SDK auth either β custom headers travel exactly where the SDKβs own auth headers travel, so a secret placed here cannot leak to third-party hosts referenced by process content.
- Custom headers are applied before the SDK-managed headers, so on a name collision the SDK wins β you cannot override
Authorization,flowx-platform, and the other headers the SDK manages itself. - The headers are live-updatable via
configure(): REST requests and document downloads read them per request; SSE applies them to connections opened after the change. - Each
configure()call replaces the whole header set β pass the complete record every time, not just the headers that changed.
Custom interceptors
requestInterceptors and responseInterceptors attach your own axios interceptors to the SDKβs REST layer β for request/response logging, timing, custom error reporting, or per-request headers.
- Interceptors apply to every REST call the SDK makes through its shared axios instance. They do not cover SSE event streams or the SDKβs non-axios fetches (images, icons, documents, native fonts) β use Custom headers to reach those.
- Like
language/locale, they take effect on the nextstartProcess()/continueProcess()β interceptors are registered per session and cleared when the session is disposed; the live session keeps the ones it started with. - Ordering relative to the SDKβs built-in interceptors (auth and platform headers, logging, error toasts) is not guaranteed β donβt rely on reading or overriding SDK-managed headers such as
Authorization. - Mirrors
requestInterceptors/responseInterceptorson the web SDKβs<FlxProcessRenderer />.
Flowx callbacks and logging
TheFlowX config exposes hooks for observing what happens inside a process session: analytics events, process swaps triggered by the backend, and a structured log stream. All three are config-level and session-independent β registrations survive dispose() and process restarts, so you can register them once at app startup.
Analytics collector
FlowX.analyticsCollector() subscribes to analytics events. An event fires whenever an executed action has analytics defined in its params, with the resolved payload:
New process started
Assign a callback toFlowX.newProcessStarted to be notified when the backend starts a new process out of the live session β a START_PROJECT action, signaled by the newProcessStarted SSE event β with the new process instance UUID.
This is a notification only: the SDK swaps the session to the new process on its own, inside the already-mounted ProcessView β the host does not need to (and should not) restart anything. Use the callback for bookkeeping, e.g. persisting the new instance UUID so the process can be resumed later with continueProcess().
Logging
FlowX.logSink() subscribes to the SDKβs structured log-event stream β useful for debugging and for feeding your own telemetry. Events cover four categories:
rest- API traffic, including the SDKβs image, icon, and document fetchessse- SSE connection lifecycle and received eventsexpression- expression evaluations (hide, disabled, computed, conditional, validator, local script)cms- CMS font registration
categories filter, and returns an unsubscribe function. Secrets in headers (Authorization & co.) are redacted before events are emitted. Pass the exported formattedLogger to pretty-print events to the console.
Chat component
To use theFlxChatRenderer component, import it from the React Native SDK:
Usage
The chat fills its parent, so give it a flexed container and let your screen own the safe area:chatConfig parameters
ThechatConfig object accepts the following properties:
Voice input
Voice messages need a recorder engine and a microphone declaration in the app, which a library cannot add on its own:- Install the optional peer dependencies
react-native-nitro-soundandreact-native-nitro-modules. Without them the SDK installs no recorder and the microphone button is not drawn. - Add the toolkitβs Expo config plugin, which declares
RECORD_AUDIOon Android and fillsNSMicrophoneUsageDescriptionon iOS (your own copy is kept if you already wrote one):
voiceInputEnabled={false} to hide the microphone even where an engine is installed. Voice messages recorded on other clients still play back either way.
