Thumbnail image for changelog item

Webhook block

We’re introducing a new block called the webhook block that allows you to send data to an external API. You can also insert data about the flow, user, and request itself into the webhook’s request body to further contextualize the data you send.

Flow with webhook block

The webhook block can be incredibly useful for tasks like triggering a follow up email or notifying your team in an internal Slack channel after one of your users has completed a step in a flow.

Read the webhook block docs →

Interactive open-source examples

Other improvements and bug fixes

  • Reorganized docs for block types to make them easier to find
  • Exposed loading methods and initialized statuses in our React and JS SDKs. You can use useDoptInitalized() to understand when Dopt’s overall initialization is complete and useFlowStatus() to understand the status of flows.
  • Removed the ability to mock flows and blocks in the react SDK. Instead, we suggest testing by identifying test users, using your development environment, and working against uncommitted versions.
  • You can now load your uncommitted flows via the Dopt SDK by specifying a version number 0. This enables you to rapidly iterate on your flows without having to commit versions before you’re ready.
  • We’ve refactored our React and JS SDKs to no longer expose internal promises when intentions like complete are called (React, JS). These methods result in server-side side effects which will eventually cause reactive state changes via client-side states; consumers can rely on our hooks in React and our subscriptions in JS to understand when state changes without relying on intention resolution.
  • We’ve deprecated older, unused user identification APIs.
    • We continue to support but have deprecated the /identify/{:identifier:} API. This API specified the user’s identifier in the URL — our current API, /identify specifies the user’s identifier in the request body along with the rest of the user’s properties; we’ve found this change has led to fewer unintentional errors when consuming the API.
    • We’ve removed all support for the /identify/bulk API in favor of our current /identify/batch API.

Thumbnail image for changelog item

Content fields

Fields enable you to define content in Dopt and access it with our SDKs to power in-product copy and configuration. You can think of fields like a lightweight in-product CMS — paired with the rest of our platform’s powerful building blocks to define the user targeting, logic, and actions of your onboarding and education flows.

Fields are key-value pairs that you can define as part of a block in Dopt’s visual flow builder. You can specify the type of the field: text, boolean, and number. We’ll be releasing more field types in the future.

Here’s a flow to power a simple modal:

Step block with fields

These fields can then be accessed with Dopt’s SDKs to power your product experience.

import { useBlock } from '@dopt/react';import { Modal } from './modal';
export function Application() {  const [{ state, getField }, { complete }] = useBlock('$BLOCK_ID');  return (    <main>      { && (        <Modal>          <h1>{getField('title')}</h1>          <p>{getField('body')}</p>          <button onClick={complete}>{getField('button')}</button>        </Modal>      )}    </main>  );}

Read the full blog post →

Read the fields docs →

1.0 SDK

The 1.0 release represents a significant milestone in terms of stability and our confidence in the core solution. It includes:

  • A reorganization of the block and flow states we expose
  • Methods for accessing states and commands for changing states
  • A new representation of the block and flow entities that we return to you
  • Group block types

Here’s the updated useBlock hook type definition:

interface Block<T> {  readonly kind: 'block';  readonly type: T;  readonly uid: string;  readonly sid: string;  readonly version: number;  readonly state: {    active: boolean;    completed: boolean;  };}
interface BlockIntention {  complete: () => void;}
const useBlock: (uid: Block['uid']) => [block: Block, intent: BlockIntention];

We offer a useFlow hook as the primary mechanism for accessing and transitioning flows. Here’s the hooks type definition:

interface Flow<T> {  readonly kind: 'flow';  readonly type: T;  readonly uid: string;  readonly sid: string;  readonly version: number;  readonly state: {    started: boolean;    completed: boolean;    exited: boolean;  };  readonly blocks: Block[];}
interface FlowIntention {  complete: () => void;  reset: () => void;  start: () => void;  exit: () => void;}
const useFlow: (uid: Flow['sid']) => [flow: Flow, intent: FlowIntention];

The most powerful concept here is that the flow has references to its blocks — meaning that you can use this hook to access all state for a flow (its state and the state of its blocks) and get live updates as that state changes.

You might have noted in the type definitions above that the type property on the flow and block interfaces is generic — this is to support us building and exposing new block types.

Read the full blog post →

Read the SDK docs →

Blocks JS client

We released a blocks JavaScript client. The blocks client is simple, language specific client to interface with Dopt’s blocks API for both client-side and server-side integrations.

Read the Blocks JS client docs →

Other improvements and bug fixes

  • Flow states on the users page now updates automatically.
  • Added “when all complete” to group block to make the logic more clear on the canvas.
  • Updated flow panel so values are automatically saved.
  • Fixed a bug when flow listing page wouldn’t load with an archived flow. Archived flows now will not be removed from users page.

Thumbnail image for changelog item

User groups, demo, & examples

Introducing user groups

We’re excited to introduce user groups for Dopt. A group is usually a company or a workspace, but could also be an account, project, team, or any other user grouping that is relevant to your product.

B2B SaaS products are collaborative by default. Users collaborate on workflows and complete tasks together, usually within a company, workspace, or account. Groups enable you to target Dopt onboarding and education flows based on the properties of those groups, not just an individual user.

Groups enable use cases like:

  • If == "pro", show the Pro onboarding flow that highlights the unique value props in that plan.
  • If == false AND == "admin", then show those admin users a flow to help them set up the integration.
  • If < 3, then show a flow to help users create their first projects so the company can work towards activating.

You set the targeting rules in the Start block.

Flow with group defined in targeting rule

Groups also give you an overview of users and their activities within a company, helping you understand how they’re experiencing your flows.

Group details page

Users can belong to many groups, supporting products where a user can be in many workspaces (like Notion or Slack).

You can associate users to groups when identifying users. This also acts as an upsert for the groups and group properties — if the group doesn’t exist, it will get created with the set properties, if the group does exist, the group properties will get updated. Here’s an example:

curl \-XPOST \-H "Content-Type: application/json" \-H "x-api-key:$USERS_API_KEY" \-d '{      "identifier": "2a845972-4cde-4cb4-ba14-5cb2fc15ec4c",      "properties": {        "name": "Evelyn Reichert",        "email": "",      },      "groups": [        {          "identifier": "21ab4-8786ca4-78e63c-4525ca434",          "properties": {            "name": "Acme co",            "plan": "pro",            "integration_setup": false,            "num_projects": 3,          }        }      ]    }'

Read the user group docs →

Demo and examples

We released a 5 min getting started demo that covers the basics of building onboarding with Dopt, from using the flow builder to using our SDKs to develop the experience.

We also released two example onboarding experiences built with Dopt:

  • Learn-by-doing onboarding example: This example shows how to use Dopt to build onboarding for a Kanban app that helps users learn the product by simply using it.
  • Getting started checklist example: This example shows a checklist style onboarding experience that guides users through the three key actions to get value out of a simple analytics app.

Stay tuned, we have got more coming!

Other improvements & fixes

  • You can keep your flow listing page tidy by archiving flows. When a flow is archived, it’s removed from the flow listing page and its configuration, versions, and associated user states are also removed. Archive flow docs →
  • Moved our Typedoc docs for the React SDK to

Thumbnail image for changelog item

SDK updates

We introduced a useFlow hook and withFlow HOC in the React SDK. The flow.reset() function resets all properties of the blocks in the flow to false. The .reset() function enables you to build experiences like “Restart walkthrough” at the end of an interactive walkthrough or “Reset onboarding help” for a user in their settings or admin panel. We’ll continue to release more flow level functions, like the ability to exit a flow and get all blocks in a flow.

Here’s an example of using the useFlow hook.

import { useFlow } from '@dopt/react';import { Modal } from '@your-company/modal';
export function Application() {  const [flow, intent] = useFlow('new-user-onboarding', 1);  return (    <main>      <Modal>        <h1>👏 Your onboarding has finished!</h1>        <p>Want to reset? click the button below.</p>        <button onClick={intent.reset}>Reset onboarding</button>      </Modal>    </main>  );}

useFlow SDK docs →

We’ve released the first version of the JavaScript blocks SDK. Unlike our React SDK, this SDK is framework agnostic. Users of Svelte, Vue.js, Angular, etc. we see you and are building to support you. The JavaScript SDK, like the React SDK, allows for subscription to block updates and exposes block intent methods for manipulating block state and transitioning flows.

Thinking about building onboarding in a JS runtime that doesn’t use React? Check this SDK out!

JS blocks SDK readme →

Our blocks SDK is now much more responsive when progressing state because we optimistically progress the state rather than waiting for a backend response. This is an optional boolean property that can be set in the Dopt provider. The default is true.

DoptProvider docs →

Other improvements & fixes

  • Blocks now update faster
  • The flow page now loads and updates faster
  • Fixed a bug where flow status didn’t update across environments
  • Fixed a bug where targeting rules were sometimes incorrectly disabled
  • The settings back button now brings you back your previous page rather than the home screen