Chat-Widget --- Next.js (`@mailoo/chat`)

Zuletzt aktualisiert: Oct 12, 2026Abschnitt: Integrationen

Stellen Sie Site-Chat von einem Next.js-Host bereit, ohne einen API-Schlüssel im Browser zu platzieren. Verwenden Sie @mailoo/chat für BFF-Routen und das optionale schwebende Widget. API-Vertrag und WebSocket-Hinweise: chat-widget{.interpreted-text role="doc"}, chat-websocket-production{.interpreted-text role="doc"}.

Ablauf

  1. Der Browser ruft nur Same-Origin-Routen Ihrer Next.js-App auf:
  • POST /api/v1/webhooks/chat/submit --- Body { "content": "...", "sessionPublicId?": "..." }
  • GET /api/v1/webhooks/chat/messages?sessionPublicId=... --- optionales Polling (since unterstützt)
  • GET /api/v1/webhooks/chat/status --- optionaler Integrationsstatus
  1. Der Routenhandler leitet an Mailoo mit X-API-Key aus Server-Umgebung weiter (createChatSubmitHandler / createChatMessagesHandler / createChatStatusHandler aus @mailoo/chat/routes). Optional senderEmail / senderName via resolveSender injizieren, damit das Dashboard die Besucheridentität statt Guest anzeigt.
  2. Optional: das Widget öffnet WebSocket zur API. Der Host wird zur Laufzeit auf dem Server aufgelöst (kein NEXT_PUBLIC_* für API-Origin):
  • Standardreihenfolge: MAILOO_CHAT_WS_ORIGIN → MAILOO_CHAT_INTEGRATION_API → API_BASE_URL (getMailooChatWebSocketOrigin aus @mailoo/chat)
  • Setzen Sie MAILOO_CHAT_WS_ORIGIN, wenn sich der browsersichtbare API-Hostname von der URL unterscheidet, die der Node-Server zum Aufrufen der API verwendet

Paketoberfläche

// app/api/v1/webhooks/chat/submit/route.ts
import { createChatSubmitHandler } from '@mailoo/chat/routes'

export const POST = createChatSubmitHandler({
  resolveSender: async () => {
    const session = await auth()
    return session?.user?.email
      ? { email: session.user.email, name: session.user.name ?? undefined }
      : null
  },
})
// app/api/v1/webhooks/chat/messages/route.ts
import { createChatMessagesHandler } from '@mailoo/chat/routes'
export const GET = createChatMessagesHandler()
// app/api/v1/webhooks/chat/status/route.ts
import { createChatStatusHandler } from '@mailoo/chat/routes'
export const GET = createChatStatusHandler()

Headless-Session (eigene UI) über @mailoo/chat/hooks:

import { useMailooChatSession } from '@mailoo/chat/hooks'

const chat = useMailooChatSession({
  apiOrigin,
  projectUid,
  integrationId,
  isAuthenticated,
  enabled: panelOpen,
})

Umgebungsvariablen (nur serverseitig)

MAILOO_CHAT_INTEGRATION_API=https://api.mailoo.app
MAILOO_CHAT_INTEGRATION_API_KEY=your-api-key-here
MAILOO_CHAT_INTEGRATION_PROJECT_UID=your-project-uid
MAILOO_CHAT_INTEGRATION_ID=your-jsbox-integration-id
MAILOO_CHAT_WELCOME_MESSAGE=Hello! How can we help?

# Optionaler öffentlicher API-Origin für ws/wss wenn abweichend von der serverseitigen API-URL


# MAILOO_CHAT_WS_ORIGIN=https://api.mailoo.app

Der API-Schlüssel benötigt chat.send-message (oder FULL). Kopieren Sie projectUid und integrationId aus den Dashboard-Connection & settings / dem Einbettungs-Snippet.

Schwebendes Widget

Importieren Sie das Shell-CSS (erforderlich, damit der FAB fixiert bleibt, auch wenn Tailwind @mailoo/chat nicht scannt). In diesem Monorepo löst PostCSS einen relativen Pfad zuverlässig auf:

@import '../../../../packages/chat/src/styles/widget.css';
/* veröffentlichtes Paket: @import '@mailoo/chat/styles'; */

Empfohlen (Standardpfad): Host-Config serverseitig auflösen und MailooSiteChatShell mounten. Marke, Themen, Position, Willkommen, Datenschutz und Operatoren kommen immer aus JSBOX config.chatWidget:

import { resolveMailooChatHostConfig } from '@mailoo/chat'
import { MailooSiteChatShell } from '@mailoo/chat/client'

const chat = await resolveMailooChatHostConfig({
  locale,
  isAuthenticated: Boolean(session?.user?.email),
})

{chat ? (
  <MailooSiteChatShell
    chat={chat}
    unavailableAction={{
      type: 'mailto',
      email: 'support@example.com',
    }}
  />
) : null}

resolveMailooChatHostConfig liefert null, wenn MAILOO_CHAT_* fehlt oder widget-config nicht geladen werden kann (HTTP-Fehler inkl. 429, Netzwerk, ungültige Antwort). Es wirft nie --- Seite bleibt HTTP 200, Chat-Shell weglassen. Rufen Sie openMailooSiteChat() aus jeder Client-Komponente auf, um das Panel zu öffnen.

Eigenes UI: übergeben Sie widgetConfig selbst an MailooSiteChatWidget (von fetchMailooChatWidgetConfig oder BFF GET …/webhooks/chat/widget-config). Der Launcher ist ein fixer FAB (Ecken oder middle-left / middle-right) mit Heroicons.

Chat nicht verfügbar / Rate-Limit

Das Paket klassifiziert Transport- und Servicefehler beim Senden und Abrufen von Nachrichten (keine rohen API-Texte in der UI):

  • rate_limited --- HTTP 429 (API-Key-Limit pro Minute)
  • unavailable --- Netzwerk, BFF 502/**503** oder andere 5xx

Validierungsfehler, geschlossene Sitzung (409) und fehlende Sitzung (404, wird automatisch geleert) bleiben normale Inline-Fehler --- sie öffnen nicht das Unavailable-Panel.

resolveMailooChatHostConfig liefert null (Chat nicht mounten), wenn widget-config nicht lädt. So bleibt die Host-Seite erreichbar; das Unavailable-Panel gilt nur nach dem Mounten des Widgets, wenn Send/Poll fehlschlägt.

Der Integrator wählt die Aktion (E-Mail, Support-Seite oder eigenes UI):

<MailooSiteChatShell
  chat={chat}
  unavailableAction={{ type: 'mailto', email: 'support@example.com' }}
  // oder: { type: 'link', href: '/support', label: 'Support kontaktieren' }
  // oder: renderUnavailable={({ fault, labels, retry }) => ...}
/>

Ohne unavailableAction sieht der Besucher Erklärung und Erneut versuchen (Fault löschen, Polling fortsetzen). Besser einen Kontaktpfad setzen. Headless: fault / onFault / retryAfterFault bei useMailooChatSession.

mailoo.app-Dogfood: Die Produktseite mountet MailooSiteChatShell in jedem Locale-Layout, wenn MAILOO_CHAT_* gesetzt ist, mit unavailableAction → mailto:support@mailoo.app. Die Karte Support → Live-Chat öffnet dasselbe Panel. Ohne diese Variablen bleibt die Karte „Demnächst", und der Launcher fehlt.

Dashboard-Chat-Konsole

Für JSBOX-Integrationen öffnet Open chat console die Operator-UI für diese Integration. Operatoren verwenden die Dashboard-Session; Besucher verwenden die öffentlichen Webhook- und WebSocket-Pfade oben.

Verwandt

  • chat-widget{.interpreted-text role="doc"} --- Öffentliche Webhooks und Berechtigungen
  • chat-websocket-production{.interpreted-text role="doc"} --- Produktions-WebSocket-Hinweise
  • nextjs-packages{.interpreted-text role="doc"} --- Paketübersicht