Docs navigation

Quickstart

Render a cancel flow with a survey, offers, and a confirm step using a single React component. The SDK runs in the browser and has no backend or account requirement.

Before you begin

You'll need React 18 or 19.

1. Install the SDK

npm install @churnkey/react

2. Render <CancelFlow>

<CancelFlow> takes a steps array describing the path the customer walks and a handle<Type> callback for each action you want to support. The example below builds a three-reason survey with attached offers, a feedback prompt, and a confirm step.

import { useState } from 'react'
import { CancelFlow } from '@churnkey/react'
import '@churnkey/react/styles.css'
 
export function CancelButton() {
  const [open, setOpen] = useState(false)
 
  return (
    <>
      <button onClick={() => setOpen(true)}>Cancel subscription</button>
      {open && (
        <CancelFlow
          steps={[
            {
              type: 'survey',
              title: 'Why are you leaving?',
              reasons: [
                {
                  id: 'expensive',
                  label: 'Too expensive',
                  offer: {
                    type: 'discount',
                    couponId: 'STRIPE_SAVE20',
                    percentOff: 20,
                    durationInMonths: 3,
                  },
                },
                {
                  id: 'not-using',
                  label: 'Not using it enough',
                  offer: { type: 'pause', months: 2 },
                },
                { id: 'missing', label: 'Missing a feature', freeform: true },
              ],
            },
            { type: 'feedback', title: 'Anything else?' },
            { type: 'confirm' },
          ]}
          handleDiscount={async (offer) => {
            await fetch('/api/billing/discount', {
              method: 'POST',
              body: JSON.stringify({ couponId: offer.couponId }),
            })
          }}
          handlePause={async (offer) => {
            await fetch('/api/billing/pause', {
              method: 'POST',
              body: JSON.stringify({ months: offer.months }),
            })
          }}
          handleCancel={async () => {
            await fetch('/api/billing/cancel', { method: 'POST' })
          }}
          onClose={() => setOpen(false)}
        />
      )}
    </>
  )
}

The SDK calls the matching handle<Type> when the customer accepts an offer and awaits the promise before advancing. handleCancel runs on confirm. Closing the modal mid-flow records the session as abandoned, visible once analytics is wired up.

3. Walk every path

Open the flow and test each reason.

PickWhat happens
Too expensiveThe discount offer appears. Accepting calls handleDiscount with the coupon ID and display fields.
Not using it enoughThe pause offer appears. Accepting calls handlePause with { months: 2 }.
Missing a featureA follow-up textarea appears under the reason. The typed answer lands on the session as followupResponse. No offer is attached, so the flow advances to feedback → confirm. Confirming calls handleCancel.

How steps resolve

The SDK walks steps in order, with two exceptions.

A survey reason with an attached offer routes to that offer next. The offer step isn't declared in your steps array — the SDK synthesizes it from the reason's offer config. Reasons without an offer fall through to the next declared step.

Accepting an offer fires the matching handle<Type> and, once it resolves, transitions to success. Any steps between the offer and success are skipped.

That's the navigation model for open source. Connected mode adds server-driven step config, segment-specific variants, and A/B tests. The Intelligence tier adds Adaptive Offers and Feedback AI. The navigation rules don't change at any level. See Integration levels.

Next steps

  • Concepts — the mental model behind steps, offers, handlers, and listeners.
  • Build a flow with offers — attach discount, pause, plan change, or trial-extension offers to reasons.
  • Theming — color scheme, CSS variables, classNames, and component overrides.