NW.js is an application runtime that lets you build native desktop applications for Windows, macOS, and Linux using ordinary web technologies — HTML, CSS, and JavaScript — while giving your page direct access to the full Node.js API and the entire npm ecosystem. It is built on the same engines that power Google Chrome (Chromium) and the Node.js server runtime, fused so that your DOM scripts and your Node modules share a single JavaScript heap.
This guide shows you how to write, run, debug, package, and ship an NW.js application. It is organized around the journey of building a real app: a five-minute Hello World, then the manifest that configures your app, then the nw.* desktop APIs, then advanced topics and a complete reference. Written from the NW.js source code at the version below.
Note
NW.js was originally called node-webkit. You will still see that name in older blog posts, the
node-webkitnpm distribution channels, and theprocess.versions['node-webkit']field. They refer to the same project.
1. Quick Start
1.1 What you need
To develop an NW.js app you need exactly two things:
- A copy of the NW.js binary for your platform (download below).
- A folder containing a
package.jsonmanifest and at least one HTML or JavaScript file.
You do not need a compiler, a build toolchain, or a bundler to get started. NW.js runs your source files directly.
Tip
While developing, always use the SDK build flavor. It includes the DevTools and developer tools (
nwjc,chromedriver). Switch to the Normal build only for production, to ship a smaller package. See Build Flavors.
1.2 Get NW.js
Download the latest binaries from the official site https://nwjs.io, or grab a specific version directly from the download server https://dl.nwjs.io.
| Platform | Package |
|---|---|
| Windows | nwjs-vX.Y.Z-win-x64.zip (64-bit) / nwjs-vX.Y.Z-win-ia32.zip (32-bit) |
| macOS 10.10+ | nwjs-vX.Y.Z-osx-arm64.zip |
| Linux | nwjs-vX.Y.Z-linux-x64.tar.gz / nwjs-vX.Y.Z-linux-arm64.tar.gz |
Nightly builds from the git tip are available at https://dl.nwjs.io/live-build/. Previous versions and the version-mapping file are listed at https://nwjs.io/versions.json.
Note
Each NW.js release pins a specific Node.js and Chromium version. Read the release notes for the version you download so you know which Node and Chromium (and therefore which Web Platform and Node APIs) you are targeting.
1.3 Hello World in three steps
Step 1 — Create package.json:
{
"name": "helloworld",
"main": "index.html"
}
package.json is your app's manifest. The two required fields are main (the first page or script to load) and name (a globally unique app name — see Section 3).
Step 2 — Create index.html:
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <script>document.write(process.version)</script>.
</body>
</html>
Step 3 — Run your app. Point the nw binary at the folder containing package.json:
Windows
cd \path\to\your\app
\path\to\nw.exe .
You can also drag the folder containing package.json onto nw.exe.
macOS
cd /path/to/your/app
/path/to/nwjs.app/Contents/MacOS/nwjs .
Linux
cd /path/to/your/app
/path/to/nw .
Expected result — a native window opens showing your heading and the embedded Node.js version:
Hello World!
We are using Node.js v26.1.0.
That you can print process.version from inside an HTML page is the whole point of NW.js: Node.js is live inside the DOM.
1.4 Your first desktop feature: a native context menu
This example creates a real OS-native right-click menu — something a plain web page cannot do. Replace index.html with:
<!DOCTYPE html>
<html>
<head><title>Context Menu</title></head>
<body>
<p>Right-click here to show the native context menu.</p>
<script>
// Create an empty context menu
var menu = new nw.Menu();
// Add some items
menu.append(new nw.MenuItem({
label: 'Item A',
click: function () { alert('You clicked "Item A"'); }
}));
menu.append(new nw.MenuItem({ label: 'Item B' }));
menu.append(new nw.MenuItem({ type: 'separator' }));
menu.append(new nw.MenuItem({ label: 'Item C' }));
// Hook the DOM "contextmenu" event and popup the native menu
document.body.addEventListener('contextmenu', function (ev) {
ev.preventDefault(); // suppress the default web menu
menu.popup(ev.x, ev.y); // show the native menu at the cursor
return false;
}, false);
</script>
</body>
</html>
All NW.js APIs live on the global nw object and can be used directly from any script in your app. See Section 4 for the full API set.
Tip
The legacy way to load the APIs,
require('nw.gui'), still works and returns the samenwobject. New code should just use the globalnw.
1.5 Calling Node.js from the page
Because Node.js is built in, you can require() core modules and npm packages straight from your page:
<script>
// Query the OS platform using Node's `os` module
var os = require('os');
document.write('You are running on ', os.platform());
</script>
Expected output (on a 64-bit Windows machine, for example):
You are running on win32
You can install and use any npm package the same way you would in a Node project — run npm install in your app folder, then require() the package.
Important
Native (compiled) Node modules built by a plain
npm installare not ABI-compatible with NW.js and must be rebuilt against NW.js headers. See Section 7.3.
2. Installation & Project Layout
2.1 Anatomy of an NW.js project
A minimal project is just a folder:
my-app/
├── package.json ← the manifest (required)
├── index.html ← your "main" entry (HTML or JS)
├── js/
│ └── app.js
├── css/
│ └── style.css
└── node_modules/ ← npm dependencies (optional)
NW.js does not impose any directory structure beyond requiring a package.json at the app root. Paths inside the manifest (such as main and window icon) are resolved relative to the folder that contains package.json.
2.2 HTML entry vs. JavaScript entry
The main field can point at either an HTML file or a JavaScript file, and the choice changes how your app starts:
main value |
Startup behavior |
|---|---|
"index.html" |
NW.js opens a window and loads the HTML page immediately. |
"main.js" |
The JS file runs in the background page on start; no window opens automatically. You open windows yourself with nw.Window.open(). |
The JS-entry pattern is useful when you want to do initialization (read config, check a license, choose a window size) before showing anything:
// main.js — runs in the background page, no window yet
// ...do initialization...
nw.Window.open('index.html', {}, function (win) {
// window is ready
});
Note
NW.js apps always have an invisible background page that lives for the entire lifetime of the app. This is where long-lived objects (menus, trays, global state) should live. See Section 5.1.
2.3 The current working directory
On startup NW.js changes the process current directory to the folder where your package files reside. Use nw.App.startPath to recover the directory the app was launched from (see Section 4.2).
3. The Manifest (package.json)
The manifest controls everything about how your app launches: its identity, which runtime features are enabled, and how the main window looks. It is a standard JSON file.
3.1 Minimal manifest
{
"main": "index.html",
"name": "nw-demo"
}
3.2 Required fields
| Field | Type | Description |
|---|---|---|
main |
String | The HTML page to open or JS file to execute on start. A URL, filename, or path relative to package.json. |
name |
String | A globally unique, lowercase, alphanumeric name (., _, - allowed; no spaces). NW.js stores your app's data under a directory named after this. |
Caution
namemust be globally unique because NW.js derives your app's per-user data directory from it (seeApp.dataPath). Two apps sharing anamewill share cookies, localStorage, and caches.
3.3 Feature-control fields
These top-level fields turn runtime features on or off and shape how the app behaves.
| Field | Type | Description |
|---|---|---|
product_string |
String | Renames the per-process Helper application on macOS (shown as <product_string> Helper). |
nodejs |
Boolean | Set to false to disable Node.js support entirely. |
node-main |
String | Path to a Node.js script executed on startup in the Node context, before the first DOM window loads. Node CLI args may precede the path in the string. |
domain |
String | Sets the host used in the chrome-extension:// URL for your app, so your app and a same-domain website share cookies. |
bg-script |
String | A background script executed in the background page at app start. |
user-agent |
String | Overrides the HTTP User-Agent for requests made by the app. Supports placeholders (table below). |
node-remote |
Array | String | Enables calling Node from remote pages. Value is a list of Chrome match patterns (e.g. "<all_urls>", "http://*.example.com/*"). |
chromium-args |
String | Extra Chromium command-line switches applied every launch. Multiple switches separated by spaces; group flags in single quotes. Prefixed by the value of the NW_PRE_ARGS env var. |
js-flags |
String | Flags passed to the V8 JavaScript engine (e.g. "--harmony_proxies"). |
crash_report_url |
String | URL of a breakpad/crashpad crash-report server; minidumps are POSTed there on crash. |
inject_js_start |
String | Local JS file injected after CSS but before any DOM is built or any other script runs. |
inject_js_end |
String | Local JS file injected after the document loads, before onload fires. |
additional_trust_anchors |
Array | PEM-encoded certificates added as extra trusted roots (for self-signed / custom-CA servers). |
dom_storage_quota |
Integer | DOM-storage quota in MB. Suggestion: set to double the value you actually want. |
single-instance |
Boolean | true. |
no-edit-menu |
Boolean |
user-agent placeholders:
| Placeholder | Replaced with |
|---|---|
%name |
the manifest name |
%ver |
the manifest version |
%nwver |
the NW.js version |
%webkit_ver |
the Blink engine version |
%chromium_ver |
the Chromium version |
%osinfo |
OS and CPU info, as in a normal browser UA |
Note
node-remoteis the single most security-sensitive manifest field. Granting Node access to a remote origin gives that site full read/write access to the user's machine. Only ever point it at origins you fully control. See Section 6, Security.
3.4 The window object
The window field is an object controlling the main window's appearance and behavior. Most subfields are inherited by child windows opened via window.open() or <a target="_blank"> — except fullscreen, kiosk, position, resizable, and show, which reset to defaults for opened windows. Every subfield can also be overridden per-window through the new-win-policy event.
window subfield |
Type | Description |
|---|---|---|
id |
String | Identifier used to remember and restore the window's size and position across launches. |
title |
String | Default window title (useful while the app is starting). |
width / height |
Integer | Initial inner width / height. |
min_width / min_height |
Integer | Minimum inner size. |
max_width / max_height |
Integer | Maximum inner size. |
position |
String | null, center, or mouse — where the window opens. |
resizable |
Boolean | Whether the user can resize the window. |
always_on_top |
Boolean | Keep window above all others. |
visible_on_all_workspaces |
Boolean | (Mac & Linux) Show on every workspace. |
fullscreen |
Boolean | Start fullscreen. |
kiosk |
Boolean | Start in kiosk mode (fullscreen + locked down). |
show_in_taskbar |
Boolean | Show in the taskbar / dock. Default true. |
frame |
Boolean | Set false for a frameless window. |
show |
Boolean | Set false to start hidden. |
transparent |
Boolean | Enable a transparent window. Default false. |
icon |
String | Path to the window icon. |
as_desktop |
Boolean | (Linux/X11) Show as a desktop-background window. |
toolbar |
Boolean | false. |
Frameless drag regions — a frameless window has no title bar to drag, so designate draggable areas with CSS:
.titlebar { -webkit-app-region: drag; }
.titlebar button { -webkit-app-region: no-drag; }
Warning
Do not combine
frame: falsewithfullscreen: true: a frameless fullscreen window prevents the mouse from being captured at the very edges of the screen. Likewise, avoidresizable: false+frame: trueon macOS, where the user can still trigger fullscreen.
3.5 The webkit object
webkit subfield |
Type | Description |
|---|---|---|
plugin |
Boolean | Load external browser plugins (e.g. Flash). Default true. |
double_tap_to_zoom_enabled |
Boolean | (Mac) Two-finger double-tap zoom. Default false. |
3.6 The webview object (partitions)
To let a <webview> load local files or trusted resources, declare a partition in the manifest and add partition="trusted" to the tag (see Section 4.10):
{
"name": "nw-demo",
"main": "index.html",
"webview": {
"partitions": [
{ "name": "trusted", "accessible_resources": ["<all_urls>"] }
]
}
}
3.7 A realistic manifest
{
"name": "my-editor",
"main": "index.html",
"version": "1.2.0",
"user-agent": "MyEditor/%ver (NW.js %nwver)",
"node-remote": [],
"chromium-args": "--disable-accelerated-video",
"js-flags": "--expose-gc",
"dom_storage_quota": 200,
"window": {
"id": "main",
"title": "My Editor",
"icon": "assets/icon.png",
"width": 1100,
"height": 720,
"min_width": 640,
"min_height": 480,
"position": "center",
"frame": true,
"show": false
}
}
Tip
Setting
"show": falseand then callingwin.show()once the page has loaded eliminates the white "flash of unstyled window" that users see while your app boots.
4. The nw.* Desktop APIs
All NW.js APIs are exposed on the global nw object. This section is the practical reference for everything you can do — windows, menus, the system tray, the clipboard, global hotkeys, the screen, and the shell.
Note
Several API objects (
Window,MenuItem,Shortcut,Screen) are EventEmitters. You listen with.on('eventname', handler)and stop with.removeListener()/.removeAllListeners(), exactly as in Node.
4.1 API at a glance
| Object | Purpose | Construct / access |
|---|---|---|
nw.App |
App lifecycle, args, data paths, proxy, global hotkeys | static object |
nw.Window |
Native window control and events | nw.Window.get() / .open() |
nw.Menu |
Menubars and context menus | new nw.Menu() |
nw.MenuItem |
An item inside a menu | new nw.MenuItem({...}) |
nw.Tray |
System tray / status-bar icon | new nw.Tray({...}) |
nw.Shell |
Open files/URLs in the desktop's default apps | static object |
nw.Clipboard |
Read/write the system clipboard | nw.Clipboard.get() |
nw.Shortcut |
System-wide global hotkeys | new nw.Shortcut({...}) |
nw.Screen |
Display geometry and screen-capture sources | nw.Screen.Init() |
4.2 App — application lifecycle and environment
Properties
| Member | Returns | Description |
|---|---|---|
App.argv |
Array | Command-line args with NW.js-internal flags filtered out. |
App.fullArgv |
Array | All args, including NW.js's own (--nwapp, --remote-debugging-port, …). |
App.filteredArgv |
Array | The regex patterns used to filter argv (e.g. /^--url=/, /^--nwapp=/). |
App.startPath |
String | The directory the app was started from. |
App.dataPath |
String | The app's per-user data directory (see below). |
App.manifest |
Object | The parsed package.json as a JS object. |
App.dataPath resolves per-platform, where <name> is the manifest name:
| Platform | Path |
|---|---|
| Windows | %LOCALAPPDATA%/<name> |
| Linux | ~/.config/<name> |
| macOS | ~/Library/Application Support/<name>/Default |
Methods
| Method | Description |
|---|---|
App.quit() |
Quit immediately. Does not send close events — no chance to save. |
App.closeAllWindows() |
Send close to every window; quit after all shut down cleanly. |
App.clearCache() |
Clear the in-memory and on-disk HTTP cache (synchronous). |
App.clearAppCache(manifest_url) |
Mark an AppCache group obsolete (synchronous). |
App.getProxyForURL(url) |
Return the proxy for a URL in PAC format (e.g. "PROXY localhost:8080"). |
App.setProxyConfig(config, pac_url) |
Set proxy rules or a PAC URL for all network requests. |
App.addOriginAccessWhitelistEntry(src, proto, host, allowSub) |
Allow a cross-origin access path (e.g. let github.com redirect into your app). |
App.removeOriginAccessWhitelistEntry(...) |
Reverse the above with identical arguments. |
App.registerGlobalHotKey(shortcut) |
Register a system-wide hotkey (see Shortcut). |
App.unregisterGlobalHotKey(shortcut) |
Unregister a hotkey. |
App.crashBrowser() / App.crashRenderer() |
Deliberately crash the browser/renderer process (to test crash dumps). |
App.enableComponent(component, cb) |
Experimental. Enable a component; only WIDEVINE is supported. |
App.updateComponent(component, cb) |
Experimental. Install/update a component. |
Events
| Event | Fires when |
|---|---|
open(args) |
The user opens a file with your app, or a second instance is launched (its full command line arrives here). |
reopen |
(Mac) The user clicks the dock icon of an already-running app. |
Setting a proxy, for example:
nw.App.setProxyConfig('http=foopy:80;ftp=foopy2', '');
nw.App.getProxyForURL('http://example.com'); // → "PROXY foopy:80"
Tip
Because
single-instanceis always on, handle theopenevent to react when a user tries to launch your app a second time (e.g. focus the existing window and open the file they double-clicked).
4.3 Window — controlling the native window
Get the current window, or open a new one:
var win = nw.Window.get(); // current window
nw.Window.open('popup.html', {}, function (newWin) { /* ... */ });
| Static method | Description |
|---|---|
Window.get([dom_window]) |
Return the native Window (current, or for a given DOM window — always the topmost, even for an iframe). |
Window.getAll(callback) |
Callback receives an array of all Window objects (since 0.42.6). |
Window.open(url, [options], [callback]) |
Open a new window loading url. options accepts all window subfields plus the extras below. |
Extra Window.open() options: new_instance (open in a separate render process), mixed_context (merge Node + DOM context; requires new_instance), inject_js_start, inject_js_end, id, and focus.
Note
Wait for the new window's
loadedevent before touching its components. The opened window is not focused by default — passfocus: trueif you need it focused.
Geometry & state — properties
| Property | Description |
|---|---|
win.window |
The corresponding DOM window object. |
win.x / win.y |
Get/set the window's screen position. |
win.width / win.height |
Get/set size (including frame). |
win.title |
Get/set the title. |
win.menu |
Get/set the menubar (a Menu of type menubar; set null to remove). |
win.zoomLevel |
Get/set zoom: 0 normal, positive zoom-in, negative zoom-out. |
win.isAlwaysOnTop / win.isFullscreen / win.isTransparent / win.isKioskMode |
State queries. |
win.cookies.* |
Cookie API (get, getAll, set, remove, onChanged), mirroring the Chrome cookies API. |
Movement, sizing, visibility — methods
| Method | Description |
|---|---|
win.moveTo(x, y) / win.moveBy(dx, dy) |
Absolute / relative move. |
win.resizeTo(w, h) / win.resizeBy(dw, dh) |
Absolute / relative resize (inner size). |
win.setInnerWidth(w) / win.setInnerHeight(h) |
Set inner dimensions. |
win.setPosition(pos) |
Move to center (supported on all platforms), null, or mouse. |
win.setMinimumSize(w, h) / win.setMaximumSize(w, h) |
Size constraints. |
win.setResizable(bool) |
Toggle resizability. |
win.setAlwaysOnTop(bool) |
Toggle always-on-top. |
win.setVisibleOnAllWorkspaces(bool) / win.canSetVisibleOnAllWorkspaces() |
(Mac/Linux) Multi-workspace visibility. |
win.setShowInTaskbar(bool) |
Show/hide in taskbar or dock. |
win.show([bool]) / win.hide() |
Show or hide. show(false) ≡ hide(). |
win.focus() / win.blur() |
Focus / unfocus. |
win.minimize() / win.maximize() / win.restore() |
Window state. |
win.enterFullscreen() / win.leaveFullscreen() / win.toggleFullscreen() |
Fullscreen control. |
win.enterKioskMode() / win.leaveKioskMode() / win.toggleKioskMode() |
Kiosk control. |
win.reload() / win.reloadIgnoringCache() / win.reloadDev() |
Reload variants (reloadDev starts a fresh renderer). |
win.close([force]) |
Close; if listening to close, you must call win.close(true) to really close. |
win.setShadow(bool) |
(Mac) Toggle native window shadow (for frameless/transparent windows). |
win.requestAttention(flag) |
Flash the taskbar entry. Boolean to start/stop, or integer flash count. |
DevTools (SDK build only)
| Method | Description |
|---|---|
win.showDevTools([iframe], [callback]) |
Open DevTools (optionally jailed to one <iframe>); callback gets the DevTools Window. |
win.closeDevTools() |
Close DevTools. |
win.isDevToolsOpen() |
Query DevTools status. |
Capture & printing
win.capturePage(callback, [config]) captures the visible area; config.format is "png" or "jpeg" (default jpeg) and config.datatype is "raw", "buffer", or "datauri" (default datauri):
win.capturePage(function (buffer) {
// do something with the PNG buffer
}, { format: 'png', datatype: 'buffer' });
win.captureScreenshot(options, [callback]) can capture the whole page beyond the visible area; omit the callback to get a Promise. Options: fullSize, format, quality, and a clip region (x, y, width, height, scale).
win.getPrinters(callback) enumerates printers; win.print(options) prints (or prints to PDF). Key print options:
| Option | Description |
|---|---|
autoprint |
Print without user interaction (default true). |
silent |
Hide the print-preview dialog (default false). |
printer |
Device name from getPrinters(). Omit when printing to PDF. |
pdf_path |
Output path when printing to PDF. |
landscape, copies, scaleFactor, shouldPrintBackgrounds |
Standard print settings. |
headerFooterEnabled, headerString, footerString |
Header/footer controls. |
marginsType |
0 default, 1 none, 2 minimum, 3 custom (marginsCustom). |
mediaSize |
Paper-size spec object. |
Note
When passing no options, call
win.print({})(an empty object), notwin.print().
Executing code & protected binaries
| Method | Description |
|---|---|
win.eval(frame, script) |
Run a JS string in a frame (null = current frame). |
win.evalNWBin(frame, path) |
Load and run a compiled .bin produced by nwjc (path, Buffer, or ArrayBuffer). See Section 7.4. |
win.evalNWBinModule(frame, path, module_path) |
Experimental. Load a compiled ES module (compile with nwjc --nw-module); import it later with dynamic import(). |
4.4 Window events
Window exposes a rich set of native events. Listen with win.on(...).
| Event | Fires when | Args |
|---|---|---|
close |
Window asked to close (lets you intercept) | (quit?) on Mac |
closed |
Window has finished closing | — |
loading |
Window starts (re)loading | — |
loaded |
Window fully loaded (like window.onload, but DOM-independent) |
— |
document-start(frame) |
Document object available, before DOM/scripts | frame |
document-end(frame) |
Document unloaded, before onunload |
frame |
focus / blur |
Gains / loses focus | — |
minimize / maximize / restore |
Window state changes (restore replaces the old unmaximize/leave-fullscreen) |
— |
move(x, y) |
After the window moves | x, y |
resize(width, height) |
After the window resizes | width, height |
enter-fullscreen |
Window enters fullscreen | — |
zoom |
Zoom level changes | new level |
devtools-opened(url) / devtools-closed |
DevTools opened / closed | — |
new-win-policy(frame, url, policy) |
A new window/popup is requested | see below |
navigation(frame, url, policy) |
The window navigates to a new page | see below |
Intercepting close to save data is the canonical pattern:
win.on('close', function () {
this.hide(); // appear to close instantly
// ...save data here...
this.close(true); // really close (bypasses this handler)
});
Caution
Inside a
closehandler you must callthis.close(true)to actually close — callingthis.close()again re-fires the event and creates an infinite loop.
Controlling where links open with new-win-policy. The policy object offers ignore(), forceCurrent(), forceDownload(), forceNewWindow(), forceNewPopup(), and setNewWindowManifest(m):
nw.Window.get().on('new-win-policy', function (frame, url, policy) {
policy.ignore(); // don't open a new NW window
nw.Shell.openExternal(url); // open in the system browser instead
});
navigation works the same way with policy.ignore() to block a page from navigating away.
4.5 Menu and MenuItem
A Menu is either a context menu (default) or a menubar. A MenuItem is one row.
Context menu:
var menu = new nw.Menu(); // type: 'contextmenu'
menu.append(new nw.MenuItem({ label: 'Cut' }));
menu.append(new nw.MenuItem({ type: 'separator' }));
menu.append(new nw.MenuItem({ label: 'Paste' }));
menu.popup(x, y); // show at a point
Menubar (a two-level menu assigned to win.menu):
var menubar = new nw.Menu({ type: 'menubar' });
var fileMenu = new nw.Menu();
fileMenu.append(new nw.MenuItem({ label: 'Open' }));
fileMenu.append(new nw.MenuItem({ label: 'Save' }));
menubar.append(new nw.MenuItem({ label: 'File', submenu: fileMenu }));
nw.Window.get().menu = menubar;
Menu members
| Member | Description |
|---|---|
new nw.Menu([{type}]) |
type is "contextmenu" (default) or "menubar". |
menu.items |
Array of the menu's MenuItems. |
menu.append(item) / menu.insert(item, i) |
Add an item. |
menu.remove(item) / menu.removeAt(i) |
Remove an item. |
menu.popup(x, y) |
Show a context menu at a point (contextmenu type only). |
menu.createMacBuiltin(appName, [{hideEdit, hideWindow}]) |
(Mac) Populate the standard App/Edit/Window menus. |
MenuItem options & properties
| Field | Type | Notes |
|---|---|---|
label |
String | Plain text. |
icon |
String | Path to icon (relative or absolute). |
tooltip |
String | (Mac) Hover text. |
type |
String | normal (default), checkbox, or separator. Set only at creation. |
click |
Function | Callback when activated. |
enabled |
Boolean | Default true. |
checked |
Boolean | For checkboxes; default false. |
submenu |
Menu | Nested menu. |
key |
String | Shortcut key (see below). |
modifiers |
String | cmd/command/super, shift, ctrl, alt, joined by + (e.g. "ctrl+alt"). |
iconIsTemplate |
Boolean | (Mac) Treat icon as a template image (default true). |
MenuItem is an EventEmitter; it emits click when activated. The key/modifiers pair binds a keyboard accelerator, where cmd maps to ⌘ on macOS and the Windows key elsewhere.
Warning
Menus and trays created in a page that can navigate or reload stop working after navigation, because the JS engine garbage-collects them. Create long-lived menus and trays in the background page (via
mainas a JS file orbg-script). This is the single most common menu/tray bug.
4.6 Tray — system tray / status icon
var tray = new nw.Tray({ title: 'Tray', icon: 'img/icon.png' });
var menu = new nw.Menu();
menu.append(new nw.MenuItem({ type: 'checkbox', label: 'Enabled' }));
tray.menu = menu; // the only way to attach a menu
// later:
tray.remove(); tray = null;
| Member | Description |
|---|---|
new nw.Tray({title, tooltip, icon, alticon, iconsAreTemplates, menu}) |
Create a tray icon. |
tray.title |
(Mac shows it; ignored on Win/Linux). |
tray.tooltip |
Hover text (all platforms). |
tray.icon / tray.alticon (Mac) |
Icon paths. |
tray.iconsAreTemplates (Mac) |
Template-image styling (default true). |
tray.menu |
Attach a Menu — setting this is the only way to give a tray a menu. |
tray.remove() |
Remove the icon (permanent; set the var to null afterward). |
Event: click |
Left-click only (right-click shows the menu; double-clicks ignored). |
4.7 Clipboard
var clip = nw.Clipboard.get();
clip.set('I love NW.js', 'text'); // write
var text = clip.get('text'); // read
clip.clear(); // empty
| Method | Description |
|---|---|
Clipboard.get() |
Get the clipboard object. |
clip.set(data, [type, [raw]]) |
Write data. type: text (default), png, jpeg, html, rtf. raw (png/jpeg only) controls Base64 framing. |
clip.set(clipboardData) / clip.set(list) |
Write one object, or multiple types at once via an array. |
clip.get([type, [raw]]) / clip.get(list) |
Read one or several types. |
clip.readAvailableTypes() |
List currently-available types. |
clip.clear() |
Empty the clipboard. |
Writing an image and an HTML <img> pointing at it, simultaneously:
clip.set([
{ type: 'png', data: base64png, raw: true },
{ type: 'html', data: '<img src="...">' }
]);
Note
The X11 selection clipboard (middle-click paste buffer) is not supported.
4.8 Shortcut — global hotkeys
A Shortcut is a system-wide hotkey that fires even when your app has no focus.
var shortcut = new nw.Shortcut({
key: 'Ctrl+Shift+A',
active: function () { console.log(this.key + ' pressed'); },
failed: function (msg) { console.log('register failed: ' + msg); }
});
nw.App.registerGlobalHotKey(shortcut);
// later:
nw.App.unregisterGlobalHotKey(shortcut);
The key is zero or more modifiers plus one key, case-insensitive:
- Modifiers:
Ctrl,Alt,Shift,Command(⌘ on Mac, Windows key elsewhere). - Keys:
A–Z,0–9,F1–F24, arrows,Home/End/PageUp/PageDown/Insert/Delete, media keys (MediaPlayPause,MediaNextTrack, …), punctuation (Comma,Period,Tab,Backquote,Minus,Equal, etc.), and W3C key codes.
Shortcut is an EventEmitter emitting active and failed.
Caution
Registering a single key with no modifier (e.g.
{ key: "A" }) hijacks that key system-wide until you unregister it. Only do this deliberately (e.g. for media keys).
4.9 Screen — displays and capture sources
Screen is a singleton EventEmitter; call nw.Screen.Init() once at startup.
nw.Screen.Init();
nw.Screen.on('displayBoundsChanged', function (screen) { /* ... */ });
console.log(nw.Screen.screens); // array of display descriptors
Each entry in Screen.screens has: id, bounds {x,y,width,height}, work_area {x,y,width,height}, scaleFactor, isBuiltIn, rotation, touchSupport.
| Member | Description |
|---|---|
Screen.Init() |
Initialize the singleton (call once). |
Screen.screens |
Array of connected-display descriptors. |
Screen.chooseDesktopMedia([sources], cb) |
Show the screen/window picker; sources is ["screen","window"]; callback gets a streamId for getUserMedia. |
| Events | displayBoundsChanged, displayAdded, displayRemoved (each passes a screen descriptor). |
Screen.DesktopCaptureMonitor is a headless alternative for building your own capture-source UI, with start(includeScreens, includeWindows), stop(), registerStream(id), the started flag, and events added, removed, orderchanged, namechanged, thumbnailchanged.
4.10 The <webview> tag
<webview> embeds untrusted guest content in a separate process from your app, so the guest cannot reach your Node-powered page. Interactions are asynchronous.
<webview id="foo" src="https://www.example.com/"
style="width:640px; height:480px"></webview>
<webview> follows the Chrome <webview> API. NW.js adds:
| Addition | Description |
|---|---|
webview.showDevTools(show, [container]) |
Open DevTools for the guest. |
webview.inspectElementAt(x, y) |
Inspect an element (after DevTools is open). |
allownw attribute |
Turn on Node.js inside the webview (use with caution — webviews normally load untrusted content). |
partition="trusted" |
With a manifest webview.partitions entry, allows loading local files / <all_urls>. |
executeScript({mainWorld:true}) |
Inject into the page's main world rather than an isolated world. |
webview.getCookieStoreId() |
Returns a store id for the chrome.cookies API. |
Important
<webview>is the safe way to display remote/untrusted web content. Prefer it over<iframe>withnode-remotewhenever the content is not 100% yours.
5. Building Real Apps
5.1 JavaScript contexts
Understanding contexts is the key to avoiding mysterious bugs in NW.js. By default NW.js runs in Separate Context Mode, with two distinct JavaScript contexts:
- Browser context — where your
<script>tags, jQuery, RequireJS, etc. run. Has DOM and Web APIs. Node objects (nw,require,process,Buffer,global) are copied in so you can use them. - Node context — where
require()-loaded modules and thenode-mainscript run. Has Node globals (__dirname,process,Buffer) but no Web APIs (nodocument, noalert). One shared Node context backs the background page.
require() path resolution differs by context:
| Caller's context | Relative paths resolved against |
|---|---|
| Node context | the calling module's own directory (normal Node behavior) |
| Browser context | the app root (the package.json directory) |
Mixed Context Mode (start NW.js with --mixed-context, or add it to chromium-args) merges the two: a fresh Node context is created alongside each browser context, so Node modules can touch DOM/nw APIs and vice versa.
{ "name": "demo", "main": "index.html", "chromium-args": "--mixed-context" }
| Separate Context (default) | Mixed Context | |
|---|---|---|
| Variable sharing across windows | Easy (shared Node context) | Hard (use postMessage) |
instanceof / type-check pitfalls |
More common | Fewer |
| Node + DOM in one module | No | Yes |
Warning
Cross-context
instanceoffails. A value passed from another window/frame has a different prototype chain, sovalue instanceof Arraycan befalsefor a real array. Use context-safe checks:Array.isArray(x), orObject.prototype.toString.call(x) === '[object Date]'. Do not turn on Mixed Context if your app relies on sharing variables between windows via the Node context.
5.2 Node and DOM extensions
NW.js extends both the DOM and Node beyond what a browser or Node alone provide.
Extended <input type="file"> (Node frames only, for security):
| Feature | Description |
|---|---|
fileinput.value |
Native filesystem path of the selected file. |
file.path |
Native path on each item of the files list. |
nwdirectory attr |
Select a directory and return its path. |
nwdirectorydesc attr |
Title for the directory dialog (default "Select Folder"). |
nwsaveas[="name"] attr |
Open a Save As dialog (allows choosing a non-existent file). |
nwworkingdir attr |
Initial directory for the dialog. |
oncancel event |
Fires when the user cancels the dialog. |
<input type="file" nwsaveas="report.txt" nwworkingdir="/home/me/">
Extended <iframe> attributes:
| Attribute | Effect |
|---|---|
nwdisable |
Make the frame a normal frame (disables require, nw, Node APIs). |
nwfaketop |
Hide the real window.parent/window.top from the frame. |
nwUserAgent |
Override the User-Agent for the frame. |
Note
nwdisablealone is enough to sandbox an iframe from Node. Addingnwfaketopalso blockswindow.parent/window.top— but it breakswindow.parent.postMessage(), so only use it when you specifically need to hide the parent.
Node changes: console.log() output is redirected to the DevTools Console. The process.versions object gains nw, chromium, and nw-flavor ('sdk' or 'normal'); process.mainModule points at your main (or node-main if set).
5.3 Reading a user-selected file end-to-end
<input type="file" id="picker">
<pre id="out"></pre>
<script>
const fs = nw.require('fs');
document.getElementById('picker').addEventListener('change', function () {
const path = this.value; // native path (NW.js extension)
fs.readFile(path, 'utf8', (err, txt) => {
document.getElementById('out').textContent = err ? String(err) : txt;
});
});
</script>
6. Security
NW.js apps run with the full privileges of the user: a Node-enabled page can read and write any file, spawn processes, and open sockets. Treat security as a first-class concern.
6.1 Node frames vs. normal frames
There are two kinds of frames. Node frames can use Node/NW.js APIs, the extended DOM features, and bypass sandbox / same-origin restrictions. Normal frames cannot. A frame is a node frame only if all of these hold:
nodejsistruein the manifest, and- the frame's URL matches a
node-remotepattern, or uses thechrome-extension://protocol, and - neither the frame nor a parent has the
nwdisableattribute, and - the frame is not inside a
<webview>.
6.2 Practical rules
Caution
- Never point
node-remoteat an origin you don't fully control. It grants that website full machine access.- Load untrusted or third-party web content in a
<webview>(separate process, no Node), not an<iframe>.- Sandbox local iframes that don't need Node with the
nwdisableattribute.- Be cautious enabling
allownwon a webview — it defeats the webview's isolation.
6.3 Tamper-resistance options
NW.js cannot make a desktop app fully tamper-proof, but it offers layers:
nwjc— compile JS to a platform-specific binary so the source isn't shipped (Section 7.4).- Content verification — sign your app files so a stock NW.js binary refuses to load modified files (Section 8.5).
- Move sensitive logic into a native Node module or NaCl.
Note
These deter casual tampering but do not stop a determined attacker from running your files under a different NW.js binary. Combine measures and keep real secrets on a server.
7. Common Tasks (Recipes)
7.1 Debugging with DevTools
DevTools is available only in the SDK build.
- Open it: press F12 (Windows/Linux) or ⌘+⌥+i (Mac), or call
win.showDevTools(). - Debug Node modules (Separate Context): right-click the app and choose Inspect Background Page; the debugger stops there when stepping into Node code.
- Debug Node modules (Mixed Context): Node and DOM share one DevTools window.
- Remote debugging: launch with
--remote-debugging-port=9222, then openhttp://localhost:9222/in a browser.
DevTools extensions (React, Vue, etc.) are supported: add the permission "chrome-extension://*" to the extension's manifest.json and load it with --load-extension=path/to/extension.
nw --load-extension=path/to/react-devtools path/to/app
Tip
For Vue:
npm install --save-dev nw-vue-devtools-prebuilt, then add"chromium-args": "--load-extension='./node_modules/nw-vue-devtools-prebuilt/extension'"to your manifest. Use the unminifiedvue.js, notvue.min.js.
7.2 Getting editor autocomplete for nw
Install the types and turn on TypeScript checking — no TypeScript required:
npm install --save-dev nwjs-types
Add // @ts-check to the top of your JS file; VS Code then autocompletes nw..
7.3 Using native Node modules
Native (C/C++) modules must be rebuilt against NW.js headers because NW.js's V8 ABI differs from stock Node.
NW.js 0.111.3+ (node-gyp)
Standard node-gyp works directly with NW.js's Node-compatible headers:
npm install --target=0.111.3 --disturl=https://dl.nwjs.io/
# or, to rebuild an existing module:
node-gyp rebuild --target=0.111.3 --disturl=https://dl.nwjs.io/
Before 0.111.3 (nw-gyp)
Older NW.js needs nw-gyp:
npm install -g nw-gyp
export npm_config_target=0.18.5
export npm_config_arch=x64
export npm_config_runtime=node-webkit
export npm_config_build_from_source=true
export npm_config_node_gyp=$(which nw-gyp)
npm install
node-pre-gyp packages
node-pre-gyp build --runtime=node-webkit --target=0.111.3 --target_arch=x64
Warning
On Windows you need a C++ compiler toolchain (Visual Studio with "Desktop development with C++"). After switching NW.js versions, delete
node_modulesand run a fullnpm installagain.node_modulesbuilt for one platform are not portable — rebuild on every target platform.
7.4 Protecting your JavaScript source
The SDK build ships nwjc, which compiles JS to native code so you can ship the binary instead of the source.
nwjc source.js binary.bin # compile a script
nwjc --nw-module mod.js mod.bin # compile an ES module
Load it at runtime:
nw.Window.get().evalNWBin(null, 'binary.bin'); // null = main frame
You can also fetch a compiled binary over the network as an ArrayBuffer and run it on the fly via evalNWBin(null, xhr.response), and Web Workers can run binaries via importNWBin(arrayBuffer).
Important
Compiled binaries are not cross-platform or cross-version. Run
nwjconce per platform (and re-run after upgrading NW.js) when packaging. Compiled code runs in the browser context. (Pre-0.22 it ran ~30% slower; fixed in 0.22.0.)
7.5 Leaving fullscreen with the Esc key
NW.js does not bind Esc to exit fullscreen by default — wire it up yourself:
nw.App.registerGlobalHotKey(new nw.Shortcut({
key: 'Escape',
active: function () { nw.Window.get().leaveFullscreen(); }
}));
7.6 Transparent windows
Set frame: false and transparent: true, give the body a transparent background, and (on Linux) pass the right flags:
{ "window": { "frame": false, "transparent": true } }
<body style="background-color:rgba(0,0,0,0);">
| Platform | Requirement |
|---|---|
| Windows | Vista+ with DWM enabled (no classic theme / basic mode / remote desktop). |
| Linux | Run with --enable-transparent-visuals --disable-gpu; WM must support compositing. |
| Click-through (Win/Mac) | Run with --disable-gpu-compositing --force-cpu-draw; works on frameless, non-resizable windows. |
7.7 Auto-updating your app
NW.js has no built-in updater; use a community module:
| Module | Notes |
|---|---|
nw-autoupdater |
Modern async/await API; reads a remote manifest, downloads the matching platform package, unpacks, swaps, and restarts. |
nwjs-autoupdater |
Tiny Go helper (~2 MB) that unpacks updates; can update itself and needs no elevated privileges. |
node-webkit-updater |
Low-level building blocks; you write the update flow. |
8. Packaging & Distribution
To ship, you redistribute the NW.js binaries together with your app files.
8.1 Prepare your app
- [ ] Gather source code and resources
- [ ]
npm installyour dependencies on each target platform - [ ] Rebuild native Node modules (Section 7.3)
- [ ] Compile JS with
nwjcand remove the originals (if protecting source) - [ ] Provide the window/app
icon
Caution
Linux and most macOS filesystems are case-sensitive —
Test.js≠test.js. Verify the case of every path. On Windows, keep build paths short (e.g.C:\build\) to avoid the 260-character path limit duringnpm install.
8.2 Build flavors
| Flavor | DevTools / NaCl | Use for |
|---|---|---|
| SDK | Yes | Development & testing |
| Normal | No | Production (smaller download) |
Check at runtime with process.versions['nw-flavor'] ('sdk' or 'normal').
Note
Ship all files from the downloaded package except the SDK-only tools
nwjc,payload, andchromedriver— those are development tools, not runtime files.
8.3 Package your app
Plain files (recommended)
Windows/Linux: put your app files in the same folder as nw(.exe), with package.json alongside the binary — or in a subfolder named package.nw.
macOS: put your files in nwjs.app/Contents/Resources/app.nw.
Zip (package.nw)
Zip your files, rename to package.nw (Win/Linux) or app.nw (Mac, placed in Contents/Resources/).
Optionally append the zip to the binary to hide it:
# Windows
copy /b nw.exe+package.nw app.exe
# Linux
cat nw package.nw > app && chmod +x app
Warning
A large
package.nwor one with many files starts slowly, because NW.js unzips it to a temp folder on launch. Prefer plain files for big apps.
8.4 Platform-specific steps
| Platform | Tasks |
|---|---|
| Windows | Replace the nw.exe icon (Resource Hacker, nw-builder, node-winresourcer); build an installer (NSIS, Inno Setup, Windows Installer). |
| Linux | Create a .desktop file; ship via makeself/shar or distro packages (apt, yum, pacman). |
| macOS | Replace Contents/Resources/nw.icns; edit Contents/Info.plist (bundle id, CFBundleDisplayName); rename helpers; sign the app or Gatekeeper blocks it. Use product_string in the manifest to rename the Helper. |
The high-level nw-builder tool automates much of this.
8.5 Content verification (app signing)
Prevents a stock NW.js binary from loading modified app files. The public key is built into NW.js; you sign your files with a private key into verified_contents.json, then launch with enforcement:
nw --verify-content=enforce_strict .
Signing with the demo keypair (tools live in tools/sign/):
cdinto the app directory; remove any existingverified_contents.json/computed_hashes.json.- Run
payload(e.g.payload.exe) → generatespayload.json. python sign.py > /tmp/verified_contents.json(write outside the app dir).- Move
verified_contents.jsoninto the app directory.
To use your own keypair you must rebuild NW.js with your public key compiled in. Verification modes are none, bootstrap, enforce, and enforce_strict.
Note
Content verification does not stop someone from loading your files with a different NW.js binary. Combine it with
nwjcand native modules for defense in depth.
8.6 macOS App Store
Download the MAS build from nwjs.io, then sign with build_mas.py (add --pkg to produce an uploadable .pkg):
python build_mas.py -C build.cfg -I myapp-dev.app -O MyApp.app
The build.cfg specifies ApplicationIdentity, InstallerIdentity, NWTeamID (your Apple Team ID, used to set up IPC), and parent/child entitlements. By default the app is sandboxed (com.apple.security.app-sandbox).
8.7 Verifying downloaded binaries
From 0.32.0 on, each download directory has a SHASUMS256.txt:
curl -O https://dl.nwjs.io/vX.Y.Z/SHASUMS256.txt
grep nwjs-vX.Y.Z.tar.gz SHASUMS256.txt | sha256sum -c -
Stable (non-nightly) releases also ship GPG detached signatures.
9. Migration: 0.12 → 0.13
NW.js 0.13 was a major architecture change (the "nw2" line). If you maintain an older app, the highlights:
- Apps now run internally as a Chrome App; the default protocol changed from
file:///app://tochrome-extension://. Allchrome.*platform APIs are available. - All NW APIs (and
require()) moved into the globalnwobject. Thenw.guilibrary still works as a compatibility wrapper. - The Node context lives in the background page's DOM context, shared across windows.
Deprecated / changed manifest fields:
| Field | Change |
|---|---|
single-instance |
Deprecated; always true. Use the App open event for second-launch handling, or a different --user-data-dir. |
toolbar |
Deprecated; always false. Use F12 and win.reload()/win.reloadDev(). |
no-edit-menu, snapshot |
Deprecated (snapshot → use win.evalNWBin()). |
node-remote |
Now an array of Chrome match patterns. |
always-on-top, visible-on-all-workspaces, new-instance, inject-js-start/end |
Renamed with underscores: always_on_top, visible_on_all_workspaces, new_instance, inject_js_start, inject_js_end. |
--data-path (CLI) |
Renamed --user-data-dir. |
Window API changes: windows now have an id for geometry persistence; Window.open() and showDevTools() pass the created window to the callback; unmaximize/leave-fullscreen events were replaced by restore; setTransparent() and capturepagedone are deprecated; Window is no longer an EventEmitter subclass (but on/once/removeListener/removeAllListeners still work). Shortcut no longer maps Ctrl→⌘ on Mac — use the cross-platform Command modifier and detect the OS yourself.
10. Troubleshooting
Format: each entry gives the symptom, the cause, and the fix.
Error: var crypto = require('crypto') returns the wrong object
Cause: Chromium defines a global crypto object that cannot be overwritten, so your variable named crypto collides with it.
Solution: rename your variable, e.g. const nodeCrypto = require('crypto');.
Prevention: avoid variable names that collide with Web globals (crypto, global, screen).
Error: Failed to load resource ... net::ERR_UNKNOWN_URL_SCHEME (images broken in AngularJS)
Cause: AngularJS prefixes unknown URL schemes with unsafe:; NW.js URLs use the chrome-extension: scheme, which Angular doesn't whitelist.
Solution: whitelist the scheme in your Angular config:
myApp.config(['$compileProvider', function ($compileProvider) {
$compileProvider.imgSrcSanitizationWhitelist(/^\s*((https?|ftp|file|blob|chrome-extension):|data:image\/)/);
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|chrome-extension):/);
}]);
Error: exception reporting missing in AngularJS 2+
Cause: Angular 2 registers exception handlers on the global global, which already exists in NW.js.
Solution: rename global before loading Angular:
<script>window.nw_global = window.global; window.global = undefined;</script>
Issue: console.log produces no output in a Linux terminal
Cause: GUI apps don't write to stdout by default.
Solution: launch with --enable-logging=stderr.
Issue: a custom --user-data-dir still creates an AppData folder (Windows)
Cause: known behavior (issue #6328) — a default data folder is still created even when a custom directory is set.
Solution: track the upstream issue; rely on the explicit --user-data-dir for your actual data and ignore the empty default folder.
Issue: Node ESM built-in modules can't be imported in the DOM/Browser context
Cause: Node and Chromium use different ES-module resolvers (issue #8333).
Solution: enable the chained resolvers with --enable-features=NWESM,NWChainImportNode (or NWChainImportDom), and load ESM via node-main (0.98.2+). See Section 11.2.
Issue: nwjc-generated file throws SyntaxError: Unexpected identifier
Cause: loading a compiled binary built for a different NW.js version/platform, or mismatched module flags (issue #8289).
Solution: recompile with nwjc using the same NW.js version and platform; use --nw-module + evalNWBinModule() for modules.
Issue: window positioning fails on Wayland (Linux)
Cause: Wayland restricts programmatic window placement (issue #8348). Solution: run under X11/XWayland if precise positioning is required; set positions in the window's callback rather than synchronously.
Issue: native module crashes or won't load
Cause: built against stock Node's ABI, not NW.js's.
Solution: rebuild with node-gyp --target=<ver> --disturl=https://dl.nwjs.io/ (0.111.3+) or nw-gyp; delete node_modules and reinstall after upgrading NW.js. See Section 7.3.
Issue: menu or tray stops working after navigation/reload
Cause: the menu/tray was created in a page that navigated, so it was garbage-collected.
Solution: create menus and trays in the background page (main as JS, or bg-script). See the warning in Section 4.5.
Issue: a real array fails value instanceof Array
Cause: the value came from another JavaScript context with a different prototype chain.
Solution: use Array.isArray(value) or Object.prototype.toString.call(value). See Section 5.1.
Issue: --single-process doesn't work
Cause: known limitation (issue #8173).
Solution: avoid relying on single-process mode; if testing crash handling with it, also set --disable-crash-handler=true.
11. Reference
11.1 The nw global — quick index
| Browser-context global | Equivalent | Notes |
|---|---|---|
nw |
— | All NW.js APIs. |
require |
nw.require |
Also supports require('nw.gui'). |
process |
nw.process |
Node process module. |
global |
nw.global |
Node global object. |
Buffer |
— | Node Buffer class. |
11.2 Command-line options
Pass these when launching nw, or bake them into chromium-args in the manifest.
| Option | Description |
|---|---|
--url=<url> |
Load <url> with the default app. |
--mixed-context |
Run in Mixed Context Mode. |
--nwapp=<path> |
Alternative way to specify the app path (useful with ChromeDriver). |
--user-data-dir=<dir> |
Override the data directory (stored data, caches, crash dumps). |
--disable-devtools |
Disable user access to DevTools in an SDK build. |
--enable-node-worker |
Enable Node.js integration in Web Workers. |
--enable-features=NWESM |
Allow ESM in the Node context (combine with NWChainImportNode/NWChainImportDom). |
--disable-raf-throttling |
Keep requestAnimationFrame firing while minimized/hidden (useful for games). |
--disable-cookie-encryption |
Don't encrypt the on-disk cookie store (testing only). |
--disable-crash-handler=true |
Disable the crash handler (with --single-process, yields a single process). |
--enable-gcm |
Enable the chrome.gcm API. |
--enable-transparent-visuals |
Transparent-window support (Linux). |
--disable-transparency |
Disable transparent windows entirely. |
--disable-gpu |
Disable GPU (used with transparency / click-through). |
--force-cpu-draw |
Force CPU drawing (transparency click-through). |
--remote-debugging-port=<port> |
Expose the DevTools protocol on a port. |
--load-extension=<path> |
Load a (DevTools) extension. |
--enable-logging=stderr |
Send console.log to the terminal. |
--verify-content=<mode> |
Content verification: none/bootstrap/enforce/enforce_strict. |
Node-context option (place in node-main, not the command line):
| Option | Description |
|---|---|
--nw-node-inspector |
Enable the V8 inspector in Node (replaces Blink's; breaks console.log in the DOM). |
Environment variables
| Variable | Effect |
|---|---|
NW_PRE_ARGS |
Prepended to the value of chromium-args. |
NW_DESKTOP |
(Linux/Ubuntu) .desktop file used by setProgressBar/setBadgeLabel (default nw.desktop). |
You can also use any Chromium command-line switch.
11.3 Manifest field index
See Section 3 for full descriptions. Top-level: main, name, version, product_string, nodejs, node-main, domain, bg-script, user-agent, node-remote, chromium-args, js-flags, crash_report_url, inject_js_start, inject_js_end, additional_trust_anchors, dom_storage_quota, window, webkit, webview. Deprecated: single-instance, toolbar, no-edit-menu, snapshot.
11.4 Getting help
- Official docs: http://docs.nwjs.io/
- Wiki (community-editable): https://github.com/nwjs/nw.js/wiki
- Mailing list: https://groups.google.com/d/forum/nwjs-general
- Chat: https://gitter.im/nwjs/nw.js
- Issues: https://github.com/nwjs/nw.js/issues