Contents

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')