Skip to main content
Inbox UI Preview
This is the latest version of the Courier Web Components SDK, recommended for new and existing apps.Coming from an earlier version? We recommend upgrading — check out the migration guide for the React SDK, which is a thin wrapper around Inbox Web Components and exposes a similar API.

Installation

Available on GitHub and npm.
npm install @trycourier/courier-ui-inbox
The Courier SDKs work with any JavaScript build system and do not require any additional build configuration.
Using React? Check out the Courier Inbox React Components.

Authentication

To use the SDK, you need to generate a JWT (JSON Web Token) for your user. This JWT should always be generated by your backend server, never in client-side code.

JWT Authentication Flow

1

Your client calls your backend

When your app needs to authenticate a user, your client should make a request to your own backend (ex. GET https://your-awesome-app.com/api/generate-courier-jwt).
2

Your backend calls Courier

In your backend endpoint, use your Courier API Key to call the Courier Issue Token Endpoint and generate a JWT for the user.
3

Your backend returns the JWT to your client

Having received the JWT from Courier, your backend should return it to your client and pass it to the Courier SDK.
See all available user scopes for the Courier APIs.

Development Authentication with cURL

To quickly test JWT generation for development only, you can use cURL to call the Courier Issue Token Endpoint directly.
Do not call the Issue Token API from client-side code. Always keep your Courier API keys secure.
curl --request POST \
     --url https://api.courier.com/auth/issue-token \
     --header 'Accept: application/json' \
     --header 'Authorization: Bearer $YOUR_API_KEY' \
     --header 'Content-Type: application/json' \
     --data \
 '{
    "scope": "user_id:$YOUR_USER_ID write:user-tokens inbox:read:messages inbox:write:events read:preferences write:preferences read:brands",
    "expires_in": "$YOUR_NUMBER days"
  }'

Inbox Web Components

<courier-inbox>

Default Courier Inbox component

Default Courier Inbox component

Importing the Courier SDK registers Courier’s Web Components (<courier-inbox>, <courier-inbox-popup-menu>).
<body>
  <courier-inbox id="inbox"></courier-inbox>

  <script type="module">
    import { Courier } from '@trycourier/courier-ui-inbox';

    // Generate a JWT for your user on your backend server
    const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

    // Authenticate the user with the inbox
    Courier.shared.signIn({
      userId: $YOUR_USER_ID,
      jwt: jwt
    });
  </script>
</body>

<courier-inbox-popup-menu>

Default Courier Inbox Popup Menu component

Default Courier Inbox Popup Menu component

Importing the Courier SDK registers Courier’s Web Components (<courier-inbox>, <courier-inbox-popup-menu>).
<body>
  <div style="padding: 24px;">
    <courier-inbox-popup-menu id="inbox"></courier-inbox-popup-menu>
  </div>

  <script type="module">
    import { Courier } from '@trycourier/courier-ui-inbox';

    // Generate a JWT for your user on your backend server
    const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

    // Authenticate the user with the inbox
    Courier.shared.signIn({
      userId: $YOUR_USER_ID,
      jwt: jwt
    });
  </script>
</body>

Handle Clicks and Presses

<body>
  <courier-inbox id="inbox"></courier-inbox>

  <!-- Uncomment the line below to use the popup menu instead -->
  <!-- <courier-inbox-popup-menu id="inbox"></courier-inbox-popup-menu> -->

  <script type="module">
    import { Courier } from '@trycourier/courier-ui-inbox';

    // Generate a JWT for your user on your backend server
    const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

    // Authenticate the user with the inbox
    Courier.shared.signIn({
      userId: $YOUR_USER_ID,
      jwt: jwt
    });

    const inbox = document.getElementById('inbox');

    // Handle message clicks
    inbox.onMessageClick(({ message, index }) => {
      alert("Message clicked at index " + index +
            ":\n" + JSON.stringify(message, null, 2));
    });

    // Handle message action clicks (these are buttons on individual messages)
    inbox.onMessageActionClick(({ message, action, index }) => {
      alert(
        "Message action clicked at index " + index + ":\n" +
        "Action: " + JSON.stringify(action, null, 2) + "\n" +
        "Message: " + JSON.stringify(message, null, 2)
      );
    });

    // Handle message long presses (useful for mobile web)
    inbox.onMessageLongPress(({ message, index }) => {
      alert("Message long pressed at index " + index +
            ":\n" + JSON.stringify(message, null, 2));
    });
  </script>
</body>

Styles and Theming

The fastest way to style the Courier Inbox to match your app is with a custom theme.
You can customize fonts, icons, text, and more. Check out the CourierInboxTheme reference.

Light and Dark Themes

Courier Inbox with a custom unread indicator style

Courier Inbox with a custom unread indicator style

<body>
  <courier-inbox id="inbox"></courier-inbox>

  <!-- Uncomment the line below to use the popup menu instead -->
  <!-- <courier-inbox-popup-menu id="inbox"></courier-inbox-popup-menu> -->

  <script type="module">
    import { Courier } from '@trycourier/courier-ui-inbox';

    // Courier authentication...

    const inbox = document.getElementById('inbox');
    const theme = {
      inbox: {
        header: {
          filters: {
            unreadIndicator: {
              backgroundColor: "#8B5CF6"
            }
          }
        },
        list: {
          item: {
            unreadIndicatorColor: "#8B5CF6"
          }
        }
      }
    };

    // Apply the theme
    inbox.setLightTheme(theme);
    inbox.setDarkTheme(theme);

    // Set the mode ('light', 'dark', or 'system')
    inbox.setMode('light');
  </script>
</body>
Customizing the popup menu's alignment, position, and dimensions

Customizing the popup menu's alignment, position, and dimensions

Customize the popup menu’s alignment with respect to its button. Available options for CourierInboxPopupAlignment are:
Vertical AlignmentOptions
Top"top-right", "top-center", "top-left"
Center"center-right", "center-center", "center-left"
Bottom"bottom-right", "bottom-center", "bottom-left"
<body>
  <div style="display: flex; justify-content: center; align-items: center; padding: 100px;">

    <courier-inbox-popup-menu
      popup-alignment="top-right"
      top="44px"
      right="44px"
      popup-width="340px"
      popup-height="400px">
    </courier-inbox-popup-menu>
  </div>
</body>

Custom Height for <courier-inbox>

<courier-inbox> has a default height of auto, meaning it will set its height based on its children. Give the inbox a fixed height by setting the height attribute.
<body>
  <courier-inbox height="50vh"></courier-inbox>
</body>

Custom Elements

List Items

Customize the inbox message list item by passing an HTML element to the setListItem method on the <courier-inbox> component.
Custom inbox message list item displaying the message object

Custom inbox message list item displaying the message object

<body>
  <courier-inbox id="inbox"></courier-inbox>

  <script type="module">
    // Reference the courier-inbox element
    const inbox = document.getElementById('inbox');

    // Set a custom list item
    inbox.setListItem(({ message, index }) => {
      const pre = document.createElement('pre');
      pre.style.padding = '24px';
      pre.style.borderBottom = '1px solid #e0e0e0';
      pre.style.margin = '0';
      pre.textContent = JSON.stringify(({ message, index }), null, 2);

      return pre;
    });
  </script>
</body>

Custom Header and Feed Type

Customize the inbox header by passing an HTML element to the setHeader method on the <courier-inbox> component. Call removeHeader to remove the header entirely. In the default header, the feed type is selectable. Call setFeedType to programmatically change the feed type between 'inbox' and 'archive'.
Custom inbox header

Custom inbox header

<body>
  <courier-inbox id="inbox"></courier-inbox>

  <script type="module">
    // Reference the courier-inbox element
    const inbox = document.getElementById('inbox');

    // Set a custom header
    inbox.setHeader(({ feedType, unreadCount, messageCount }) => {
      const headerDiv = document.createElement('div');
      headerDiv.style.background = 'red';
      headerDiv.style.fontSize = '24px';
      headerDiv.style.padding = '24px';
      headerDiv.style.width = '100%';
      headerDiv.textContent = feedType;
      return headerDiv;
    });

    // Uncomment the line below to remove the header
    // inbox.removeHeader();

    // Uncomment the line below to set the feed type to 'archive'
    // inbox.setFeedType('archive');
  </script>
</body>
Customize the inbox popup menu button by passing an HTML element to the setMenuButton method on the <courier-inbox-popup-menu> component.
Custom inbox popup menu button

Custom inbox popup menu button

<body>
  <div style="display: flex; justify-content: center; align-items: center; padding: 100px;">
    <courier-inbox-popup-menu id="inbox"></courier-inbox-popup-menu>
  </div>

  <script type="module">
    // Reference the courier-inbox element
    const inbox = document.getElementById('inbox');

    // Set a custom menu button
    inbox.setMenuButton(({ unreadCount }) => {
      const button = document.createElement('button');
      button.textContent = `Open the Inbox Popup. Unread message count: ${unreadCount}`;
      return button;
    });
  </script>
</body>

Loading, Empty, Error States and Custom Pagination

Customize the inbox loading, empty, error states and pagination item by passing an HTML element to the setLoadingState, setEmptyState, setErrorState, and setPaginationItem methods.
Subsequent pages of messages are loaded automatically when the user scrolls to the bottom of the inbox, so the pagination component may only be visible briefly.
Custom pagination state

Custom pagination state

<body>
  <courier-inbox id="inbox"></courier-inbox>

  <script type="module">
    // Reference the courier-inbox element
    const inbox = document.getElementById('inbox');

    // Set a custom loading state
    inbox.setLoadingState(props => {
      const loading = document.createElement('div');
      loading.style.padding = '24px';
      loading.style.background = 'red';
      loading.textContent = 'Custom Loading State';
      return loading;
    });

    // Set a custom empty state
    inbox.setEmptyState(props => {
      const empty = document.createElement('div');
      empty.style.padding = '24px';
      empty.style.background = 'green';
      empty.textContent = 'Custom Empty State';
      return empty;
    });

    // Set a custom error state
    inbox.setErrorState(props => {
      const error = document.createElement('div');
      error.style.padding = '24px';
      error.style.background = 'blue';
      error.textContent = 'Custom Error State';
      return error;
    });

    // Set a custom pagination state
    inbox.setPaginationItem(props => {
      const pagination = document.createElement('div');
      pagination.style.padding = '24px';
      pagination.style.background = '#f0f0f0';
      pagination.style.textAlign = 'center';
      pagination.textContent = '🔄 Loading the next page of messages';
      return pagination;
    });
  </script>
</body>