• Public
  • Public/Protected
  • All

Module webview

Webview Platform

Serve webviews that integrated with the chat platforms.

  • Host a front-end app powered by Next.js.
  • Automatically log in users with the chat platform account.
  • Mutually communicate to the server with WebSocket.

This package combines three modules: @machinat/auth, @machinat/next and @machinat/websocket. You can use them separatedly if you don't need them all.


npm install react react-dom next @machinat/core @machinat/http @machinat/webview
# or with yarn
yarn add react react-dom next @machinat/core @machinat/http @machinat/webview


Check the Embedded Webview document and the API references.



Assume you have the Next.js app directory at ./webview, set up webview platform like this:

// src/app.js
import Machinat from '@machinat/core';
import Http from '@machinat/http';
import Webview from '@machinat/webview';
import Messenger from '@machinat/messenger';
import MessengerWebviewAuth from '@machinat/messenger/webview';
import nextConfigs from '../webview/next.config.js';

const DEV = NODE_ENV !== 'production';

const app = Machinat.createApp({
modules: [
Http.initModule({/* ... */}),
platforms: [
Messenger.initModule({/* ... */}),
webviewHost: DOMAIN,
webviewPath: '/webview', // have to match `basePath` in next.config.js
authPlatforms: [
// auth providers from platforms
nextServerOptions: {
dev: DEV, // use dev mode or not
dir: './webview', // the front-end app dir
conf: nextConfigs, // import configs from next.config.js

app.onEvent(async ({ event, bot }) => {
if (event.platform === 'webview' && event.type === 'connect') {
await bot.send(event.channel, {
type: 'hello',
payload: 'hello from server',

You can create the front-end app with npx create-next-app if you don't have one.


Set up the Next.js app like this:

// webview/next.config.js
module.exports = {
distDir: '../dist', // the path of built front-end codes
basePath: '/webview', // have to match `webviewPath` on back-end
publicRuntimeConfig: {
// export settings to front-end if needed
messengerAppId: process.env.MESSENGER_APP_ID,

Then you can use WebviewClient in the front-end pages like this:

// webview/pages/index.js
import { useEffect } from 'react';
import getConfig from 'next/config';
import WebviewClient from '@machinat/webview/client';
import MessengerWebviewAuth from '@machinat/messenger/webview/client';

// get settings if needed
const { publicRuntimeConfig } = getConfig();
// to activate publicRuntimeConfig
export const getServerSideProps = () => ({ props: {} });

const client = new WebviewClient({
// prevent connecting in the back-end while server rendering
mockupMode: typeof window === 'undefined',
// auth providers from platforms
authPlatforms: [
new MessengerWebviewAuth({
appId: publicRuntimeConfig.messengerAppId,

export default function Home() {
const greetingMsg = useEventReducer(
(msg, event) => event.type === 'hello' ? event.payload : msg,
() => {
client.send({ type: 'hello', payload: 'hello from webview' });
return <h1>{greetingMsg} || 'connecting...'</h1>




Re-exports ConnectEventValue
Re-exports ConnectionEventValue
Re-exports DisconnectEventValue
Re-exports EventInput
Re-exports EventValue
AnyClientAuthenticator: WebviewClientAuthenticator<unknown, unknown, AnyAuthContext>
NoneAuthenticator: NoneServerAuthenticator
WebviewComponent: NativeComponent<unknown, UnitSegment<EventInput>>
WebviewConfigs<Authenticator, Value>: { authApiPath?: string; authPlatforms?: ServiceProvider<AnyServerAuthenticator, unknown[]>[]; authSecret: string; basicAuth?: { appIconUrl?: string; appName?: string; codeMessageComponent?: CodeMessageComponent; loginDuration?: number; maxLoginAttempt?: number; mode?: "loose" | "strict"; verifyCodeDigits?: number }; cookieDomain?: string; cookiePath?: string; cookieSameSite?: "strict" | "lax" | "none"; dataCookieMaxAge?: number; dispatchMiddlewares?: MaybeContainer<WebviewDispatchMiddleware>[]; eventMiddlewares?: MaybeContainer<WebviewEventMiddleware<Authenticator, Value>>[]; heartbeatInterval?: number; nextServerOptions?: NextServerOptions; noNextServer?: boolean; noPrepareNext?: boolean; refreshDuration?: number; secure?: boolean; tokenLifetime?: number; webSocketPath?: string; webviewHost: string; webviewPath?: string }

Type parameters

Type declaration

  • Optional authApiPath?: string

    Route path to the auth api. Default to "/auth"

  • Optional authPlatforms?: ServiceProvider<AnyServerAuthenticator, unknown[]>[]

    Auth providers from the platforms

  • authSecret: string

    The secret for signing auth token

  • Optional basicAuth?: { appIconUrl?: string; appName?: string; codeMessageComponent?: CodeMessageComponent; loginDuration?: number; maxLoginAttempt?: number; mode?: "loose" | "strict"; verifyCodeDigits?: number }

    Initiate basic auth flow service with the options

    • Optional appIconUrl?: string

      The app image to show while login using basic auth flow

    • Optional appName?: string

      The app name to show while login using basic auth flow

    • Optional codeMessageComponent?: CodeMessageComponent

      The customized component to render code message

    • Optional loginDuration?: number

      Login session duration in seconds. Default to 10 min

    • Optional maxLoginAttempt?: number

      Max time to verify login code. Default to 5

    • Optional mode?: "loose" | "strict"

      The user needs to enter a verify code in strict mode. Default to strict

    • Optional verifyCodeDigits?: number

      The digits of the verify code number. Default to 6

  • Optional cookieDomain?: string

    The domain scope of the auth cookies

  • Optional cookiePath?: string

    The path scope of the auth cookies. Default to '/'

  • Optional cookieSameSite?: "strict" | "lax" | "none"

    The SameSite attribute of the auth cookies. Default to strict

  • Optional dataCookieMaxAge?: number

    The MaxAge of the data cookies in seconds. Default to 5 minute

  • Optional dispatchMiddlewares?: MaybeContainer<WebviewDispatchMiddleware>[]
  • Optional eventMiddlewares?: MaybeContainer<WebviewEventMiddleware<Authenticator, Value>>[]
  • Optional heartbeatInterval?: number
  • Optional nextServerOptions?: NextServerOptions

    Options for nextjs server.

  • Optional noNextServer?: boolean

    Set to true for not running NextJS server.

  • Optional noPrepareNext?: boolean

    Set to true for not running #prepare() of NextJS server.

  • Optional refreshDuration?: number

    The duration a token can be refreshed in seconds. Default to Infinity

  • Optional secure?: boolean

    Force using HTTPS if set to true

  • Optional tokenLifetime?: number

    The lifetime of the token in seconds. Default to an hour

  • Optional webSocketPath?: string

    Route path to the web socket server. Default to "/websocket"

  • webviewHost: string

    Host of the webview.

  • Optional webviewPath?: string

    Route path to the webview pages, default to "/".

WebviewDispatchChannel: WebviewTopicChannel | WebviewUserChannel | WebviewConnection
WebviewEvent<Value, User>: Value & { channel: WebviewConnection; platform: "webview"; user: User }

Type parameters

WebviewEventContext<Authenticator, Value>: { bot: BotP; event: WebviewEvent<Value, UserOfAuthenticator<Authenticator>>; metadata: WebviewMetadata<ContextOfAuthenticator<Authenticator>>; platform: "webview"; reply: any }

Type parameters

Type declaration

WebviewEventMiddleware<Authenticator, Value>: EventMiddleware<WebviewEventContext<Authenticator, Value>, null>

Type parameters

WebviewMetadata<Context>: Omit<WebSocketMetadata<Context>, "connection"> & { connection: WebviewConnection }

Type parameters

WebviewPlatformUtilities<Authenticator>: PlatformUtilities<WebviewEventContext<Authenticator, EventValue>, null, WebSocketJob, WebviewDispatchFrame, WebSocketResult>

Type parameters

NoneAuthenticator: ServiceProvider<NoneServerAuthenticator, [unknown]> & typeof NoneServerAuthenticator = ...

Generated using TypeDoc