Custom Protocols
How to register and handle custom protocols.
Overview
MōBrowser provides the protocol object for registering custom URL scheme handlers. A custom protocol lets your application handle URLs such as app://local/home/ and decide what content to return.
import { protocol } from '@mobrowser/api'
Custom protocols are useful when you want to:
- Serve application resources through an app-owned scheme instead of
file://. - Generate HTML, JSON, or other content dynamically.
- Intercept resource loading for URLs your application controls.
- Stream local or generated content to a browser window.
Registering a protocol
Use protocol.handle(scheme, handler) to register a handler for a custom scheme. Pass only the bare scheme name, without : or ://.
import { protocol } from '@mobrowser/api';
protocol.handle('app', (request: Request) => {
const url = new URL(request.url)
if (url.pathname === '/home/') {
return {
statusCode: 200,
mimeType: 'text/html',
charset: 'utf-8',
data: '<html><head><title>Home</title></head><body>Home</body></html>',
}
}
return {
statusCode: 404,
mimeType: 'text/plain',
charset: 'utf-8',
data: 'Not found',
}
})
After the handler is registered, navigations and fetch requests that use the scheme are routed through your handler:
import { BrowserWindow } from '@mobrowser/api'
const win = new BrowserWindow()
win.browser.loadUrl('app://local/home/')
win.show()
Routing requests
The handler receives a Fetch API Request-like object. Use request.url with the standard URL API to route requests by path, host, or search parameters. For example, app://local/home/ has the host local and the pathname /home/.
protocol.handle('app', (request: Request) => {
const url = new URL(request.url)
if (url.pathname === '/api/config.json') {
return {
statusCode: 200,
mimeType: 'application/json',
charset: 'utf-8',
data: JSON.stringify({
theme: url.searchParams.get('theme') ?? 'system',
}),
}
}
return {
statusCode: 404,
mimeType: 'text/plain',
data: 'Not found',
}
})
Returning responses
A protocol handler can return a standard Response, a promise that resolves to a Response, or a plain ProtocolResponse object.
For HTML, JSON, and small payloads, a ProtocolResponse object is usually the simplest option:
return {
statusCode: 200,
mimeType: 'text/html',
charset: 'utf-8',
data: '<h1>Hello</h1>',
}
The data property can contain a string body, a byte buffer view, or a Node.js Readable stream. You can also return an error value to fail the request with a network error code.
Use a standard Response when it is more convenient to work with Fetch APIs:
protocol.handle('app', async (request: Request) => {
const url = new URL(request.url)
if (url.pathname === '/api/time.json') {
return Response.json({
now: new Date().toISOString(),
})
}
return new Response('Not found', {
status: 404,
headers: {
'content-type': 'text/plain; charset=utf-8',
},
})
})
Scheme rules
The scheme name must be a valid URL scheme token:
- It must start with an ASCII letter.
- It can contain ASCII letters, ASCII digits,
+,-, or.after the first character. - It must not include
:or://.
Scheme matching is case-insensitive. For example, registering Demo handles URLs that use demo:.
Important: MōBrowser does not allow overriding the built-in mobrowser scheme or standard browser schemes such as http, https, file, ftp, ws, and wss. Attempting to register an invalid or reserved scheme throws a TypeError.
Removing a handler
When you no longer want your application to handle a scheme just remove it:
protocol.removeHandler('app')