# @healthie/sdk

> Healthie React SDK

Latest version **1.5.5** (published 2026-08-17) · See LICENSE file license · 0 weekly downloads

## Install

```sh
npm install @healthie/sdk
pnpm add @healthie/sdk
yarn add @healthie/sdk
bun add @healthie/sdk
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.5.5 |
| Published | 2026-08-17 |
| First published | 2023-04-04 |
| Weekly downloads | 0 |
| License | See LICENSE file |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 45 |
| Unpacked size | 973.4 KB |
| Known vulnerabilities | 0 (+1 in 1 direct dependencies) |
| Install scripts | no |
| Author | Healthie Inc |
| Maintainers | klinskyc, healthie_bot, chris_healthie |
| Keywords | healthie |

## Links

- npm: https://www.npmjs.com/package/@healthie/sdk
- npm.io page: https://npm.io/package/@healthie/sdk

## Dependencies (45)

- [clsx](https://npm.io/package/clsx.md) ^1.2.1
- [uuid](https://npm.io/package/uuid.md) ^9.0.0
- [moment](https://npm.io/package/moment.md) ^2.29.4
- [date-fns](https://npm.io/package/date-fns.md) ^3.6.0
- [dompurify](https://npm.io/package/dompurify.md) ^3.2.6
- [linkifyjs](https://npm.io/package/linkifyjs.md) ^4.3.1
- [states-us](https://npm.io/package/states-us.md) ^1.0.2
- [@tiptap/pm](https://npm.io/package/@tiptap/pm.md) ^2.1.3
- [final-form](https://npm.io/package/final-form.md) ^4.20.9
- [linkify-html](https://npm.io/package/linkify-html.md) ^4.3.1
- [react-select](https://npm.io/package/react-select.md) ^5.7.1
- [@tiptap/react](https://npm.io/package/@tiptap/react.md) ^2.0.0-beta.209
- [react-virtuoso](https://npm.io/package/react-virtuoso.md) 4.12.3
- [react-waypoint](https://npm.io/package/react-waypoint.md) ^10.3.0
- [spinners-react](https://npm.io/package/spinners-react.md) ^1.0.7
- [moment-timezone](https://npm.io/package/moment-timezone.md) ^0.5.43
- [prosemirror-view](https://npm.io/package/prosemirror-view.md) ^1.29.1
- [react-datepicker](https://npm.io/package/react-datepicker.md) ^4.10.0
- [react-final-form](https://npm.io/package/react-final-form.md) ^6.5.9
- [@headlessui/react](https://npm.io/package/@headlessui/react.md) ^1.7.7
- [@stripe/stripe-js](https://npm.io/package/@stripe/stripe-js.md) ^1.53.0
- [final-form-arrays](https://npm.io/package/final-form-arrays.md) ^3.1.0
- [prosemirror-model](https://npm.io/package/prosemirror-model.md) ^1.18.3
- [prosemirror-state](https://npm.io/package/prosemirror-state.md) ^1.4.2
- [react-canvas-draw](https://npm.io/package/react-canvas-draw.md) ^1.2.1
- [prosemirror-keymap](https://npm.io/package/prosemirror-keymap.md) ^1.2.0
- [@tiptap/starter-kit](https://npm.io/package/@tiptap/starter-kit.md) ^2.0.0-beta.209
- [@u-wave/react-vimeo](https://npm.io/package/@u-wave/react-vimeo.md) ^0.9.10
- [prosemirror-history](https://npm.io/package/prosemirror-history.md) ^1.3.0
- [react-device-detect](https://npm.io/package/react-device-detect.md) ^2.2.3
- [prosemirror-commands](https://npm.io/package/prosemirror-commands.md) ^1.5.0
- [react-debounce-input](https://npm.io/package/react-debounce-input.md) ^3.3.0
- [prosemirror-gapcursor](https://npm.io/package/prosemirror-gapcursor.md) ^1.3.1
- [prosemirror-transform](https://npm.io/package/prosemirror-transform.md) ^1.7.0
- [prosemirror-dropcursor](https://npm.io/package/prosemirror-dropcursor.md) ^1.6.1
- [react-signature-canvas](https://npm.io/package/react-signature-canvas.md) ^1.0.6
- [@stripe/react-stripe-js](https://npm.io/package/@stripe/react-stripe-js.md) ^2.1.0
- [prosemirror-schema-list](https://npm.io/package/prosemirror-schema-list.md) ^1.2.2
- [react-custom-scrollbars](https://npm.io/package/react-custom-scrollbars.md) ^4.2.1
- [react-final-form-arrays](https://npm.io/package/react-final-form-arrays.md) ^3.1.4
- [@types/react-canvas-draw](https://npm.io/package/@types/react-canvas-draw.md) ^1.2.0
- [@tiptap/extension-underline](https://npm.io/package/@tiptap/extension-underline.md) ^2.0.0-beta.209
- [@tiptap/extension-placeholder](https://npm.io/package/@tiptap/extension-placeholder.md) ^2.0.0-beta.209
- [@types/react-signature-canvas](https://npm.io/package/@types/react-signature-canvas.md) ^1.0.2
- [@types/react-custom-scrollbars](https://npm.io/package/@types/react-custom-scrollbars.md) ^4.0.10

## Recent versions

- 1.5.5 (latest) — 2026-08-17
- 1.5.5-rc.0 (legacy-next) — 2026-08-17
- 1.5.4-rc.0 (next) — 2026-07-22
- 1.5.4 — 2026-08-03
- 1.5.3 — 2026-05-13
- 1.5.3-rc.0 — 2026-05-13
- 2.0.0-rc.0 — 2026-04-17
- 1.5.2-rc.1 — 2025-10-30
- 1.5.2-rc.0 — 2025-10-30
- 1.5.1-rc.3 — 2025-09-05
- 1.5.1-rc.2 — 2025-08-27
- 1.5.1-rc.1 — 2025-08-27
- 1.5.1-rc.0 — 2025-07-16
- 1.5.0 — 2025-07-16
- 1.5.0-rc.7 — 2025-07-08
- … 37 more at https://npm.io/package/@healthie/sdk/versions

## README

# Official React SDK for Healthie API <!-- omit in toc -->

- [Overview](#overview)
- [Before you start](#before-you-start)
- [Installation](#installation)
- [Basic setup](#basic-setup)
  - [Server-Side Rendering](#server-side-rendering)
- [Example usage](#example-usage)
- [Components](#components)
  - [Conversation List](#conversation-list)
    - [Props](#props)
    - [Detailed usage](#detailed-usage)
  - [Chat](#chat)
    - [Props](#props-1)
  - [Form](#form)
    - [Props](#props-2)
    - [Detailed usage](#detailed-usage-1)
    - [Styling](#styling)
    - [Document and Folder Fields](#document-and-folder-fields)
  - [Booking \& Buying](#booking--buying)
    - [Props](#props-3)
- [License](#license)

## Overview

Healthie SDK is a React component library built with TypeScript, providing components and hooks to make it easier to work with Healthie's API. Currently supported features include:

- Chat
- Forms
- Booking & Buying

## Before you start

This SDK is intended to be used in an existing projects that use Healthie's API. The user authentication flow is not currently part of this SDK and should be implemented separately in your project.

## Installation

```sh
yarn add @healthie/sdk
yarn add @rails/actioncable graphql-ruby-client
# or
npm i @healthie/sdk
npm i @rails/actioncable graphql-ruby-client
```

## Basic setup

This SDK works on top of the Apollo Client with the assumption that you already have the Apollo Client installed and set up.

Chat and other websocket capabilities are implemented using ActionCable.

The following is a basic configuration of the Apollo Client in order to let the SDK to work properly:

```jsx
import {
  ApolloProvider,
  HttpLink,
  ApolloClient,
  InMemoryCache,
  split,
} from '@apollo/client'
import { getMainDefinition } from '@apollo/client/utilities'
import * as ActionCable from '@rails/actioncable'
import ActionCableLink from 'graphql-ruby-client/subscriptions/ActionCableLink'

import { HealthieProvider } from '@healthie/sdk'

const httpLink = new HttpLink({
  uri: 'https://api.gethealthie.com/graphql',
  headers: {
    authorization: 'Basic <user_auth_token>',
    authorizationsource: 'API',
  },
})

const cable = ActionCable.createConsumer(
  'wss://ws.gethealthie.com/subscriptions?token=<user_auth_token>'
)
const wsLink = new ActionCableLink({ cable })

const link = split(
  // split based on operation type
  ({ query }) => {
    const definition = getMainDefinition(query)
    if (!('operation' in definition)) {
      return false
    }

    const { kind, operation } = definition
    return kind === 'OperationDefinition' && operation === 'subscription'
  },
  wsLink,
  httpLink
)

const client = new ApolloClient({
  link,
  cache: new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          // custom configuration if needed
        },
      },
    },
  }),
})

export function App() {
  return (
    <ApolloProvider client={client}>
      <HealthieProvider userId={'<user_id>'}>
        {/* ... your app ... */}
      </HealthieProvider>
    </ApolloProvider>
  )
}
```

Replace `<user_auth_token>` with the user's API key obtained during the authentication process and `<user_id>` with the ID of the currently authenticated user.

Read more about Healthie API authentication [here](https://docs.gethealthie.com/docs/#authentication).

### Server-Side Rendering

Frameworks such as Next.js, Remix, Astro, and others heavily depend on server-side rendering (SSR). This means they attempt to render the code on the server where browser APIs are not available. Some Healthie SDK components (like Chat) utilize WebSockets through the ActionCable library. If you try to use the above ActionCable code in Next.js or other SSR frameworks, you will likely encounter an error.

To address this issue, follow the steps below. This solution should work for most frameworks. If you prefer a framework-specific solution, such as [`next/dynamic`](https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading), consult your framework's documentation.

First, create a `useHydrated.ts` React hook that will help us determine if the JS has been hydrated already.

```tsx
import { useEffect, useState } from 'react'

let isHydrating = true

export function useHydrated() {
  let [isHydrated, setIsHydrated] = useState(() => !isHydrating)

  useEffect(function hydrate() {
    isHydrating = false
    setIsHydrated(true)
  }, [])

  return isHydrated
}
```

Next, define our `ClientOnly.tsx` component that renders its children only client-side.

```tsx
import { ReactNode } from 'react'
import { useHydrated } from './useHydrated'

type Props = {
  children(): ReactNode
  fallback?: ReactNode
}

export function ClientOnly({ children, fallback = null }: Props) {
  return useHydrated() ? <>{children()}</> : <>{fallback}</>
}
```

Then make sure to lazy-load the ApolloProvider and its client definition, so we avoid running the WebSocket code on the server.

Create a file called `ApolloForHealthie.tsx` which wraps ApolloProvider.

```tsx
type ProviderProps = {
  children: React.ReactNode
}

// rest of the client initialization code (see the "Basic setup" guide)
// ...
// ...
// ...

const client = new ApolloClient({
  link,
  cache: new InMemoryCache(),
})

export default function ApolloForHealthie({ children }: ProviderProps) {
  return <ApolloProvider client={client}>{children}</ApolloProvider>
}
```

Lastly, load the new provider lazily and wrap it with the ClientOnly component:

```tsx
import { lazy } from 'react'

// it's important to use the React.lazy() instead of regular import
const ApolloForHealthie = lazy(() => import('./ApolloForHealthie'))

function Loading() {
  return (
    <div>
      {/* Ideally this should be the same size as the original component to avoid layout shifts */}
    </div>
  )
}

export default function App() {
  const healthieUserId = '__REPLACE_ME__'

  return (
    <ClientOnlyHydrated fallback={<Loading />}>
      {() => (
        <ApolloForHealthie>
          <HealthieProvider userId={healthieUserId}>
            {/* render Healthie components here */}
          </HealthieProvider>
        </ApolloForHealthie>
      )}
    </ClientOnlyHydrated>
  )
}
```

The above code will render the ApolloClient and Healthie components client-side, while rendering the custom-defined Loading component on the server. This prevents the use of browser-specific APIs, such as ActionCable, on the server.

## Example usage

```jsx
import { ConversationList, Chat, Form } from '@healthie/sdk'
import '@healthie/sdk/dist/styles/index.css'

// This example assumes you defined the Apollo Client according to the
// instructions described in the "Basic setup" section of the Readme

// const client = ...

export default function App() {
  const healthieUserId = '' // obtain during the auth flow

  return (
    <ApolloProvider client={client}>
      {/* HealthieProvider must be rendered before using any of these components */}
      <HealthieProvider userId={healthieUserId}>
        {/* ... */}
        <div className="conversation-list-container">
          <ConversationList />
        </div>
        <div className="chat-container">
          <Chat />
        </div>

        {/* ... */}
        <div>
          <Form id="1">
        </div>

        {/* ... */}
      </HealthieProvider>
    </ApolloProvider>
  )
}
```

## Components

Make sure to import the stylesheet, usually in the root component of your app:

```jsx
import '@healthie/sdk/dist/styles/index.css'
```

### Conversation List

This component will fetch the list of active conversations for the currently authenticated user and display it on the screen.
If no `onConversationClick` or `activeId` props were provided, Healthie SDK will manage the state itself.

> :bulb: The default and recommended way to render this component is to leave both props empty and let the HealthieContext manage it's state.

```jsx
<ConversationList
  onConversationClick={handleOnConversationClick}
  activeId="<conversation_id>"
/>
```

#### Props

| Prop name             | Type              | Description                                                                                                                                 |
| --------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `onConversationClick` | `Function`        | (optional) Callback to trigger when user clicks on the Conversation item. If not provided, will set the clicked conversaton as active.      |
| `activeId`            | `string` / `null` | (optional) ID of the currently selected Conversation. If not provided, the component will set the first conversation on the list as active. |

#### Detailed usage

```jsx
import { useState } from 'react'

function Example() {
  const [conversationId, setConversationId] = useState(null)

  return (
    <ConversationList
      onConversationClick={(id) => {
        setConversationId(id)
      }}
      activeId={conversationId}
    />
  )
}
```

### Chat

```jsx
<Chat conversationId="<conversation_id>" />
```

> **Warning**: If you rendered the `ConversationList` component without custom props, don't provide the `conversationId` prop in order to leverage full capabilities of Healthie Context.

#### Props

| Prop name        | Type     | Description                                                                                                                                                                                                                                                                                |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `conversationId` | `string` | (optional) ID of the Conversation to open. Obtain this information [via the GraphQL API](https://docs.gethealthie.com/docs/#listing-conversations) or use the [Conversation List](#conversation-list) component. If not provided, will render the active Conversation from HealthieContext |

The `Chat` component takes the full height of the parent container. This enables you to fully control this component's sizing and positioning.

Make sure to correctly specify the height of the container (fixed or fluid), otherwise chat messages may not be visible.

> :bulb: Make sure to provide the currently authenticated Healthie User's ID to the `HealthieProvider`. Otherwise the Chat component will not be able to distinguish incoming and outgoing messages.

### Form

The `Form` component renders a Form Template (known as a Custom Module Form) in the context of the current user. It will automatically prefill the form with the user's data (if applicable) and will submit the form on behalf of the user.

```jsx
<Form id="<custom_module_form_id>" />
```

#### Props

| Prop name               | Type                                                                  | Description                                                                                                                                                                                                                                                                                                                                                                                                               |
| ----------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                    | `string`                                                              | ID of the Form Template (Custom Module Form) to render. You can retrieve a Form Template ID by, for example, querying [Form Completion Requests](https://docs.gethealthie.com/docs/#form-completion-requests) for the current user.                                                                                                                                                                                       |
| `submitButtonText`      | `string?`                                                             | (optional) Text to display on the submit button. Defaults to "Submit".                                                                                                                                                                                                                                                                                                                                                    |
| `onSubmit`              | `(values: FormFields) => Promise<boolean \| void> \| boolean \| void` | (optional) Callback to trigger when the form is submitted. The callback will receive form data to submit as an argument. You can optionally return `false` from the callback to prevent the form from submitting. In this case, you will need to manually submit the form by using the [`createFormAnswerGroup`](https://docs.gethealthie.com/docs/#creating-a-filled-out-form-e-g-a-chart-note-or-intake-form) mutation. |
| `onQueryStateChange`    | `({ loading, error, data }: QueryState) => void`                      | (optional) Callback to receive Apollo Query state change updates when loading the form.                                                                                                                                                                                                                                                                                                                                   |
| `onMutationStateChange` | `({ loading, error, data }: MutationState) => void`                   | (optional) Callback to receive Apollo Mutation state change updates when submitting the form.                                                                                                                                                                                                                                                                                                                             |

#### Detailed usage

```jsx
import { useState } from 'react'

function Example() {
  const customModuleFormId = '' // obtain via the GraphQL API

  return (
    <Form
      id={customModuleFormId}
      onSubmit={(data) => {
        // do something with the data
        // return false to prevent the form from submitting
      }}
      onQueryStateChange={({ loading, error, data }) => {
        // access Apollo query status
      }}
      onMutationStateChange={({ loading, error, data }) => {
        // access Apollo mutation statu
      }}
      submitButtonText="Submit form"
    />
  )
}
```

#### Styling

Currently the `Form` component supports custom styling only via overriding the default CSS classes. All fields have generic class names like `input-wrapper` or `form-field-container`. Each field type has its own class name, so you can target specific fields.

Additionally, all Healthie SDK components are wrapped in a `healthie-container` class.
To override the default styles, you can leverage the CSS specificity and override the default styles by using the `healthie-container` class as a parent selector.

For example:

```css
.healthie-container .input-text {
  /* your styles */
}
```

This way you are not required to use `!important` to override the default styles, while still being able to style form components according to your needs.

#### Document and Folder Fields

The `Form` component supports rendering Document and Folder fields. These fields open a link to the corresponding document or folder in the Healthie Web app. By default, the link will open the app via generic domain (https://secure.gethealthie.com). If you are using a branded Healthie URL, you can pass the `brandedUrl` prop to the Healthie Context via the `HealthieProvider` component.

```jsx
<HealthieProvider userId="<user_id>" brandedUrl="https://myapp.example.com">
  <Form id="<form_id>" />
</HealthieProvider>
```

This will open Documents or Folders via the branded URL like this: https://myapp.example.com/documents/{id}/download.

### Booking & Buying

The `Booking` components renders the widget for Calendar and Packages, which enables clients to book appointments, browse services, and purchase packages.

```jsx
<Booking queryString={queryString} />
```

Appointment calendar links are generated with the Healthie production URL by default. If you are using a branded Healthie Backend URL or Healthie staging environment, you can pass the `brandedBackendUrl` prop to the Healthie Context via the `HealthieProvider` component.

```jsx
<HealthieProvider
  userId="<user_id>"
  brandedBackendUrl="https://staging-api.gethealthie.com"
>
  <Booking queryString={queryString} />
</HealthieProvider>
```

#### Props

| Prop name     | Type     | Description                                                                                                                                                                                                                                                                                                    |
| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `queryString` | `string` | The query string used to render the booking embed widget. This is obtained via the [Sharing Link](https://help.gethealthie.com/article/75-integrate-healthie-with-website) generated in the Healthie Dashboard. For example: `?dietitian_id=1&require_offering=true&offering_id=24&hide_package_images=false`. |

## License

This SDK is licensed under The Healthie React SDK license. See the LICENSE file for more details.

---
_Source: https://npm.io/package/@healthie/sdk · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
