Skip to main content
The Vue SDK wraps Courier’s in-app components as Vue components, plus one composable that exposes the client behind them.
  • <CourierInbox />: inbox for displaying and managing messages
  • <CourierInboxPopupMenu />: popup menu version of the inbox
  • <CourierToast />: toast notifications for time-sensitive alerts
  • <CourierPreferences />: preference center for topic subscriptions and delivery
  • useCourier(): composable for custom UIs
See these components in the interactive Inbox demo. No setup required.

Installation

Available on GitHub and npm.
vue (>= 3.3) is a peer dependency.
Not using Vue? Use the instead. Its elements work in any JavaScript project.

Authentication

Courier authenticates with a JWT that your backend mints with your Courier API key, never in client code. is the full guide: the token flow, scope strings, reading auth state, signing out, and token refresh. Using the EU datacenter? See .

Quick start

Add the inbox component to your app. Courier components are normal Vue components. Import them and use them in your template.
Follow the for step-by-step guidance, including backend JWT generation.

Component reference

Each component’s props, theme, callbacks, and custom-render surface live with the feature. These links open on the Vue tab. Bind a render prop in kebab-case. Vue lowercases attribute names, so :render-list-item reaches the component and :renderListItem doesn’t. A custom render must also return a Vue node built with h(), not a string of markup. A string renders nothing. The CourierInboxTheme, CourierToastTheme, and CourierPreferencesTheme objects are the same on React, Vue, Angular, and the Web Components, so each is documented once: , , .

useCourier composable

The useCourier() composable gives you programmatic access to Courier. Use it to build custom UIs. It returns the same shape as the React hook, but auth, inbox, and toast are Vue shallowRefs. Access them with .value in <script setup>. They auto-unwrap in templates.

When to use the composable vs components

  • Components (<CourierInbox />, <CourierToast />): quick integration with the default UI
  • Composable (useCourier()): custom UIs, programmatic control, state management
  • Both together: the composable manages state, components render

Composable return value

Call inbox.value.listenForUpdates() after authentication to open the realtime connection. Without it, the inbox loads once from the initial fetch and doesn’t update again. Complete example: authentication, inbox setup, real-time updates, and displaying messages. Templates auto-unwrap the refs (inbox.totalUnreadCount, inbox.feeds[...]):
Every method and reactive value the inbox slice exposes is in . Read them off inbox.value in <script setup>, and off inbox in a template.

Advanced

Server-side rendering

Courier Inbox and Toast render client-side only. They mount in onMounted, which never runs during SSR. They work with Nuxt and other SSR setups without extra configuration, rendering once on the client.

Troubleshooting

Call inbox.value.listenForUpdates() after authentication. It opens the WebSocket connection required for real-time updates.
Possible causes:
  1. Not authenticated: call signIn()
  2. Feeds not registered: call registerFeeds() before load()
  3. Network errors: check inbox.value.error for details
  4. JWT expired: generate a new token
  • Invalid JWT: generate the JWT correctly on your backend
  • Expired JWT: JWTs expire. Generate a new one
  • Missing scopes: include inbox:read:messages and inbox:write:events in the JWT
  • Wrong user ID: the userId must match the user the JWT was issued for
Custom render props must return a Vue node built with h() (imported from vue), not a raw string of markup. Bind the render prop with :render-list-item="..." (kebab-case) on the component.
Import types directly from the package:

Best practices

  • JWT security: always generate JWTs server-side. Cache on the client, refresh before expiration (standard: '1d'), and include only the scopes you need.
  • Performance: canUseCache: true (default) serves cached data. Set a suitable setPaginationLimit(). The composable’s shallowRefs update on their own, so avoid unnecessary re-renders.
  • Testing: mock useCourier() in tests to return test data:

TypeScript types