---
title: Stepping through DaVinci flows
description: Explains how to navigate DaVinci flows in an iOS application by handling different node types (`ContinueNode`, `SuccessNode`, `ErrorNode`, `FailureNode`) and their collectors.
component: orchsdks
page_id: orchsdks:davinci:usage/ios/03-stepping-through-davinci-flows
canonical_url: https://developer.pingidentity.com/orchsdks/davinci/usage/ios/03-stepping-through-davinci-flows.html
revdate: Fri, 9 Jan 2026 17:23:51 +0000
keywords: ["DaVinci", "iOS", "Flows", "Nodes", "Collectors", "Navigation"]
section_ids:
  starting_a_davinci_flow: Starting a DaVinci flow
  determining_davinci_flow_node_type: Determining DaVinci flow node type
  continue_node_type_ios: Handling DaVinci flow collectors in continue nodes
  node-next: Continuing a DaVinci flow
  error_node_type_ios: Handling DaVinci flow error nodes
  success_node_type_ios: Handling DaVinci flow success nodes
---

# Stepping through DaVinci flows

[icon: circle-check, set=far]PingOne [icon: apple, set=fab]iOS

* [Install](01-installing-the-davinci-module.html)

* [Configure](02-configuring-the-davinci-module.html)

* **Navigate**

To authenticate your users the DaVinci module for iOS must start the flow, and step through each node.

|   |                                                                                                                                 |
| - | ------------------------------------------------------------------------------------------------------------------------------- |
|   | For information on which connectors and fields the DaVinci module supports, refer to [Compatibility](../../compatibility.html). |

## Starting a DaVinci flow

To start a DaVinci flow, call the `start()` method:

Start a DaVinci flow

```swift
var node = await daVinci.start()
```

## Determining DaVinci flow node type

Each step of the flow returns one of four node types:

* `ContinueNode`

  This type indicates there is input required from the client. The `node` object for this type contains a `collector` object, which describes the information it requires from the client.

  Learn more in [Handling DaVinci flow collectors in continue nodes](#continue_node_type_ios).

* `SuccessNode`

  This type indicates the flow is complete, and authentication was successful.

  Learn more in [Handling DaVinci flow success nodes](#success_node_type_ios).

* `ErrorNode`

  This type indicates an error in the data sent to the server. For example, an email address in an incorrect format, or a password that does not meet complexity requirements.

  You can correct the error and resubmit to continue the flow.

  Learn more in [Handling DaVinci flow error nodes](#error_node_type_ios).

* `FailureNode`

  This type indicates that the flow could not be completed and must be restarted. This can be caused by a server error, or a timeout.

  Learn more in [\[failure\_node\_type\_ios\]](#failure_node_type_ios).

You can use the helper functions to determine which node type the server has returned:

Determine `node` type.

```swift
switch (node) {
  case is ContinueNode: do {}
  case is ErrorNode: do {}
  case is FailureNode: do {}
  case is SuccessNode: do {}
}
```

## Handling DaVinci flow collectors in continue nodes

The `ContinueNode` type contains `collectors`. These collectors define what information or action to request from the user, or client device.

|   |                                                                                                                                            |
| - | ------------------------------------------------------------------------------------------------------------------------------------------ |
|   | For a list of supported collectors, refer to [Supported PingOne fields and collectors](../../compatibility.html#supported-davinci-fields). |

There are specific collector types. For example there are `TextCollector` and `PasswordCollector` types.

To complete a DaVinci flow we recommend that you implement a component for each connector type you will encounter in the flow. Then you can iterate through the flow and handle each collector as you encounter it.

Access collectors in a `ContinueNode`

```swift
node.collectors.forEach { item in
    switch(item) {
    case is TextCollector:
        (item as! TextCollector).value = "My First Name"
    case is PasswordCollector:
        (item as! PasswordCollector).value = "My Password"
    case is SubmitCollector:
        (item as! SubmitCollector).value = "click me"
    case is FlowCollector:
        (item as! FlowCollector).value = "Forgot Password"
    }
}
```

## Continuing a DaVinci flow

After collecting the data for a node you can proceed to the next node in the flow by calling the `next()` method on your current `node` object.

Continue a DaVinci flow using `next()`

```swift
let next = node.next()
```

|   |                                                                                                                                                                  |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | You do not need to pass any parameters into the `next` method as the DaVinci module internally stores the updated object, ready to return to the PingOne server. |

The server responds with a new `node` object, just like when starting a flow initially.

Loop again through conditional checks on the new node's type to render the appropriate UI or take the appropriate action.

### Handling DaVinci flow error nodes

DaVinci flows return the `ErrorNode` type when it receives data that is incorrect, but you can fix the data and resubmit. For example, an email value submitted in an invalid format or a new password that is too short.

You can retrieve the error message by using `node.message()`, and the raw JSON response with `node.input`.

Displaying the reason for an error

```swift
let node = await daVinci.start() //Start the flow

//Determine the Node Type
switch (node) {
  case is ContinueNode: do {}
  case is FailureNode: do {}
  case is ErrorNode:
      (node as! ErrorNode).message //Retrieve the error message
  case is SuccessNode: do {}
}
```

|   |                                                                                                          |
| - | -------------------------------------------------------------------------------------------------------- |
|   | This is different than a `FailureNode` type, which you cannot resubmit and must restart the entire flow. |

You can retain a reference to the `node` you submit in case the next `node` you receive is an `ErrorNode` type. If so, you can re-render the previous form, and inject the error information from the new `ErrorNode` node.

After the user revises the data call `next()` as you did before.

[]()== Handling DaVinci flow failure nodes

DaVinci flows return the `FailureNode` type if there has been an issue that prevents the flow from continuing. For example, the flow times out or suffers a server error.

You can retrieve the cause of the failure by using `node.cause()`, which is an `Error` instance.

Handling receipt of a `FailureNode` type

```swift
let node = await daVinci.start() //Start the flow

//Determine the Node Type
switch (node) {
  case is ContinueNode: do {}
  case is FailureNode:
    (node as! FailureNode).cause //Retrieve the cause of the Failure
  case is ErrorNode: do {}
  case is SuccessNode: do {}
}
```

You should offer to restart the flow on receipt of a `FailureNode` type.

## Handling DaVinci flow success nodes

DaVinci flows return the `SuccessNode` type when the user completes the flow and PingOne issues them a session.

To retrieve the existing session, you can use the following code:

Handling receipt of a `SuccessNode` type

```swift
let user: User? = await daVinci.user()

_ = await user?.token()
await user?.revoke()
_ = await user?.userinfo(cache: false)
await user?.logout()
```
