DaVinci client sample apps
We provide the source code for sample applications that demonstrate how to integrate DaVinci flows into your mobile and web applications using the DaVinci client.
You can clone or download the sample source code from our GitHub repository at https://github.com/ForgeRock/sdk-sample-apps.
Each sample is a functional application designed to provide a practical guide for common integration scenarios. You can use them as a reference to understand key concepts or as a starting point for your own custom implementation.
The sample applications are provided "as is" for demonstration purposes only. They are not official products of Ping Identity and are not officially supported. |
We provide DaVinci client sample apps for the following platforms:
Android sample apps
kotlin-davinci
What does the kotlin-davinci
sample support?
Feature | Supported by sample |
---|---|
Orchestration |
|
Implementation |
|
Language |
|
DaVinci Fields |
|
DaVinci Buttons |
|
DaVinci Toolbox |
|
The kotlin-davinci
application is a lightweight Android client.

It is designed to demonstrate a core capability of the DaVinci client for Android: rendering a dynamic user interface based on signals received from a DaVinci flow.
Instead of having a hardcoded login screen, the app starts a DaVinci flow and waits for the server to send instructions on what to display. It then constructs the UI on-the-fly, whether it’s a username/password form, a message, or other interactive elements defined in your DaVinci flow.
The application’s code showcases several important implementation patterns for integrating with DaVinci:
1. Dynamic UI Rendering with Jetpack Compose
The app uses modern Android development practices, leveraging Jetpack Compose to build its user interface. The core logic resides in the DaVinciScreen.kt
file.
-
It observes a state object from the
DaVinciViewModel
. -
It uses a
when
statement to react to the current state of the DaVinci flow (Login
,Success
, orFailure
). -
For the
Login
state, it iterates through the list of collectors returned from the DaVinci flow and renders the appropriate Composable for each one.This is the dynamic part—if you change the DaVinci flow the UI will change without needing to recompile the app.
2. State Management with ViewModel and StateFlow
The application follows the recommended Android architecture by separating UI logic from business logic.
-
DaVinciViewModel.kt
is responsible for all interactions with the Ping Identity SDK. -
It uses a
MutableStateFlow
to hold the current state of the DaVinci flow (DaVinciAction
). The UI (Composable functions) subscribes to this flow and automatically updates whenever the state changes.This decouples the SDK interaction from the UI, making the code cleaner and easier to test.
3. SDK Initialization and Configuration
The app demonstrates how to initialize and configure the SDK to connect to your specific PingOne and DaVinci environment. In DaVinciViewModel
, it shows how to:
-
Provide the necessary DaVinci client configuration
-
Start the DaVinci flow by calling
start()
.
4. Handling User Input
The sample shows how to collect data from the dynamically rendered input fields, such as username and password fields, package it into a Map
, and submit it back to DaVinci using the action.next()
method.
This is the mechanism for advancing the flow after a user provides their credentials or makes a choice.
iOS sample apps
swiftui-davinci
What does the swiftui-davinci
sample support?
Feature | Supported by sample |
---|---|
Orchestration |
|
Implementation |
|
Language |
|
DaVinci Fields |
|
DaVinci Buttons |
|
The swiftui-davinci
application is a modern iOS client built with Swift and SwiftUI.

It’s designed to demonstrate a core capability of the DaVinci client for iOS: rendering a dynamic user interface based on collectors received from a DaVinci flow.
Instead of having a hardcoded login screen, the app initiates a DaVinci flow and waits for the server to send collectors, which describe the required data. It then constructs the UI on-the-fly, whether it’s a username and password form, a message, or other interactive elements defined in your DaVinci flow.
The application’s code showcases several important implementation patterns for integrating with DaVinci using modern iOS development practices:
1. Dynamic UI Rendering with SwiftUI
The app uses SwiftUI to build its user interface declaratively. The core rendering logic resides in ContentView.swift
.
-
It observes a state object from the
DavinciViewModel
. -
It uses a
switch
statement to react to the current state of the DaVinci flow, either.loading
,.loaded
, or.success
). -
For the
.loaded
state, it iterates through an array of collectors returned by the DaVinci flow and renders the appropriate SwiftUI View for each one.This is the dynamic part—if you change the DaVinci flow on the server, the UI will change without needing to recompile the app.
2. State Management with Combine and ViewModel
The application follows the recommended MVVM (Model-View-ViewModel) architecture by separating UI logic from business logic.
-
DavinciViewModel.swift
is responsible for interactions with the DaVinci client for iOS. -
It uses
@Published properties
from the Combine framework to hold the current state of the DaVinci flow, such asflowState
andinputs
. The SwiftUIView
subscribes to these properties and automatically updates whenever their values change.This decouples the SDK interaction from the UI, making the code cleaner and easier to manage.
3. SDK Initialization and Configuration
The app demonstrates how to initialize and configure the SDK to connect to your specific PingOne and DaVinci environment.
-
Provide the necessary DaVinci client configuration
-
Start the DaVinci flow by calling the
start()
method.
4. Handling User Input and Flow Progression
The sample shows how to collect data from the dynamically rendered input fields, bind it to a dictionary in the ViewModel
, and submit it back to DaVinci.
This is the mechanism for advancing the flow after a user provides their credentials or makes a choice.
JavaScript sample apps
embedded-login-davinci
Source code: https://github.com/ForgeRock/sdk-sample-apps/tree/main/javascript/embedded-login-davinci
What does the embedded-login-davinci
sample support?
Feature | Supported by sample |
---|---|
Orchestration |
|
Implementation |
|
Language |
|
DaVinci Fields |
|
DaVinci Buttons |
|
Integrations |
|
The embedded-login-davinci
application is a lightweight, single-page web application built with TypeScript and Vite.

Its primary purpose is to demonstrate how to embed a PingOne DaVinci authentication experience directly into a web page using the DaVinci client for JavaScript.
Instead of redirecting the user to a hosted login page, the application communicates with a DaVinci flow and dynamically builds the necessary UI components, such as username fields, password fields, and buttons in the browser based on the collectors it receives from DaVinci.
The application’s code showcases several important patterns for integrating DaVinci into a modern, framework-free web application:
1. Dynamic UI Rendering via DOM Manipulation
The core of the sample is its ability to render a UI without a front-end framework. The logic in src/main.ts
is responsible for this.
-
It receives a response object from the DaVinci flow which contains an array of collectors.
-
It iterates through these collectors and uses a
switch
statement to identify the type of UI element to create, such astext
,password
, orbutton
. -
It then uses standard browser DOM APIs such as
document.createElement
,setAttribute
, andappendChild
to construct and display the corresponding HTML elements.This allows the UI to change dynamically based on the needs of the DaVinci flow.
2. SDK Initialization and Configuration
The application demonstrates how to configure and initialize the Ping Identity SDK to connect to a specific PingOne and DaVinci environment.
-
It uses Vite’s environment variable system to securely load configuration from a
.env
file. The configuration values such asVITE_WELLKNOWN_URL
andVITE_WEB_OAUTH_CLIENT
are accessed viaimport.meta.env
. -
In
main.ts
, it callsstart()
to begin the DaVinci flow.
3. Asynchronous Flow Management
The entire user interaction is managed as a series of asynchronous steps.
-
The application makes an initial call to
start()
and waits for the first set of collectors. -
After the user fills out the dynamically generated form and clicks a submit button, the application gathers the input values.
-
It then calls the
next()
method on the DaVinci response object, sending the user’s input back to the server. -
The server processes the input and responds with the next set of collectors (or a success or failure message), and the rendering cycle begins again.
This loop continues until the flow is complete.
4. User Session Management
Upon successful completion of the DaVinci flow, the sample demonstrates how to handle the successful authentication.
-
It receives a
success
response from the server. -
It displays the user’s session and token information, demonstrating that a session has been established.
-
It also renders a logout button, showing how to terminate the session using
FRUser.logout()
.
reactjs-todo-davinci
What does the reactjs-todo-davinci
sample support?
Feature | Supported by sample |
---|---|
Orchestration |
|
Implementation |
|
Language |
|
DaVinci Fields |
|
DaVinci Buttons |
|
DaVinci Toolbox |
|
The reactjs-todo-davinci
application is a "To-Do List" single-page application (SPA) built with ReactJS.

Its primary purpose is to demonstrate how to secure a React application by embedding a PingOne DaVinci flow directly into the user experience.
Instead of a static login form, the application initiates a DaVinci flow and dynamically renders the necessary UI components based on the collectors it receives from the server. Once a user is authenticated, they can access the protected To-Do list page, showcasing a complete, secure workflow from login to application usage.
This sample requires the |
The application showcases several modern, best-practice patterns for integrating the DaVinci client for JavaScript within a React project:
1. Global State Management with React Context
The application uses React’s built-in Context API for managing shared state, which is a lightweight and effective alternative to larger libraries like Redux for this use case.
-
Location:
javascript/reactjs-todo-davinci/client/global-state.js
-
Function: It defines a custom hook,
useGlobalStateMgmt
, which encapsulates all the logic for managing shared state likeisAuthenticated
,username
, andtheme
. TheAppContext
then makes this state and its setter functions available to any component wrapped in its provider.The
setAuthenticationWrapper
function couples the application’s state with the DaVinci client’s functionality. When a component sets the authentication state tofalse
, this wrapper interprets it as a logout action and triggerslogout()
, ensuring the user’s session is properly terminated PingOne.
2. Dynamic, View-Based Routing
The application uses react-router-dom
to manage navigation, with a structure that separates public and private views.
-
File:
javascript/reactjs-todo-davinci/client/router.js
-
Function: The
Router
component defines all application routes. It makes use of a customProtectedRoute
component to guard access to the/todos
page.This guard checks the
isAuthenticated
flag from the global context and redirects unauthenticated users to the/login
page.
3. Component-Driven DaVinci Flow
The login experience is not hardcoded but is driven by the DaVinci flow itself.
-
File:
javascript/reactjs-todo-davinci/client/views/login.js
-
Function: The
Login
view acts as a container. It renders a dedicated<Form />
component (refer tojavascript/reactjs-todo-davinci/client/components/davinci-client/form.js
).This
Form
component is responsible for initiating the DaVinci flow, listening for collectors, and dynamically rendering the appropriate input fields, such as a username and password. This architecture makes the login UI incredibly flexible, as the entire user journey can be modified in the DaVinci flow builder without changing the React code.
angular-todo-davinci
What does the angular-todo-davinci
sample support?
Feature | Supported by sample |
---|---|
Orchestration |
|
Implementation |
|
Language |
|
DaVinci Fields |
|
DaVinci Buttons |
|
The angular-todo-davinci
application is a classic "To-Do List" single-page application (SPA) built with Angular.

Its primary purpose is to demonstrate how to secure an Angular application using a PingOne DaVinci flow for embedded user authentication.
Instead of a static, hardcoded login form, the application initiates a DaVinci flow and dynamically renders the login UI based on the collectors it receives from the server. Once authenticated, the user can manage their to-do list, demonstrating how to protect application features and routes.
This sample requires the |
The application showcases modern, best-practice patterns for integrating the DaVinci client for JavaScript within an Angular project:
1. Component-Driven Authentication Flow
The DavinciFormComponent
(refer to javascript/angular-todo-davinci/src/app/features/davinci/form/form.component.ts
) acts as a self-contained controller for the DaVinci authentication process:
- State Management is Local
-
The component manages the state of the DaVinci flow in its own local properties, not in a shared service. This includes the DaVinci client instance, the current node, and the collectors needed to build the form.
- Flow Initialization
-
In
ngOnInit
, the component itself is responsible for creating the DaVinci client and starting the flow.This is a key SDK integration point.
2. The Role of SdkService
The SdkService
plays a different, but crucial, role. It is not responsible for the DaVinci flow itself, but rather for what happens after the flow is successfully completed:
- Post-Authentication Handler
-
Its primary job is to take the authorization
code
andstate
from a successful DaVinci flow and use them to complete the OAuth 2.0 flow to get tokens and establish a user session. - Session Management
-
The
successHandler
method in theDavinciFormComponent
is responsible for this hand-off.
3. Dynamic UI Rendering
The component’s template (refer to javascript/angular-todo-davinci/src/app/features/davinci/form/form.component.html
) is responsible for dynamically rendering the correct input fields based on the collectors array, which is populated from the current DaVinci node.
This allows the UI to adapt to any changes in the DaVinci flow without requiring code changes in the Angular app.
4. Route Protection
The AuthGuard
class protects routes by checking the final authentication state managed by the SdkService
.