You can also use our Reach React Library to embed Reach into your application.
You can see an example Github repository for a React application that uses this library here.
We currently only support React 18.

Install the library

npm install @embedreach/components

Initialize the library

Start by importing our css styles at the top of your application:
import "@embedreach/components/styles.css";
Now to integrate Reach components into your application, wrap them with the ReachProvider component. The provider requires a config object that initializes the Reach SDK with authentication and tenant configuration.
const config = {
  theme: {
    ...
  },
  authToken: 'your-auth-token',
  callbacks: {
    onReauthRequested: async () => {
      // return your auth token
      const token = ''
    },
  },
}


<ReachProvider {...config}>
  ...
</ReachProvider>
Please see Authentication for more information on how to generate an auth token.
Please see Customization for more information on how to customize the components.

Customization

We support the following customization options:

Components Available

SegmentBuilderDialog

We expose a dialog component that can be used to create and edit segments.
<SegmentBuilderDialog
  /**
   * Control the open state of the dialog
   */
  open: boolean;
  setOpen: (open: boolean) => void;

  /**
   * Optional callback when the segment builder is closed
   * @param createdSegment - The created segment id or false if the segment was not created, 'error' if there was an error
   */
  onSegmentUpdated?: (createdSegment: string | false | 'error') => void;

  /**
   * Optionally pass in a segmentId to edit an existing segment
   */
  segmentId?: string;
/>

CreateAutomationDialog

This is the initial modal that can be used to create a new automation.
<CreateAutomationDialog
  /**
   * Optional callback when the segment builder is closed
   * @param createdAutomation - The created automation id or false if the automation was not created, 'error' if there was an error
   */
  onClose?: (createdAutomation: string | false | 'error') => void;

/**
   * Optionally skip the selection of automation and jump to the automation type
   * Currently only supports one time automation
   *
   * @Note This will remove the ability to select the automation type (e.g. the user will not be able to change the automation type)
   */
  automationType?: AutomationTriggerType.ONE_TIME;

  /**
   * Optional function to return extra merge fields for the automation
   */
  getExtraMergeFields?: () => Promise<ReachMergeField[]>;

  /**
   * Optional text and hyperlink to display for
   * replyTo settings
   */
  replyToSettingsText?: string;
  replyToSettingsLink?: string;

  /**
   * Optional text and hyperlink to display for
   * from name settings
   */
  fromNameSettingsText?: string;
  fromNameSettingsLink?: string;

  /**
   * Optional function to call prior to scheduling if a user wants to implement custom
   * logic to block scheduling
   *
   * @param args.estimatedEmailRecipients - The estimated number of email recipients
   * @param args.estimatedSmsRecipients - The estimated number of sms recipients
   *
   * @returns true if the automation should be scheduled, string otherwise that will be displayed to the user in a toast notification
   */
  onBeforeSchedule?: (args: {
    estimatedEmailRecipients: number;
    estimatedSmsRecipients: number;
  }) => Promise<true | string>;
/>

ViewAutomationModal

This is the component used to view and edit automations. This components allows users to preview communications, edit automation details and view statistics on sent communications.
<ViewAutomationModal
 /**
   * The id of the automation to view
   */
  automationId?: string;

  /**
   * Optional function to return extra merge fields for the automation
   */
  getExtraMergeFields?: () => Promise<ReachMergeField[]>;

  /**
   * Optional callback when a duplication is created
   */
  onDuplicationCreated?: (duplicationId: string) => void;

  /**
   * Optional boolean to hide features
   */
  hideSms?: boolean;
  hideSales?: boolean;

  /**
   * Optional text and hyperlink to display for
   * replyTo settings
   */
  replyToSettingsText?: string;
  replyToSettingsLink?: string;

  /**
   * Optional text and hyperlink to display for
   * from name settings
   */
  fromNameSettingsText?: string;
  fromNameSettingsLink?: string;

  /**
   * Optional function to call prior to scheduling if a user wants to implement custom
   * logic to block scheduling
   *
   * @param args.estimatedEmailRecipients - The estimated number of email recipients
   * @param args.estimatedSmsRecipients - The estimated number of sms recipients
   *
   * @returns true if the automation should be scheduled, string otherwise that will be displayed to the user in a toast notification
   */
  onBeforeSchedule?: (args: {
    estimatedEmailRecipients: number;
    estimatedSmsRecipients: number;
  }) => Promise<true | string>;
/>
If you would like to request any additional components, please reach out to us at support@embedreach.com.

Extra Merge Fields

The ViewAutomationModal component allows you to pass in a function to return extra merge fields for the automation.
getExtraMergeFields?: () => Promise<ReachMergeField[]>;
The expected return type is an array of ReachMergeField objects. Each merge field can be either a static or dynamic type. Each merge field must have a unique id that will be used when updating merge field contents. The type field determines whether it’s a static or dynamic merge field.
You cannot have two identical template names for any merge fields.
When a merge field includes an image configuration, the image will be automatically added as an attachment to the message. The merge field still provides its text value for use in the message content, while the image serves as a supplementary attachment (e.g., a QR code for a coupon, a product image, etc.).

Dynamic Merge Field

type DynamicMergeField = {
  type: 'dynamic';
  id: string;
  mergeFields: {
    displayName: string;
    templateName: string;
    /**
     * Optional image configuration for this merge field. Auto-applied to SMS if the merge field text is used.
     */
    image?: {
      placeholderUrl: string; // URL for placeholder image to show in UI
      maxSize: number; // Max size in bytes for this image (used to deduct from total message size)
    };
  }[];
  url: string;  // e.g. "https://acme.co/id/" (we require https)
};

URL Requirements

The URL will be called with a POST request with the following body:
{
 userIds: string[];
 id: string; // `id` is the id of the dynamic merge field
 tenantExternalId: string; // `tenantExternalId` is the external id of the business
}
And a the following headers:
{
  'Authorization': 'Bearer your-auth-token'
}
Where the your-auth-token is a signed JWT token using the shared secret for the platform. The userIds are mapped to the externalId Partner Resource. The response should be a JSON object with the following format:
{
 [userId: string]: {
  /**
   * The value of the merge field
   * For text fields: string
   * For fields with images: { value: string; image?: { url: string } }
   */
  [mergeFieldId: string]: string | { value: string; image?: { url: string } };
 }
}
This means for example if you have a dynamic merge field, you can pass up to 20 merge fields in a single request.
{
  type: 'dynamic',
  id: 'coupon_code',
  mergeFields: [
    {
      displayName: 'Coupon Code',
      templateName: 'coupon_code'
    },
    {
      displayName: 'Expiration Date',
      templateName: 'expiration_date'
    },
    {
      displayName: 'Coupon With QR Code',
      templateName: 'coupon_with_qr_code',
      image: {
        placeholderUrl: 'https://acme.co/placeholder-qr-code.jpg',
        maxSize: 1600
      }
    },
    ... // other merge fields you might want to pass
  ],
  url: 'https://acme.co/id/'
}
The URL will be called with the following body:
{
  userIds: ['123', '456'],
  id: 'coupon_code',
  tenantExternalId: 'acme' // the external id of the business
}
And the expected response would be where the key is the userId and it returns a dictionary of all the templateNames and their values:
{
  '123': {
    'coupon_code': '123456',
    'expiration_date': '2021-01-01',
    'coupon_with_qr_code': {
      value: '123456',
      image: {
        url: 'https://acme.co/qr-codes/123456.png'
      }
    }
  },
  '456': {
    'coupon_code': '456789',
    'expiration_date': '2021-02-01',
    'coupon_with_qr_code': {
      value: '456789',
      image: {
        url: 'https://acme.co/qr-codes/456789.png'
      }
    }
  }
}