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
- 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 (sinceunterstützt)GET /api/v1/webhooks/chat/status--- optionaler Integrationsstatus
- Der Routenhandler leitet an Mailoo mit
X-API-Keyaus Server-Umgebung weiter (createChatSubmitHandler/createChatMessagesHandler/createChatStatusHandleraus@mailoo/chat/routes). OptionalsenderEmail/senderNameviaresolveSenderinjizieren, damit das Dashboard die Besucheridentität stattGuestanzeigt. - 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(getMailooChatWebSocketOriginaus@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 Berechtigungenchat-websocket-production{.interpreted-text role="doc"} --- Produktions-WebSocket-Hinweisenextjs-packages{.interpreted-text role="doc"} --- Paketübersicht