Docs navigation

Step types

A flow is an ordered list of Step values. The SDK walks them in declaration order, with two exceptions: a survey reason with an attached offer routes the flow to that offer next, and accepting an offer advances directly to success.

type Step =
  | SurveyStep
  | OfferStep
  | FeedbackStep
  | ConfirmStep
  | SuccessStep
  | CustomStepConfig

SurveyStep

interface SurveyStep {
  type:         'survey'
  guid?:        string
  title?:       string
  description?: string
  reasons:      ReasonConfig[]
  classNames?:  SurveyClassNames
}

guid is an optional stable identifier. Use it when you need analytics to key on the step regardless of its position in the flow.

OfferStep

interface OfferStep {
  type:         'offer'
  guid?:        string
  title?:       string
  description?: string
  offer?:       OfferConfig | OfferDecision  // standalone offer (not routed from a survey reason)
  classNames?:  OfferClassNames
}

Use OfferStep to show an offer outside the survey-reason path — e.g. a pause offer at the start of every flow regardless of reason. copy is optional on the offer; the SDK synthesizes default headline, body, and button text from the offer's display fields. Provide a copy block to override.

FeedbackStep

interface FeedbackStep {
  type:         'feedback'
  guid?:        string
  title?:       string
  description?: string
  placeholder?: string
  required?:    boolean
  minLength?:   number
  classNames?:  FeedbackClassNames
}
FieldBehavior
required: trueThe Continue button stays disabled until minLength is met.
minLengthCharacter count threshold for Continue to enable. Defaults to 0.
placeholderEmpty-state hint inside the textarea.

ConfirmStep

interface ConfirmStep {
  type:           'confirm'
  guid?:          string
  title?:         string
  description?:   string
  losses?:        string[]       // bulleted list of features the customer loses
  lossesLabel?:   string         // heading above the loss list. Defaults to "You'll lose access to:"
  confirmLabel?:  string         // defaults to "Cancel subscription"
  goBackLabel?:   string         // defaults to "Go back"
  classNames?:    ConfirmClassNames
}

losses renders as a bullet list above the action buttons. Set it on the step config or, in connected mode, in the dashboard.

The default Confirm reads the subscriptions prop and renders a "Your access continues until X" notice when the active subscription has a currentPeriod.end. The date is formatted in the user's locale via Intl.DateTimeFormat. Override the Confirm component to suppress or restyle.

SuccessStep

interface SuccessStep {
  type:                 'success'
  guid?:                string
  savedTitle?:          string
  savedDescription?:    string
  cancelledTitle?:      string
  cancelledDescription?: string
  classNames?:          SuccessClassNames
}

Success is terminal. The SDK renders the saved copy when an offer was accepted, the cancelled copy when the customer confirmed.

CustomStepConfig

interface CustomStepConfig {
  type:         string             // any non-built-in string identifies a custom step
  guid?:        string
  title?:       string
  description?: string
  data?:        Record<string, unknown>
}

Register a component for the type on customComponents. The component receives step, customer, subscriptions, onNext, onBack. See Custom step + offer types.

ReasonConfig

interface ReasonConfig {
  id:        string
  label:     string
  freeform?: boolean             // shows a textarea under the reason list when picked
  offer?:    OfferConfig         // attached offer; presented if the customer picks this reason
}

A reason with freeform: true reveals a textarea below the reason list when the customer picks it. The typed text lands on the session as followupResponse, alongside surveyChoiceId (the reason's id) and surveyChoiceValue (the static label) — analytics groupings stay stable on id and label.

Reason IDs land on the session as reasonId on AcceptedOffer and on outcome.reason. Keep them stable — analytics joins on them.

Transitions

The SDK resolves the next step in this order:

  1. If the current step is a survey and the selected reason has an offer, the next step is that offer.
  2. Otherwise, advance to the next step in steps.
  3. On accept, advance directly to success. Intervening steps are skipped.
  4. On decline from an offer step, advance to the next step.

A step with a type that isn't built-in and isn't registered in customComponents logs a console warning and is skipped. The flow never crashes on unknown types.

Connected mode override rules

When the dashboard supplies steps and you also pass steps:

Server step typeLocal step with same typeResult
PresentAbsentServer step renders.
PresentPresentLocal overrides by type.
AbsentPresentLocal step is appended.

This lets you keep a custom step (like NPS) on every flow regardless of dashboard config.

Next steps