Skip to main content

User Onboarding

Welcome a new user with email, send a Telegram team alert, an in-app nudge, an HTTP setup check that gates the next step, then an SMS confirmation.

Sequence steps

Follow each step as it queues up, sends, and completes.

Sequence code
tenant_key = "demo"

{:ok, email_adapter} =
  DripDrop.create_channel_adapter(%{
    tenant_key: tenant_key,
    name: "Local email",
    channel: "email",
    provider: "local",
    is_default: true,
    credentials: %{"from" => "DripDrop Demo <demo@dripdrop.dev>"}
  })

{:ok, sms_adapter} =
  DripDrop.create_channel_adapter(%{
    tenant_key: tenant_key,
    name: "Local SMS",
    channel: "sms",
    provider: "local",
    is_default: true,
    credentials: %{"from" => "+15550001000"}
  })

{:ok, pubsub_adapter} =
  DripDrop.create_channel_adapter(%{
    tenant_key: tenant_key,
    name: "Phoenix PubSub",
    channel: "pubsub",
    provider: "phoenix_pubsub",
    is_default: true,
    credentials: %{
      "pubsub" => "DripdropDemo.PubSub",
      "topic" => "demo:in_app"
    }
  })

{:ok, telegram_adapter} =
  DripDrop.create_channel_adapter(%{
    tenant_key: tenant_key,
    name: "Local Telegram",
    channel: "telegram",
    provider: "local",
    is_default: true,
    credentials: %{"chat_id" => "@dripdrop_demo"}
  })

{:ok, sequence} =
  DripDrop.create_sequence(%{
    tenant_key: tenant_key,
    name: "Onboarding demo",
    key: "onboarding",
    description:
      "Short lifecycle sequence for exercising email, PubSub, HTTP hooks, SMS, and Telegram.",
    active: true,
    metadata: %{"demo" => true}
  })

{:ok, setup_status_hook} =
  DripDrop.create_http_hook(sequence.id, %{
    tenant_key: tenant_key,
    name: "Setup status check",
    key: "setup_status",
    description: "Checks whether the app has marked onboarding setup complete.",
    method: "GET",
    url:
      DripdropDemo.MockHooks.url(
        "/onboarding/setup-status?subscriber_id={{ subscriber_id }}&plan={{ plan }}&setup_complete={{ setup_complete }}"
      ),
    response_type: "boolean",
    response_path: "sms_followup_eligible",
    timeout_ms: 2_000,
    retry_count: 0
  })

{:ok, version} =
  DripDrop.create_sequence_version(sequence.id, %{
    version: 1,
    name: "Local demo path",
    mode: :lifecycle,
    config: %{"demo_time_scale" => Application.fetch_env!(:dripdrop_demo, :demo_time_scale)}
  })

{:ok, welcome_email} =
  DripDrop.create_step(version.id, %{
    name: "Welcome email",
    key: "welcome-email",
    position: 1,
    channel: "email",
    channel_adapter_id: email_adapter.id,
    timing: %{type: "immediate"},
    template_type: "inline",
    template_content: %{
      "subject" => "Welcome to DripDrop, {{ first_name }}",
      "text" => "Hi {{ first_name }}, your onboarding sequence has started.",
      "html" => "<p>Hi {{ first_name }}, your onboarding sequence has started.</p>"
    },
    config: %{"unsubscribe_headers" => true}
  })

{:ok, telegram_message} =
  DripDrop.create_step(version.id, %{
    name: "Telegram team alert",
    key: "telegram-message",
    position: 2,
    channel: "telegram",
    channel_adapter_id: telegram_adapter.id,
    timing: %{type: "delay", delay_amount: 2, delay_unit: "seconds"},
    template_type: "inline",
    template_content: %{
      "chat_id" => "@dripdrop_demo",
      "text" => "New signup: {{ first_name }} joined the onboarding flow."
    },
    config: %{}
  })

{:ok, in_app_nudge} =
  DripDrop.create_step(version.id, %{
    name: "In-app nudge",
    key: "in-app-nudge",
    position: 3,
    channel: "pubsub",
    channel_adapter_id: pubsub_adapter.id,
    timing: %{type: "delay", delay_amount: 10, delay_unit: "seconds"},
    template_type: "inline",
    template_content: %{
      "topic" => "demo:in_app",
      "event" => "onboarding.nudge",
      "payload" => %{
        "title" => "Finish setup",
        "message" => "{{ first_name }}, complete setup to unlock the next step."
      }
    },
    config: %{}
  })

{:ok, setup_sms} =
  DripDrop.create_step(version.id, %{
    name: "Setup SMS",
    key: "setup-sms",
    position: 4,
    channel: "sms",
    channel_adapter_id: sms_adapter.id,
    timing: %{type: "delay", delay_amount: 12, delay_unit: "seconds"},
    template_type: "inline",
    template_content: %{
      "body" =>
        "{{ first_name }}, your onboarding setup is complete!"
    },
    config: %{"recipient_key" => "sms"}
  })

{:ok, _welcome_to_telegram} =
  DripDrop.create_step_transition(version.id, %{
    from_step_id: welcome_email.id,
    to_step_id: telegram_message.id,
    condition_mode: "always",
    priority: 1
  })

{:ok, _telegram_to_nudge} =
  DripDrop.create_step_transition(version.id, %{
    from_step_id: telegram_message.id,
    to_step_id: in_app_nudge.id,
    condition_mode: "always",
    priority: 1
  })

{:ok, setup_transition} =
  DripDrop.create_step_transition(version.id, %{
    from_step_id: in_app_nudge.id,
    to_step_id: setup_sms.id,
    condition_mode: "all",
    priority: 1
  })

{:ok, _setup_condition} =
  DripDrop.create_condition(setup_transition.id, %{
    transition_id: setup_transition.id,
    condition_type: "hook",
    http_hook_id: setup_status_hook.id,
    operator: "==",
    expected_value: "true"
  })

{:ok, _end_sequence} =
  DripDrop.create_step_transition(version.id, %{
    from_step_id: setup_sms.id,
    to_step_id: nil,
    condition_mode: "always",
    priority: 1
  })

{:ok, _validated} =
  DripDrop.validate_sequence_version(version.id)

{:ok, _activated} =
  DripDrop.activate_sequence_version(version.id)

{:ok, enrollment} =
  DripDrop.enroll(%{
    sequence_id: sequence.id,
    subscriber_type: "demo_user",
    subscriber_id: "onboarding-...",
    tenant_key: tenant_key,
    data: %{
      "first_name" => "Sam",
      "email" => "sam@example.com",
      "sms" => "+15555550101",
      "plan" => "standard",
      "setup_complete" => true
    }
  })

Sequence messages

Messages appear here as each step is sent.

Sequence logs
# Live DripDrop events will stream here after dispatch starts.
A project by Goodway — we build software that drives results.