The NW.js Page

Basically this page encapsulates some of the experience I have had with using NW.js


Basically my coding started with 6800/6809 machine coding and then to BASIC (CP/M and DOS). VB5/6 were used then VB2005/2008.
Unfortunately VB was just getting too cumbersome with .NET frameworks etc so I tried Q7Basic. Q7Basic looked quite good but was a bit limited in cross-platform capability and then of course the sole developer decided to abandon the project.
Thereafter I tried the Konfabulator/YWE for small widget type apps and it worked great until they sold out to the Yahoo TV Widget dream.
Somehow I came across Node-Webkit (now NW.js) and it looked ideal going forward since I could leverage my web knowledge.

NW.js for me has been quite easy to use and one of my apps which started on CP/M Basic now runs on NW.js too.

😁 I know - what is CP/M? - it is Control Program/Micro. Basically the predecessor to DOS and the machine I used was an InterTec SuperBrain with a Z80 CPU (in fact - two!)

So Here We Go .... :

NW.js ticks a lot of boxes for me -
   Cross-platform (OSX/Win/Linux)
   Web technologies (HTML/CSS/JS)
   No compilation required
   Easy to encapsulate web sites into desktop apps
   Transparency to allow widget type functionality
   Ability to compile/obfuscate js files if necessary
   App can start in either browser or node context

A short history:
NW.js started out as Node-Webkit which basically uses the Chrome/Chromium browser in conjunction with Node.js providing a unified framework for the client/server contexts based on javascript - it allows cross-platform development of desktop applications utilizing web technologies (HTML/CSS/JS).
I suppose the elephant in the room for NW.js (and the same for Electron) is that every application being shipped essentially is integrated into it's own customised Chromium browser so the binary sizes can be quite large for simpler programs compared to say apps built with C++ or suchlike (size starts at c. 100M) - this is the price for easy cross-platform desktop development!

It should be noted that a similar project exists called Electron (formerly Atom) - this was created for GitHub by a former Node-Webkit developer and has gained a lot of traction with devs/larger companies (eg: Microsoft with Visual Studio Code).
I have noticed that a number of apps formerly built with NW.js have now moved to Electron and the resourcing of Electron looks more plentiful - looking a bit like a VHS/Betamax scenario however I'm happy with NW.js and for me it is a lot easier to understand than the Electron approach which appears to rely on IPC messaging, etc.

I think that core architecture influences the takeup of either NW.js or Electron. The core of NW.js is implemented in a way that makes it tough for devs to work with the core but easy for devs using the standard core build whereas Electron it's the other way round to some extent so it is more difficult to get a lot of folk to be able to assist with the NW.js project itself.

Current State of the Play:
NW.js has been updated quite regularly (inline with the Chromium browser) since the architectural change from Node-Webkit 0.12.3 to NW.js 0.13 and currently 0.53 works pretty well.

On balance for me (a non-professional hobbyist) NW.js offers a great way to build cross-platform desktop apps that work relatively easily but be aware that documentation can be quite sparse in places (Basic tended to be great in this respect). NW.js offers me a good replacement for Visual Basic/Basic (aside from the lack of a Visual Interface - I think it may happen one day but likely to be online only eg: Macaw).

Documentation has improved a bit but the wiki that exists still adds confusion - it was done for 0.12 and earlier and only some parts are good for the 0.13 or later versions. Unfortunately a lot of forum references still relate to the old wiki which can be confusing.
The official docs usually give enough for professional developers to use but for the lesser skilled hobbyist needing real world examples it will involve a lot of searching/trawling to understand some stuff.
Unfortunately in terms of using existing apps to learn how to do stuff the number of apps available that use NWjs is quite sparse and most that I have found are using early node-webkit/nwjs before they moved to Electron.

A particular hassle can be with plugins/extensions for audio/flash/etc - the docs will say it can be done and give a short one-liner but there is very little by way of example on how to do it.
I have included sections below to try and fill out areas that I have come across which may help some folk.

There are quite a lot of books on Node.js and a few on NW.js in particular however a lot of the existing books/documents/sample projects (as at early 2016) are still based on 0.12.3 or earlier. With the advent of the re-architected 0.13 and later docs can be a bit thin and prior knowledge of the Chrome/Chromium project is assumed.
One book I have found to be excellent is written by Paul Jensen.
Cross-Platform Desktop Applications with Node, Electron and NW.js HERE

Also worth a look maybe (I haven't checked it myself) -
Cross-platform Desktop Application Development: Electron, Node, NW.js and React by Dmitry Sheiko (Packt Publishing)

Bug Support:
The team available to fix bugs with NW.js is extremely small (King Roger Wang and a couple of others) but important bugs are usually dealt with promptly. I find it helps a lot by providing a wee sample app that demonstrates the problem and therefore 'puts it on a plate' for the developer - quick turnaround may ensue. P1 bugs are generally quick (crash bugs are generally P1), P2 less so but a sample helps.

Quick note on the logo:
It is a compass and compass needles always point to magnetic north (unless you are standing next to a huge lump of magnetite/iron or something) so it follows that if you were holding the compass the top would be pointing to the North West (NW) - I quite like it as an icon and no chance of dying of radiation poisoning from a nuclear particle 😂

Useful NW.js Links

NW.js site HERE the main site with docs, etc

Live Builds HERE useful for getting latest builds

Roger Wang Twitter Feed HERE Useful for short updates on NW.js project

Google Groups HERE the official NW.js mailing list

StackOverflow HERE 

Node.js site HERE the main Node.js site with docs, etc

NPM site HERE tons of useful modules

Web2Executable HERE use for packaging Apps (NOTE: Python-based GUI - this repo is now unmaintained)

nw-builder HERE use for packaging Apps (NOTE: CLI - this repo struggles for maintainers but basically OK)

nwjs-builder-phoenix HERE use for packaging Apps (NOTE: CLI - this repo is now looking for new maintainer)

nw-autoupdater HERE Auto update tool for apps

node-appdmg HERE DMG packaging tool for OSX (note: is picky on the node module version)

Chromium Command Line Switches HERE used with chrome-arguments in package.json

NW.js Utilities HERE Courtesy The Jared Wilcurt - useful stuff

Universal Graphical User Interface project HERE Courtesy The Jared Wilcurt - useful for learning

Gitter site HERE Good forum superbly held together by The Jared Wilcurt

StackOverflow HERE search for nwjs

Chromium site HERE Chromium download site (NW.js is based on Chromium code base)

dblite - Simple no-hassle sqlite3 HERE works with sqlite3 exe as supplied by sqlite-tools package or system install

NWjs Concepts/Packaging

Node-Webkit : Uses Node.js and Webkit browser (legacy)
NW transition : Uses io.js and Chrome browser with Blink rendering engine (legacy)
NW.js : Uses Node.js and Chrome browser with Blink rendering engine

OSX support is 64bit only with the later releases of NW.js - 0.29.0 or later supports OSX 10.10 onwards.
Windows: OK from Windows 7 onwards (32/64bit).
Legacy Windows: Vista using the Aero interface will be OK with transparency (not supported with later NW.js).
 XP/Vista non-Aero will work but will have problems with transparency since graphics layering is used rather than compositing (not supported with later NW.js).
Linux: There is 32/64bit support but may need particular versions of distros.

NW.js 0.14.x LTS supports XP.

CSS/HTML coding:

This is quite straight forward normally since NW.js is based on Chromium and therefore only Chrome needs to be considered regarding layout however if the app is of a type that allows remote access from other browsers then the layout coding may have to reflect that (combined server/client capability allows this).

If a NW.js binary is started outside an app folder (therefore no package.json found) the default window will show as -

The NW.js Default Screen

Typical OSX Project to produce a desktop App:

New Project :: - call it Hippo

I generally use two styles of App - normal desktop mode and transparent widget type, Hippo is setup as a widget style App.

=> App folder
=> Resources folder (Icons,plist,etc for project)
=> Info.plist file

App folder
=> package.json file (REQUIRED)
=> index.html (or similar REQUIRED for main in package.json)
=> node_modules folder (REQUIRED for NPM modules)
=> css folder
=> js folder
=> Resources folder (images,etc within application)

The NW.js binary can be placed in the App folder and if double-clicked will startup as the application. The binary will look for the package.json (also called the manifest) and execute it - the start page is generally specified as the main: parameter within the manifest.

When the application is run the support files will be placed in User/Library/Application Support/Hippo
Strange issues/problems with the app can sometimes be cured by deleting this folder and it will be recreated next time the app is run.

Using NPM modules ::

NWjs makes use of the NPM packaging system which gives quite a lot of flexibility in projects.

To use fs-extra with project called Hippo eg:
Use Terminal and navigate to Hippo project folder and then to App folder within then enter -

npm install fs-extra --save

This will install the npm module fs-extra into the node_modules folder within the app folder and the save command will write the dependencies into the package.json file of the app folder.

NOTE: NPM modules should be installed/uninstalled correctly to best avoid error issues during development.

Packaging the App ::

My packaging app of choice is now a custom version of nw-builder with a GUI frontend which creates cross-platform app packages.

I tend to develop on the OSX platform but nw-builder allows me to use the same source project to package for Win/Linux as well. It should be noted however that certain OS particular features may be easier to develop on the appropriate platform eg: transparent widgets on Windows will tend to require use of the context menu whereas the OSX native menu can still be used if desired. Windows also makes use of the registry quite a bit.
It is quite OK to use the same source folder arrangement on the Windows platform - the app can be run by simply dragging the app folder (containing package.json) onto the nw.exe binary.

NW Structure - Basic Layout of a Packaged App (OSX) using 0.12.3 (legacy)

NW Structure - Basic Layout of a Packaged App (OSX) using 0.13 to - 0.39

NW Structure - Basic Layout of a Packaged App (OSX) using 0.40 or later

Folder Structure - 0.40 - Changed structure with new Helpers

Download Hippo project source (ZIP) HERE
 Sample NW.js transparent widget type app called Hippo -
=> Unzip and place NWjs binary into the Hippo folder(contains package.json) - 0.14 or later
=> Double-click NW.js binary to run app

Use a builder app to package project if desired.

Using Audio/Video (MP3/MP4)

Since c. 0.22.1 NW.js has included the MP3 codecs (patent restrictions just expired). Pre-built codecs can be obtained from various sources - some work, some don't.

The iteufel GitHub repo is the best source for pre-built binaries -

OSX - libffmpeg.dylib
Win - ffmpeg.dll
Linux -

NWjs includes -
  vp8 & vp9
  pcm_u8, pcm_s16le, pcm_s24le, pcm_f32le, pcm_s16be & pcm_s24be
  mp3 (v0.22.1+)

iTeufel pre-built adds -

I guess that the status of codecs should be checked if apps are destined for commercial distribution however.

As a sidenote check out mpv.js for a versatile player (repo on GitHub) which will play most formats -

  swf - audio only

Using Flash

UPDATE: As of Dec 2020 Flash support has been disabled/removed from NW.js 0.51 (Chromium 88) onward. Any flash apps will have to use pre-0.51 builds of NW.js

Flash is Dead - Long live Flash
Basically everyone is running away from Adobe Flash as fast as they can but there is still a lot of legacy requirements out there.
Chrome no longer supports NPAPI plugins but now use Pepper Flash plugins (PPAPI). NW.js does not include a flash plugin but it can be obtained from Adobe.

The PepperFlash folder resides in the Internet Plug-Ins folder within the Chrome/Chromium Framework.framework package
This needs to be placed in the nwjs Framework.framework/Internet Plug-Ins folder of the NW.js binary
NOTE: NW.js requires a manifest.json file to accompany the PepperFlashPlayer.plugin and this is NOT provided in the Chrome/Chromium apps so here is an example - HERE - typical for use with PepperFlashPlayer.plugin
- download HERE

Using Webview Tag -

index.html -
<webview id="wbv" src="sound.swf" style="width:200px; height:100px" partition="trusted"></webview>

package.json -

   "webkit": {
      "plugins": true
   "webview": {
      "partitions": [
            "name": "trusted",
            "accessible_resources": [

Current status as at 0.32.0:
If PepperFlash is installed within the app and on the system NW.js seems to use the latest version available.
   eg: (checked on OSX)
         App Version       System Version    -->  App version used    -->  System version used
             N/A         -->  System version used                  N/A      -->  App version used

The PPAPI version of flash is available from Adobe for all OS types.

Handy manifest (package.json) settings

Transparency ClickThrough requires -
   "frame": false
   "resizable": false
   "chromium-args": "--disable-gpu --force-cpu-draw" (pre - 0.28)
   "chromium-args": "--disable-gpu-compositing --force-cpu-draw" (since 0.28)

Print Preview uses PDF plugin so requires -
   "plugin": true for webkit parameter

Full DevTool logging may require -
   "chromium-args" : "--mixed-context"

Debug logging (chrome_debug.log file in Application Support/<Appname> folder)    "chromium-args": "--enable-logging --v=1"


Java Applet support ceased about 0.13 since later Chrome browsers no longer support it. Support exists in 0.12.3

PDF support is built in to NW.js

I have also noticed when doing restarts/reloads to test changes the first start is often buggy so I need to run a second test - I think there must be an obscure cache which has data from the last run in it.

UPDATE: I think that this may have been down to a Chromium bug c. NWjs v0.20 or so - seems not to happen now.

Chrome Extension Support


"chromium-args" : "--load-extension" eg: "chromium-args" : "--load-extension=/Users/whateveruser/Desktop/ fmkadmapgofadopljbjfkapdkoienihi"

Extension can be taken from chrome (unpacked).
eg: using react-devtools example -

"chromium-args" : "--load-extension=/Users/whateveruser/Desktop/ fmkadmapgofadopljbjfkapdkoienihi"

"chrome-extension://*" needs to be placed in permissions of manifest.json inside extension folder

Example using Google Office Editing for Docs, Sheets & Slides (.doc/.docx/.xls/.xlsx/.ppt/.pptx)


"chromium-args" : "--load-extension" eg: "chromium-args" : "--load-extension=/Users/USER/Desktop/ gbkeegbaiigmenfmjfclcdgdpimamgkj/129.2270.2278_0"

File src -

<iframe style="width:780px;height:600px;" src="file:///Users/USER/Desktop/TestExtensions/test.xls" nwfaketop nwdisable allowfullscreen="true"></iframe>
Both chromium-args and file source require a full path - relative will not work.

UPDATE: As of 0.37.1 relative paths will work (eg: src='./test.xlsx) using extns .xlsx/.doc/.docx/.ppt/.pptx/.csv following a gitfix for NWjs
Extension .xls will not work in relative mode on Mac due to an upstream Chromium issue (#155455)

Drag and Drop

Plenty of descriptions on the web but my use case is usually for a file selection zone that will react to either a click for folder dialog or DnD of files directly.
Example below uses a bit of html layout trickery but works quite well.

Essential concept is place all of BODY content in newBody and apply ondragstart/ondragenter/ondragover/ondrop parameters - this kills all DnD within this DIV.
DnD zone DIV is created within the newBody DIV but the INPUT tag that uses the DnD functions must be outside the newBody DIV - the INPUT tag (with opacity of 0.01 to allow click-through) is positioned over the dropzone div.

GREEN - DnD related code

BLUE - draggable related code

Although strictly not DnD content within the app window will tend to behave as per a normal browser where images can be dragged and the body content will move if 'swiped' whereas this is not a feature of desktop mode.
The blue code shows the tweaks needed - the img tag css could also be used to limit draggability (overflow: hidden; used to stop 'swiping' movement).
user-select: none; can also be placed in the BODY CSS to avoid selection/dragging of page text.


<body style="background-color: black; overflow: hidden;" class="yui3-skin-sam">

   <div id="newBody" style="position: absolute; display: block; text-align: center; width: 100%; height: 100%;" ondragstart="return false;" ondragenter="return false;" ondragover="return false;" ondrop="return false;">

      <div id="header">
         <div id="banner"><img src="assets/hc.png" draggable="false" style="width: 96px; height: 96px;" alt="banner" /></div>
         <img src="assets/pano.png" draggable="false" style="margin-left: 300px; width: 343px; height: 100px; border: none; border-radius: 10px;" />
         <br />
         <img id="proggo" src="assets/proggo.png" alt="Pending" draggable="false" style="position: absolute; display: block; top: 30px; left: 980px; width: 30px; height: 30px;" />

         <div id="filednd">
            <p id="newLabel">Select Source Image<br />Click to Choose or Drag/Drop file here</p>  <!-- input control is outside new body div -->

   <p id="currentSrc">Current Source Image:</p><textarea id="currentFile" rows="1" cols="120" style="resize: none;"></textarea>

   <!-- must remain outside newBody div -->

      <input type="file" id="fileSelection" name="files[]" />
      <output id="list"></output>


#filednd {
   position: absolute;
   display: block;
   border: 2px dotted gray;
   border-radius: 8px;
   top: 20px;
   left: 950px;
   width: 300px;
   height: 80px;

   margin-left: auto;
   margin-right: auto;
   text-align: center;

#fileSelection {
   position: absolute;
   opacity: 0.01;
   top: 20px;
   left: 950px;
   width: 300px;
   height: 80px;


#newLabel {
   position: relative;
   top: 20px;
   color: gray;
   font: 13px "Comic Sans MS";

JS -

// ******************** Get Image File to process *****************************
* @param evt - listener trigger event to be processed
* @returns
function handleFileSelect(evt) {

   var fileToProcess =; // FileList object
   srcFile = fileToProcess[0].path;

   srcFileReal = srcFile;
   localStorage.pref_srcFileToProcess = srcFile; // make available as global
   localStorage.pref_firstStart = false;


// ***************************** Mainline **************************************
// Occurs on Load/reload

   if (localStorage.pref_firstStart == "true") { // this flag set in js code defined by main in package.json
      document.getElementById('filednd').style.borderColor = 'red';
   } else {
      document.getElementById('filednd').style.borderColor = 'darkorange';

      document.getElementById('currentFile').innerText = localStorage.pref_srcFileToProcess;
      var el = document.getElementById('currentFile');

   var tempo = document.getElementById('viewDng').classList;
   if (localStorage.pref_fileOutput == 'dng') {
   } else {


document.getElementById('fileSelection').addEventListener('change', handleFileSelect, false);

Project Building

The toolchain for NW.js is rather fragmented - project build/update tools tend to get left to the community rather than be integral to the NW.js project (shows lack of support from bigger companies/stronger developer base).
It would appear that a lot of devs rely on their own custom build arrangements or use customised forks of existing build tools

Build tools:
   nw-builder -> npm package available - CLI app using js - github repo limping along - not very active but sporadic updates.
   nwjs-builder-phoenix -> npm package available - CLI app using js - supercedes nwjs-builder - github repo more active but looking for new maintainer.
   web2executable -> GUI app using Python - github repo no longer maintained

I was using web2executable which worked fairly well but since maintenance has ceased I have migrated to a custom build of nw-builder which underpins a homemade GUI.

Most builders will output a folder with executable files but further packaging (eg: DMG, MSI, EnigmaVB, etc) will require further tools. Many developers will choose CLI tools such as Grunt, Gulp, Yeoman, etc

Update Tools:
   Again Update tools are generally not available with the project and rely on the community to some extent (Electron is well supported in the updating stakes eg: Squirrel).

nw-autoupdater HERE Auto update tool for apps - possibly most current of all the main forks

Signing Tools:
   I don't personally develop for the Mac App Store but tried to incorporate it in my builder GUI however documentation regarding signing is sparse and as a hobbyist I haven't paid the required yearly Developer's Signing Fee from Apple which is a required pre-requisite. The only MAS build for NW.js is using 0.19 (current build - 0.37) and it appears to be a resourcing issue to produce a later version.
It is difficult to differentiate between signing procedures for apps destined for the MAS and those that are distributed via normal download methods. I believe an app can be signed without using the MAS build but again the process is unclear and good examples lacking. It definitely looks like the OSX Gatekeeper will only let an app auto run if a correct signature is found (this means a yearly Developer fee folks).
The GateKeeper blocking is becoming a hassle because the option to allow unsigned apps in Sys Prefs has been removed in High Sierra (identified developers only) and unsigned apps will have to be manually authorised by the user on the first run.

Content Verification is also thrown into the mix and this works with caveats.
This basically provides a couple of files (verified_contents.json/computed_hashes.json) within the app that are used by NW.js to determine if content files have been altered. I can get it to work but due to outstanding bugs (#6540/#6541) implementation can't be done using just the latest build.

Current braindump for NWB hacking and NWjs building - HERE

Download modified NW-Builder CLI project source (ZIP) HERE (MIT)

This project underpins my GUI builder but have yet to get to grips with GitHub repos (since I don't develop on GitHub) so neither project will appear there yet.

Important Changes

0.13.0 - Architectural changes (major)

0.14.7 - Last XP supported build

0.19.5 - MAS build available (this is still latest available!)

0.21.0 - CSS Grid supported

0.22.0 - Architectural change (symlinks used in nwjs Framework.framework bundle - upstream change)

0.22.1 - MP3 codec included - (patents expired)

0.23.0 - Headless Chromium supported

0.23.0 - Dramatic performance improvement with Source Code protection

0.24.4 - Helper Renaming supported - uses product_string parameter in package.json (if running an app using the standard nwjs binary this needs to be set as 'nwjs' otherwise should be the app name when packaged).

0.25.0 - Architectural change (minor - libffmpeg location moved up to parent folder)

0.25.2 (node 8.5.0) - fs.copyFile/copyFileSync supported

0.26.0 - Min OSX 10.9 required

0.29.0 - Widevine supported

0.29.0 - Min OSX 10.10 required

0.35.4 - Architectural change(optional) - moves NW application window implementation from Chrome App window to Chromium browser window (only with --enable-features=nw2 switch)

0.36.0 - Minor architectural change - libffmpeg in OSX moved back into nwjs Framework.framework as 10.9 no longer supported

0.38.0 - Fix/enhancement change - quoted arguments on POSIX command line (OSX/Linux)

0.40.0 - Folder architectural change - Frameworks folder moved to Contents (as per 0.12) and Versions now subset of nwjs Framework.framework, Helper binaries separated into subtasks (GPU/Plugin/Renderer)
0.42.4 - Architectural - nw2 now default - switch no longer required (--disable-features=nw2 can be used to use old mode in the interim)

0.42.5 - Layout change - Window height changed (now specifies inner dimension exclusive of 22px titlebar in MacOS)

0.44.0 - Feature - Full page screenshot/silent autoprint

0.47.1 - Fix - MP4 working again - regression break at 0.45.0

0.47.3 - Feature - Last version with full Flash support

0.48.0 - Flash broken (audio OK but visual no good)(Adobe withdrawing Flash support as at Dec 2020)

0.50.1 - Flash working again (Adobe withdrawing Flash support as at Dec 2020)

0.51.0 - Min OSX 10.11 (El Capitan) required. Flash removed from NW.js/Chromium as at Dec 2020)

0.64.1 - Min OSX 10.15 (Catalina) required. Change due to node 18 requirement)

Application Package Renaming

eg: App name is foobar

package.json --> new parameter --v
      product_string: foobar

Contents/Info.plist - CFBundleDisplayName --> update to foobar
Contents/Resources/en.lproj/InfoPlist.strings - CFBundleDisplayName --> update to foobar

Prior to 0.40 -
Contents/Versions/n.n.n.n/nwjs Helper --> rename to 'foobar Helper'
Contents/Versions/n.n.n.n/nwjs --v
      - CFBundleDisplayName --> update to foobar
      - CFBundleExecutable --> update to foobar (avoid broken icon on Helper package)
      - CFBundleName --> update to foobar
Contents/Versions/n.n.n.n/nwjs --> rename to 'foobar'

Since 0.40 -
Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper --> rename to 'foobar Helper'
Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs --v
      - CFBundleDisplayName --> update to foobar
      - CFBundleExecutable --> update to foobar (avoid broken icon on Helper package)
      - CFBundleName --> update to foobar
Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs --> rename to 'foobar'

Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (GPU).app/Contents/MacOS/nwjs Helper (GPU) --> rename to 'foobar Helper (GPU)'
Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (GPU).app/Contents/Info.plist --v
      - CFBundleDisplayName --> update to foobar
      - CFBundleExecutable --> update to foobar (avoid broken icon on Helper package)
      - CFBundleName --> update to foobar
Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (GPU).app --> rename to 'foobar Helper (GPU).app'

Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Plugin).app/Contents/MacOS/nwjs Helper (Plugin) --> rename to 'foobar Helper (Plugin)'
Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Plugin).app/Contents/Info.plist --v
      - CFBundleDisplayName --> update to foobar
      - CFBundleExecutable --> update to foobar (avoid broken icon on Helper package)
      - CFBundleName --> update to foobar
Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Plugin).app --> rename to 'foobar Helper (Plugin).app'

Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Renderer).app/Contents/MacOS/nwjs Helper (Renderer) --> rename to 'foobar Helper (Renderer)'
Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Renderer).app/Contents/Info.plist --v
      - CFBundleDisplayName --> update to foobar
      - CFBundleExecutable --> update to foobar (avoid broken icon on Helper package)
      - CFBundleName --> update to foobar
Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Renderer).app --> rename to 'foobar Helper (Renderer).app'

Widevine Support

Sourcing -

OSX - included in NWjs but is in libraries folder in versions branch
Win32 - Chrome Downloads - install and see below
Win64 - Chrome Downloads - install and see below
Linux32 - Chrome Downloads - unavailable
Linux64 - Chrome Downloads - google-chrome-stable_current_amd64.deb - unzip and drill data.tar.xz folder - data/opt/google/chrome/

- OSX:

      Contents/Versions/66.0.3359.117/nwjs Framework.framework/Libraries/WidevineCDM/ ( package)

- On 64-bit windows:

      C:\Program Files (x86)/Google/Chrome/Application/66.0.3359.117/WidevineCDM/

- On 32-bit windows:

      C:\Program Files/Google/Chrome/Application/66.0.3359.117/WidevineCDM/

Application Start Modes

Apps generally start from NW.js binary looking up the package.json (manifest) file and checking the "main": setting.
   "main": "index.html", --- app will start in browser context with the html page and css/js will be introduced in normal web fashion.

   "main": "js/app.js", --- app will start in node/javascript context and html pages are generated via etc.

(Electron tends to use the JS start method, NW.js default is HTML but is happy with either).

I tend not to use the CLI very much during development but NW.js is easy to use in a GUI environment
eg: an app called hippo (this example assumes MacOS) -

hippo - appfolder

Place the NW.js package into the appfolder and double click - it will look for the manifest and start according to the 'main' setting.
Since v0.24.4 it is important that the manifest 'product_string' setting is 'nwjs' otherwise NW.js will start but the app will not operate.

When the app is packaged (with nw-builder or suchlike) the app name will probably change (in this case - "name": "hippo", "product_string": "hippo",) but the app copy of NW.js will have been updated with the new name. If the package is opened the folder structure will contain a file called 'hippo Helper' whereas a default NW.js package it would be 'nwjs Helper'.

Node Module Versions

NPM will install node modules according to the version of node on the machine. NWjs has an inbuilt node version which will change according to the version build of NWjs. In many cases NWjs will run with node modules installed with a different version but some are picky (eg: appdmg) so the best results will be obtained if the node modules used by the NWjs app are installed with the same node version.
NPM allows for running different node versions on the machine.

eg: Terminal shows - Expected 47, got 46 (also sometimes 57, got 46)

Can happen if node that npm is using is upgraded and the installed modules haven't been upgraded.
eg: node v4.2.2 (46) on system was upgraded to v8.1.3 (57)- a module (appdmg) had been installed in a project with npm using 4.2.2 and when npm was running on 8.1.3 the error occurred.
The fix was to re-install the appdmg module with npm running 8.1.3

46 - 4.x ---
47 - 5.x --- 0.13 ~ 0.14.7
48 - 6.x --- 0.15.0 ~ 0.17.6
51 - 7.x --- 0.18.8 ~ 0.23.0
57 - 8.x --- 0.23.0 ~ 0.26.2
59 - 9.x --- 0.26.3 ~ 0.30.1
64 - 10.x --- 0.30.2 ~ 0.33.4
67 - 11.x --- 0.34.0 ~ 0.38.0
72 - 12.x --- 0.38.1 ~ 0.42.0
79 - 13.x --- 0.42.1 ~ 0.45.2
83 - 14.x --- 0.45.3 ~ 0.49.1
88 - 15.x --- 0.49.2 ~

Web Components/Frameworks

There is obviously a large number of good frameworks/components out there particularly for commercial/professional apps but for my personal use I tend to look to open-source/community offerings which can be excellent.
It should be noted that some of the packages available in the open-source arena may not have the best support and will be more suited to experienced developers/coders who need less assistance
It is also fair to say that a lot of components are aimed more toward the mobile UI rather than Desktop

I've tried the following reasonably successfully.

Useful stuff for building GUI's -

W2UI 1.5rc1 - Very good selection of components - based on jQuery
Status: MIT license - available to the community - repo on GitHub

  • Good demos
  • Themeable
  • API docs are sufficient
  • No forum (have to sift site for info or try Stack Overflow)
  • Last Blog entry - December 12, 2015

W2UI site HERE

PrimeUI - Very good selection of components - based on jQueryUI
Status: Apache License 2.0 - available to the community (leverages off commercial offerings) - repo on GitHub

  • Good demos
  • Themeable
  • API docs are sufficient
  • Forum could be more active, often slow or no response - appears developers are understandably more focused on their commercial offerings (PrimeUIPro/PrimeFaces/PrimeReact/PrimeNG)
  • PrimeUI is moribund in favour of PrimeVue
  • Good widgets for desktop use not necessarily optimised for mobile only

PrimeUI site HERE

AlloyUI 3.0 - Based on YUI3 - very good range of components (some not seen in other collections)
Status: BSD License - available to the community (no longer being developed as YUI3 is deprecated) - repo on GitHub

  • Good demos
  • Still usable but wouldn't advise for commercial/professional use going forward
  • API docs are sufficient

AlloyUI site HERE

Syncfusion - Community version - very good range of components
Status: License - available to the community (unless revenue threshold is exceeded)

  • Good demos
  • Licensing may alter but at the moment JS libraries are still available to community
  • API docs are sufficient

Syncfusion site HERE

Native type UI components:

Photon - Mac OS style - small range of components
Status: MIT - repo on GitHub - not maintained.

Photon site HERE

A later fork exists for Photon Components but these are optimised for Electron but a bit of hacking will allow some of them to work OK on NW.js

Some others that I haven't tried but look quite good -

PrimeVue - c. 75 components (similar components to PrimeUI but with some gaps filled - more aligned with commercial offerings like PrimeFaces)
Status: MIT License - available to the community - repo on GitHub

PrimeVue site HERE

React Desktop - Mac/Win10 components - small range
Status: MIT - repo on GitHub - looking for maintainers.

Status: MIT License - available to the community - repo on GitHub

Vue Dark Mode site HERE

Buefy - based on Bulma and Vue
Status: MIT License - available to the community - repo on GitHub

Buefy site HERE

Quasar - based on Vue
Status: MIT License - available to the community - repo on GitHub

Quasar site HERE

ToastUI - good selection of components - based on Vue?
Status: MIT License - available to the community - repo on GitHub

  • Good demos
  • Uses Google Analytics to monitor framework usage - can be disabled apparently
  • API docs are sufficient

ToastUI site HERE

Another avenue for smaller/home devs is to take advantage of the free offerings from commercial firms where they allow use of the components up to set thresholds of revenue.
Personally I think this is a good idea because if I was getting good revenue from an app I wouldn't mind paying the normal commercial fees but it still gives access of use to the small dev of low/no revenue apps.

SyncFusion - excellent selection of components
Status: Community License - need to login to SyncFusion
The Syncfusion Community License is available to individual developers or up to five users at companies with annual gross revenue below $1 million USD (plenty of scope for the small user here).

Sencha ExtJS - excellent selection of components
Status: Community License - need to login to Sencha
The Sencha ExtJS Community License is available to individual devs/small devs or up to five users with a $10000 USD threshold - the components are the webby type rather than the classic which are not included.


Dev tools are available within NW.js (SDK version) using the Chromium inbuilt dev tools.

Normally on a right-click the context menu will give two options -

   Inspect - this shows the client context and content may vary according to window being inpected
   Inspect Background Page - this shows the node context and will be consistent across windows

The application profile is normally found in -
   Mac - /Users/USER/Library/Application Support/APPNAME eg: /Users/USER/Library/Application Support/hippo
   Win -
   Lin -

The application folder name is specified by the package.json eg: NW.js default is nwjs
Unexplained occurrences whilst debugging/running apps can sometimes be fixed by deleting this profile - a new profile will be generated when the app is started.

Since the product_string parameter was introduced to the package.json (manifest) to allow renaming of the app processes it is possible that the NWjs app starts and sits in the dock but no window will show - this comes about because of a mismatch between the app name and the naming of the internal Helper files.

eg: An app called hippo if correctly packaged will have an internal helper name of hippo Helper however if the app name is hippo and the helper file is still the default nwjs Helper then this issue will occur. Likewise if NWjs is being used within the source folder to run the app then the product_string setting in the manifest will have to be nwjs or the issue will occur.

Databases (SQLite)

Using SQLite 3 can be tricky - I found that getting versions working between node versions was messy and I definitely don't want to go down the road of re-building the binary with node-gyp and all that stuff so I tend to use dblite.

Basically dblite is a wrapper that uses an existing sqlite3 binary - the module does not provide its own. It is available on NPM and has a GitHub repo - it makes working with sqlite super easy with no hassle.

I have found that dblite works with the SQLite Tools binaries very well on MacOS (yet to try Win) - to upgrade the sqlite just re-download sqlite-tools and install.
If the dblite.bin is not specified then dblite will use the system installed binary - it works OK with a standalone copy of the binary also.

Example for OSX -
   Download sqlite-tools from eg: (v 3.27.2)
   Install sqlite executable to desired location
   npm install --save dblite (--save will write the version into the application package.json dependencies section and dblite will be placed in the node_modules folder)

Code -
var dblite = nw.require('dblite');

dblite.bin = 'data/bin/sqlite3-tools-osx/sqlite3

db = dblite('data/hippo.db'); (or whatever path to db - if db does not exist it will be created)

Typical commands:

db.query('.version'); // OK
// various status eg: headers, mode, separators, echo, etc - OK
db.query('.show'); // OK

db.query('.databases'); // OK

db.query('.tables'); // OK

db.query('.dbinfo'); // OK

db.query('.dump'); // OK

db.query('.read hippo.sql'); OK (will restore the hippo database from SQL file)

db.query('.read hippo address.sql'); OK (will restore the address table to the hippo database)

db.query('.cd /Users/USER/Desktop/DBLite'); // OK

db.query('.clone'); // OK

db.query('.backup'); // OK

db.query('.import'); // OK

db.query('SELECT * FROM cars'); // OK

Some .commands don't appear to work

db.query('.once hippo.csv'); // Hangs but produces file with SUPER_SECRET string included

db.query('.output hippo.csv'); // Hangs but produces file with SUPER_SECRET string included

db.query('.dump hippo.sql'); // Hangs but produces file with SUPER_SECRET string included

db.query('.mode'); // column/line/list/tabs OK --- ascii/csv/html/insert/quote/tcl Fail
It looks like dblite is set up so .mode is not used and the csv is the preferred type.

The once/output options to file seem to hang so to create csv/dump files the data will have to be processed from the output of the SELECT statements or .dump output can be processed via the 'info' listener that dblite provides.
Most of the .commands will provide output via the info listener which appears in the background context and can be processed into the client context.

I find that dblite is working OK for me but if you wish to use IndexedDB then dexie.js may be worth a look.

UI Design - Widgets

NW.js is excellent for desktop applications but can also be used for widget style apps that use transparency (ie: a frameless window with only the app body skinning visible.

Widgets tend to do things differently to normal desktop apps -

   Frameless window is used so transparency is often invoked in the layout

   Normal window controls are not available so these need to be provided if necessary within the app

   Normal window menus may not be available so more use of context menus occurs (OSX still has the native menus as they are not window based)

Basic widget settings

The manifest (package.json) holds the basic main window setup -

   "frame": false
   "transparency": true

Transparency ClickThrough also requires -
   "resizable": false
   "chromium-args": "--disable-gpu --force-cpu-draw" (pre - 0.28)
   "chromium-args": "--disable-gpu-compositing --force-cpu-draw" (since 0.28)

Moving/dragging widgets

Quite a simple method that often works is to use CSS classes eg:

.draggo {
   -webkit-app-region: drag;
   user-select: none;

.nodraggo {
   -webkit-app-region: no-drag;
   user-select: none;
   -webkit-user-drag: none;

Apply the draggo class to an element that covers most of the widget and apply the nodraggo class to the elements that you want to interact with (click a button, etc).
A context menu can be used with right-click on any of the non-draggable items.

No drag is quite important on areas that contain images otherwise you will get ghostly drags from the app onto the desktop for example.


Because the runtime of any NW.js app essentially is the Chromium browser the windows will tend to act like normal web pages so unless steps are taken then some functions will occur that whilst desirable in a web arena may not be wanted in the desktop world. Draggable objects are a case in point - the above code shows how to avoid dragging within the app but does not handle the case of files/objects being dragged onto the app from elsewhere. In the web world the window would be replaced by the new content (if compatible) and in the case of a desktop app this will also occur therefore deep-sixing the app!

The following code can help to prevent dragged files taking over the app UI -

   document.addEventListener('dragover', function(e){
   }, false);

   document.addEventListener('drop', function(e){
   }, false);

This code needs to be placed against any window within the app.

Alternative approach

Rather than use the listeners the following can be done -

Place ondragstart="return false;" ondragenter="return false;" ondragover="return false;" ondrop="return false;" into the body tag

Note: There may be occasions when the app requires a Drag and Drop area within the UI so placing either of these solutions against the BODY will stop all DnD. In this case the solutions can be applied against a wrapping div that holds the app html and the DnD input cotrol is placed outside the wrapping div.


   <div id="shell">
     <div id="attachdnd">
       <p id="newLabel">Attachments<br />Choose or Drop file</p>
       <!-- Input control is place outside the shell div to allow DnD (attachFileName) -->

   <<input type="file" id="attachFileName" name="files[]" nwdirectory multiple />
   <<output id="list"></output>

document.body.div>shell.addEventListener(etc ... - listeners placed against the shell div and input will accept DnD


<div id="shell" ondragstart="return false;" ondragenter="return false;" ondragover="return false;" ondrop="return false;"> - modified shell div tag

UI Design - Desktop Style

The app content of the window generally should not be subject to swiping actions as per the web world so overflow: hidden; against the body tag can be used to make the window content solid.

Pollution of the app UI by dragged files/objects, as outlined above, is avoided using the same method as for widgets.

Window Sizing - eg: 640w x 480h px

   Mac - overall height excludes titlebar - so 640w x 480 + 22px (this is correct as of 0.42.5)
   Win - 640 x 480

Emoji sheets

Not necessarily NW.js but I had occasion to incorporate the quill-emoji node module into one of my apps and was disappointed with the hamburger.🍔 (newer version)

As it turned out the module uses early IOS versions of the emoji's and I wanted the later hamburger from IOS 9 or so - this required new sprite sheets and updated CSS/JS files.
This is the saga -

:: Updating quill-emoji sprite sheets ::
Source material

     Use EmojiPedia web page ( as source (in logical groupings starting with emoticons).

     Save As Webpage Complete named images.html

     Massage html to extract img src lines to file (use .js code function - 3180 lines at last count)

The JS code in this file HERE will produce a massaged html file which contains an img line for each emoji in order.

The images-massaged.html file is then used via the Terminal (using headless Chrome to produce the sprite sheets).

Create Sprite Sheets

     Split images-massaged.html page (difficult to render all images otherwise) and do two runs.
       Note: this is necessary if window sizes get too large.

     Use headless Chrome to convert html to transparent images -

"/Applications/Google Chrome" --headless --screenshot --window-size=5312,6048 --default-background-color=0 --run-all-compositor-stages-before-draw apple1.html (96 - 53 across/60 down)

"/Applications/Google Chrome" --headless --screenshot --window-size=5312,6048 --default-background-color=0 --run-all-compositor-stages-before-draw apple2.html (96 - 53 across/60 down)

Apple - "/Applications/Google Chrome" --headless --screenshot --window-size=7040,7936 --default-background-color=0 --run-all-compositor-stages-before-draw a-images-massaged.html (128 - 53 across/60 down)

"/Applications/Google Chrome" --headless --screenshot --window-size=7040,7936 --default-background-color=0 --run-all-compositor-stages-before-draw a-images-massaged2.html (128 - 53 across/60 down)

FaceBook - "/Applications/Google Chrome" --headless --screenshot --window-size=7040,8064 --default-background-color=0 --run-all-compositor-stages-before-draw fb-images-massaged.html (128 - 53 across/60 down)

"/Applications/Google Chrome" --headless --screenshot --window-size=7040,8064 --default-background-color=0 --run-all-compositor-stages-before-draw fb-images-massaged2.html (128 - 53 across/61 down)

As mentioned above the window sizing if using 128px sprites will be getting close to limits so the first half of the produced sheet is generally complete but the later part of the sheet will have missing images and placeholders - the top part of the second sheet can be spliced onto the first to give a complete sheet.

The default background option is important as this allows the sheet to be transparent rather than the browser default white.

Use Pixelmator (or some other app) to join top/bottom image (using layers)
   Need to remove image placeholders on master image and finally apply 1.5% sharpen

The complete sheet can then be reduced in size and used with the quill-emoji module but the directionality and indexing of the sprites will be different to the sheets supplied with the module so the associated quill-emoji.css and quill-emoji.js files will have to be adjusted for the revised sprite mapping.

The JS code in this file HERE will produce CSS/JS code files that can be used in the quill-emoji files.

The .ap class in the quill-emoji.css file can be altered according to your wishes - I was using 128px sprites to give a 40px emoji for my app. The default uses 20px.

.ap {
   background-image: url(1e7b63404cd2fb8e6525b2fd4ee4d286.png);
   background-repeat: no-repeat;
   background-size: 2120px; /* 1060px; 20px size new sheet */ /* 820px; org sheet */
   box-sizing: border-box;
   display: inline-flex;
   font-size: 20px;
   height: 40px; /* 20px; */
   line-height: 1;
   margin-top: -3px;
   overflow: hidden;
   text-indent: -999px;
   width: 40px; /* 20px; */

It is of note that there is a little bit of fudging needed to get the sheets working perfectly (pixel sizing in the main) but this procedure works pretty well.

IMPORTANT: Emojis from firms such as Apple, etc are subject to copyright especially if used commercially so I would recommend any procedures here are used for personal use only.

expander -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- expander