Skip to main content
Custom protocols let you handle URL schemes such as app:// directly inside Node.js without starting an HTTP server. The webview loads content by scheme name — app://localhost/index.html, for example — and your handler resolves every request. This is the recommended approach for serving local assets, and it is required on Windows when the page needs to use window.ipc.postMessage(), because IPC does not fire on file: URLs on that platform.

Registering a protocol

Call win.registerProtocol(scheme, handler) before win.createWebview(). The handler receives a standard Fetch Request and must return a Response (or a Promise<Response>).
You must call win.registerProtocol() before win.createWebview(). Registering a scheme after the webview is created has no effect on the existing webview instance.

Fetch API interface

The protocol handler receives a standard global Fetch API Request object and must return a standard Response. This means anything that works with the Fetch API — headers, status codes, streaming bodies — works here too.
If the handler throws or returns a rejected Promise, WebviewJS delivers a 500 text/plain response to the webview.

Routing with Hono

Because the handler receives a standard Request and must return a standard Response, you can pass the request directly to a Hono router. No HTTP server is required — Hono’s fetch method acts as the handler.
Any Fetch-compatible router works the same way.

Multiple protocols

Register as many schemes as you need before calling createWebview(). Each scheme gets its own independent handler.
Protocol registrations are fixed at the moment the webview is created. Calling registerProtocol() after createWebview() does not change the routing for an existing webview.

CORS and cache headers

Set response headers when the page makes cross-protocol fetch calls or when you want to control caching behavior.

Security

Never resolve a request path without verifying that it stays inside your intended asset directory. An attacker-controlled URL such as app://localhost/../../etc/passwd can escape your dist/ folder with a naive join().
Use relative() to detect path traversal attempts and return a 403 before touching the file system:

Legacy response format

As an alternative to returning a Response object, your handler can return a plain CustomProtocolResponse object. This format is supported for compatibility but the standard Response API is preferred.
Example usage:

  • IPC Messaging — send messages between the page and Node.js (requires custom protocol on Windows)
  • Webview API referenceWebviewOptions, registerProtocol, and webview creation