Skip to main content
Nook supports browser extensions using WebKit’s native WKWebExtension API, providing compatibility with Chrome/Firefox extensions while leveraging macOS’s built-in extension framework.

System requirements

Extension support requires:
  • macOS 15.5+ (for content script world isolation)
  • macOS 15.4+ (basic extension support)
Nook automatically detects OS compatibility via ExtensionUtils.isExtensionSupportAvailable.
// Nook/Utils/ExtensionUtils.swift:14
static var isExtensionSupportAvailable: Bool {
    if #available(iOS 18.5, macOS 15.5, *) { return true }
    return false
}

Manifest versions

Nook supports both Manifest V2 and V3 extensions:

Manifest V3

Preferred format with service worker backgrounds

Manifest V2

Legacy format with automatic scripting permission injection

Manifest V3 requirements

For MV3 extensions, your manifest must include a service worker:
manifest.json
{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0.0",
  "background": {
    "service_worker": "background.js"
  }
}
Nook validates this during installation via validateMV3Requirements().

Creating your first extension

1

Create the manifest

Start with a basic manifest.json file:
manifest.json
{
  "manifest_version": 3,
  "name": "Hello Nook",
  "version": "1.0.0",
  "description": "My first Nook extension",
  "permissions": ["activeTab"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icon16.png",
      "48": "icon48.png",
      "128": "icon128.png"
    }
  }
}
Required fields: manifest_version, name, version. Validation happens in ExtensionUtils.validateManifest().
2

Create the popup HTML

popup.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <style>
      body { width: 300px; padding: 16px; }
      h1 { font-size: 18px; margin: 0 0 12px 0; }
    </style>
  </head>
  <body>
    <h1>Hello from Nook!</h1>
    <button id="test">Click me</button>
    <script src="popup.js"></script>
  </body>
</html>
3

Add popup JavaScript

popup.js
document.getElementById('test').addEventListener('click', async () => {
  const tabs = await browser.tabs.query({ active: true, currentWindow: true });
  console.log('Active tab:', tabs[0]);
});
Use browser namespace (Firefox style) or chrome namespace (Chrome style). Nook supports both.
4

Package your extension

Nook supports multiple installation formats:
zip -r my-extension.zip manifest.json popup.html popup.js icon*.png

Installation flow

When you install an extension, Nook performs these steps automatically:
Extension installation code is in ExtensionManager.swift:1467 (performInstallation).

Installation locations

  • Extension packages: ~/Library/Application Support/Nook/Extensions/{extensionId}/
  • Native messaging hosts: ~/Library/Application Support/Nook/NativeMessagingHosts/

Permission model

Nook uses an install-time permission grant model (Chrome-style):
ALL permissions and host_permissions are automatically granted at install time. Users don’t see permission prompts during installation.
// ExtensionManager.swift:1536
for p in webExtension.requestedPermissions {
    extensionContext.setPermissionStatus(.grantedExplicitly, for: p)
}
for m in webExtension.allRequestedMatchPatterns {
    extensionContext.setPermissionStatus(.grantedExplicitly, for: m)
}

Runtime permissions

For optional_permissions, users see a permission dialog when your extension calls browser.permissions.request():
background.js
// Request optional permission at runtime
const granted = await browser.permissions.request({
  permissions: ['bookmarks'],
  origins: ['https://example.com/*']
});

Background service workers

Nook loads background service workers immediately after installation:
background.js
// MV3 service worker
browser.runtime.onInstalled.addListener(() => {
  console.log('Extension installed!');
});

browser.action.onClicked.addListener(async (tab) => {
  await browser.tabs.sendMessage(tab.id, { action: 'toggle' });
});
Background health is automatically probed at +3s and +8s via probeBackgroundHealth() to detect initialization issues.

Next steps

Manifest reference

Deep dive into manifest structure and WebKit-specific patching

API reference

Explore available browser APIs and native messaging

Debugging

Learn debugging tools and diagnostic utilities

Build docs developers (and LLMs) love