Skip to main content



Here are the key concepts in Dopt:

UsersUsers in Dopt are the people using your product.
FlowsA flow represents the end-to-end flow you’d like a particular set of users to experience.
BlocksFlows are composed of connected blocks. Blocks are the atomic units of the Flow and define targeting and logic. States of the block is also accessed and updated via the SDK to build experiences in your product.
PathsBlocks are connected with paths that define how user will transition through the flow.


Users in Dopt are the people using your product. A user contains important properties that enable the targeting of Flows and for Dopt to remember which Flows a user has already seen.

User properties

User properties are attributes you send to Dopt about your users. They are the “adjectives” that describe your users. Examples include things like email address, company, role, created date, etc.

One of the powerful features of Dopt is the ability to target users based on user properties — who they are or what they’ve done. For example, you may want to target “new marketing admins”, for which you would need to know created date, role, and team. All of these are user properties you can send to Dopt.

User properties are evaluated in Start blocks to determine if a user should qualify for a flow.


There are no required user properties other than a unique identifier used when initially identifying users to Dopt. Some properties, like name and email, are personally identifiable information (PII). As a best practice we recommend only sending properties that may be required to complete your use cases.

Example user

Here’s an example user with properties:

user = {
email: "",
name: "O'Neil",
company: "Acme Co",
projects: 2,
SKU: "Pro",
activated: false,
role: "Marketing",

Identifying users

Users are identified to Dopt using Dopt’s identify API.

How to identify users →


A flow represents a single end-to-end 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 all the targeting and logic rules.

Flow 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.
In progressUser has started the flow. At least one step block is active.
FinishedUser has finished the Flow by hitting a finish block.
ExitedUser was manually exited from the Flow without finishing (e.g. could be a “Hide onboarding” link).


Blocks are the atomic units of the Flow and define targeting and flow logic. They’re also used to store state for each user in a flow that developers can access via the SDK to build experiences with.

Blocks have paths between them that define how user will transition through them.

There are currently 3 types of Blocks:

Start blocksStart blocks define which users will enter a flow.
Step blocksStep blocks represent the state of an experience for a particular user (e.g. active: true) as the user progresses through the flow. Methods for accessing and updating the state are made available by Dopt’s SDK to build onboarding experiences in your application.
Finish blocksA finish block sets all blocks in the flow to completed, effectively finishing the flow.

Start blocks

A start block defines which users will enter a flow. This enables you to target specific sets of users to enter specific flows.

A start block contains targeting rules, which is an expression that will evaluate user properties to determine if a user should qualify for the flow. For example, a targeting rule could be projects < 10 AND SKU == "Pro".

Targeting rules expression language

This is the expression language you can use to craft entry conditions:

Type of user propertyOperatorsRulesExample
projects_created <= 3
Allowed values are only true and false (not T, F, etc.)activated == true
Strings must be surrounded by double quotes ". You can escape any double quote characters with \. These are case sensitive: they must exactly match the property value.SKU == "Free"
company == "World’s \"Best\" Coffee"
Logical groupAND
These are case insensitive: you can use OR, Or , or orrole == "marketing" OR role == "sales"
Reserved wordsThe expression can’t contain:

Property names are case sensitive and the property name in the expression must match the case of the user property. Projects is different than projects.

Example Targeting Rules

Let’s say a user has the following properties:

user = {
email: "",
name: "O'Neil",
company: "Acme Co",
projects: 2,
SKU: "Pro",
activated: false,
role: "Marketing",

Here are some example targeting rules and the result for this user:

Targeting rulesResult
projects < 10✅ User qualifies
projects < 10 AND SKU == "Pro"✅ User qualifies
role == "Marketing" OR role == "Sales"✅ User qualifies
activated == true❌ User does not qualify
role != "Marketing"❌ User does not qualify

Flow qualification

A user’s qualification for a Flow is evaluated in real-time. If the user hasn’t started the Flow and the user’s properties are updated where the user no longer matches the targeting rules, then they will no longer qualify for that Flow and will not start it.

Once a user starts a flow the flow is in progress and the user will remain in that flow until the flow is finished or exited, even if the user’s properties are updated and no longer match the targeting rules.

Step blocks

A step block is used to represent and store the state (e.g. active: true ) of a step of the flow.

A step block usually represents a single experience for users, like an embedded contextual tip or a welcome modal. For example, if you wanted to create a flow for an interactive walkthrough with 3 steps, then the flow would likely have 3 step blocks, one for each step.

Every step block has a unique ID (UID). The UID is the key that developers will use to access the block via the SDK.

Using step blocks in code to build experiences

Step blocks are the bridge between Dopt’s flow builder and using Dopt’s SDKs to build your experience in code.

More here →

Flow transitions

When a step block’s state is updated via the SDK, Dopt will automatically transition the flow state appropriately.

More here →

Step block states

A step block contains the below. All states can be either true or false for a user in a flow.

Step statesDefinition
ActiveThe block has met all entry criteria so it can be shown to the user
StartedA user has seen this block and has not yet completed it
CompletedA user has seen and completed this block
StoppedA user has seen the block and will not progress to the following block
ExitedA user will not progress to any block in this flow

These states represent the entire lifecycle of a Step that developers can use to build onboarding experiences with.

Finish blocks

When a finish block is triggered all blocks in the flow are set to completed, effectively finishing the flow. This occurs even if there are other branches in the flow that have not yet hit a finish block.

Once the flow is finished, the user will not re-enter the flow, even if they match the targeting rules.

You can have many finish blocks in a Flow and many edges can flow into a single finish block.

You can reset the flow for a user via the API or the users page. Once reset, a user will be able to qualify for the flow again. More here →

Paths & transitions

Blocks can be connected to other blocks by paths. Paths define the logic of how Dopt will transition across blocks.

How transition works

When a .complete() call from the SDK occurs on a step block:

  1. The step block’s state is updated to completed == true
  2. Dopt will automatically transition the state of the flow by updating all downstream step block’s states to active == true. This is in effect transitioning the flow to the next step.

An example transition

For a simple example, let’s say you have Step 1 → Step 2.

Action via SDKStep 1 stateStep 2 state
1. Starting statesactive == trueactive == false
2. Updated statesStep1.complete()active == false, complete == trueactive == true

For more detailed dev-documentation on methods corresponding to an intent-based API for signaling state transitions of a block check out these docs!