Skip to main content



A flow represents a single end-to-end onboarding or engagement flow users will experience in your product such as marketers trial onboarding, invited users creating first project onboarding, or admin onboarding.

Flows are composed of connected blocks that contain the targeting and logic rules.

Lifecycle for users

A flow can be in the following states for each user.

Not qualifiedThe user does not meet the entry condition and will not enter the flow. This is the default state.
QualifiedThe user meets the entry condition and is qualified to start the flow. The flow has not started yet because none of the blocks are active.
StartedUser has started the flow. At least one component block is active.
FinishedUser has finished the flow by hitting a finish block.
StoppedUser was manually exited from the flow without completing it (e.g. clicking a “Hide onboarding” link).

The not qualified and qualified states are conceptual states and are not exposed.

You can see or reset the state of each user per flow on the users page.

Transitioning state

While it is most common to transition state at the block level, Dopt also offers the ability to transition state at the flow level. You can programmatically get and set flow state by accessing the flow via API or SDK. Learn more →

This is useful for building out experiences that involve working with and updating the overall state of a flow such as when starting a flow for a user after a given in-product action or when bringing a user back to the beginning of a tour when they click restart.

StartStart the flow according to its targeting rules. If successful, update started: true and set the flow's initial block(s) to active: true, entered: true. If the optional force parameter is provided, ignore targeting rules and forcefully start the flow.
ResetReset the flow to its original state by setting all flow states to false and all block states to active: false, entered: false, exited: false as well as all block transitions to false. After updating state, start the flow again.
StopStop the flow by setting the flow state to stopped: true and finished: false and all block states to active: false.
FinishFinish the flow by setting the flow state to finished: true and stopped: false and all block states to active: false.


All flows have a unique identifier that is specified when the flow is created. This is the key that you will use to reference the flow when configuring which flow version to request via API or SDK. Flow identifiers cannot be changed after the flow is created.


Flows can have a status of either enabled or disabled for a particular environment. Setting the status of a flow effectively allows you to turn a flow on or off depending on your needs.

  • Enabled - Users who match the targeting rules are able to enter the flow and users who are progressing in the flow are able to continue progressing within the flow
  • Disabled - Users will be prevented from entering the flow (even if they match the targeting rules). Users who are progressing in the flow will not be able to continue progressing until the flow is enabled again.

When a flow is disabled, all flow intents will not function (i.e., you cannot reset a disabled flow).

Flow status can be set from flows page or the targeting tab in the flow builder. Setting the flow status affects all versions of a flow for a particular environment.


When you create a new flow, its status will default to enabled on the development environment and disabled on the production environment.


Flows can be versioned to keep a snapshot of the flow at a particular moment so you can continue to iterate on new changes without worrying about breaking any experiences that rely on how your flow looked like before.

A version is associated with a version tag, a transition method, and an optional commit message which can help with describing the changes made in the version. Versions cannot be modified further once created.

When creating a flow version, you can specify how users will transition when they encounter this version. Dopt currently supports three transition methods:

  • Restart in progress users only - Restarts users who have started (but not completed) the flow to the beginning of the new flow version
  • Restart all users - Restarts all users (including those who have completed) to the beginning of the new flow version
  • Stop in progress users only - Stops users who have started (but not completed) the flow so they will not see the new version
  • Carry over in progress users - Carries over the state of in-progress users from the previous version to the new version when possible. If a user's state can't be brought over due to incompatible changes, those users will be restarted from the beginning of the flow

When accessing flow versions via the SDK or API, you can specify the flow's version tag to access a committed version.

Additionally, you can use the "uncommitted" tag (or the version 0) to access uncommitted changes prior to creating a new version. This can be useful while actively developing your flow so that you don’t have to commit to see the changes while developing.

For committed versions, you can also access the most recent version using the "latest" tag. In combination with the Restart all users migration strategy, this allows you to ship the latest updates to your users including things like status and maintenance banners, feature announcements, product changelogs, and more.

How to create a flow version →


Be careful when using the "uncommitted", "latest", or 0 version tags to access flows in your code because changes made in Dopt will directly propagate to your users without changes in your code.


Carry over in progress users is under development. Picking this migration strategy will restart users if large discrepancies exist in flow state between versions. For example, if users in your flow are lingering on historic versions, they will likely be restarted when they reach a version with this migration strategy.


There may be cases where you may not want to keep a flow around. In these instances, Dopt offers the ability to archive a flow.

When a flow is archived, its configuration, versions, and associated user states are also removed. You will not be able to reuse the archived flow’s identifier in a new flow. If you request an archived flow via API or SDK, it will return false for all states. Likewise, if you request a block via API or SDK that is part of an archived flow, it will return false for all states.

How to archive a flow →


Archiving a flow effectively deletes the flow. This action cannot be undone so make sure you are comfortable with losing the ability to access this flow and the user state relating to this flow before proceeding.