# native-client is the Node host that lets a browser extension call the desktop

> native-client is a small NodeJS program that implements the native messaging side of browser extensions, so an add-on can open a URL in another browser, hand a file to GIMP or VLC, or drive FFmpeg on Windows, Linux and macOS. It is MPL-2.0 licensed, installed through npm, and it writes manifest files and registry entries that you have to know how to remove.

**andy-portmen/native-client** — Native Messaging component for Windows, Linux, and Mac OS that is written in NodeJS.

- Repository: https://github.com/andy-portmen/native-client
- Website: https://webextension.org/listing/open-in.html
- Stars: 823 · Forks: 515
- Language: JavaScript
- License: MPL-2.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/andy-portmen-native-client

## The half of native messaging that is not in the browser

A browser extension cannot start a desktop program on its own. That is what native messaging is for: the extension writes a message to a local socket or standard input of a helper program, and the helper does the thing on the operating system.

native-client is that helper, written in NodeJS, and the README describes it as a small client that helps extensions communicate with your operating system. The project is by andy-portmen, it is licensed under the Mozilla Public License 2.0 with the COPYING file at the root, and the current version is 1.1.5, published on 2026-10-06, after 1.1.4 in September 2026 and 1.1.3 earlier that month. The last push to the repository was on the same day as the newest release.

The repository is small in the way a helper program should be. There is config.js, which holds the complete list of supported actions along with their official identifiers, host.js, which is presumably the piece that the browser launches, messaging.js for the protocol side, install.sh and prepare.sh for installation, and separate linux/, mac/ and windows/ directories for the platform specific parts. The build badge points at travis-ci.org.

It is worth being clear that this is the desktop half of a two part system. The extension side is yours to write, and the browser side needs the standard native messaging manifest, which is what the installer writes for you.

## Eight actions, from opening a browser to running FFmpeg

The action list in the README is the clearest picture of what the client does, and it is broader than the name suggests.

Four of the entries are about opening a URL in a different browser than the one you are in: open in Firefox, open in Google Chrome, open in IE, and open in Chrome, with open in Edge and open in Safari listed as well. The distinction between Google Chrome and Chrome is in the original list, so the identifiers are not simply a brand list.

Two entries target desktop applications. Open in GIMP photo editor accepts either a URL or a temporary local image file, and the README explains the data-URL case: they are converted to temporary local files and then GIMP is called to open the file. Open in VLC media player takes a URL.

Then there is the Media Converter and Muxer, which covers downloading the FFmpeg media converter, opening FFmpeg, and exporting media files to a temporary directory and then calling FFmpeg.

The complete list, with the official identifiers that the extension side has to send, lives in config.js in the repository, and the README points there rather than repeating the identifiers.

That matters for how you use it. The extension does not call a program by name; it sends an action identifier, and the client resolves that identifier to a command through the config file. If you extend the list, you extend config.js rather than the extension.

## Installing through npm, and the Node requirement that follows

The README documents two installation routes. The first is a video, one for Windows and one for Linux and Mac, which is a sign of how much of the setup is platform specific.

The second is npm, using the separate native-client-npm repository, and it is two commands.

```bash
npm install native-client
npm run install --prefix node_modules/native-client
```

The first command fetches the package, the second runs its install script with the package directory as the prefix.

The notes that follow are the practical part. On Linux and Mac, the installer script only copies the node executable if it is not already defined in the PATH environment variable, so you need an up to date NodeJS on the machine, and that is the single dependency the whole thing rests on. If Node is not present, the client cannot run, and the browser will report a missing host rather than anything that points at Node.

There is also a way to choose where the program lives. On Linux and Mac you can define a custom root directory by adding --custom-dir= to the installer script.

```bash
./install.sh --custom-dir=~/Desktop/
```

That is a small feature with a large effect, because the root directory is what you delete to remove the program, and putting it somewhere obvious makes that possible later.

## On Linux and macOS the removal is two manifest files and a directory

The uninstall notes are unusually specific, and they are the most useful part of the README for anyone who has to support this on a user's machine.

For Linux and Mac, as of version 0.2.1 the installer prints all the directories it creates or inserts scripts into. The mechanism is that two JSON files are inserted into predefined directories and a root directory is created which contains all the files. To remove the program you delete the root directory and delete the two generated manifest JSON files, and the paths to all of these are printed during installation.

For Windows, a directory is created in the %LocalAPPData% location and all the files go into it, and two registry entries are added so that Chrome, Opera and Firefox can find the actual executable. The paths of those registry entries are printed as well, and you can use uninstall.bat to remove the files and the registry entries.

Two things follow from this. First, the installer output is not decoration: it is the only record of where things went, so it should be captured rather than skimmed during a deployment. Second, deleting the application directory on Windows is not a complete removal, because the registry entries survive it, and uninstall.bat is what clears them.

There is one more convenience in the notes. If you do not remember where the files are, you can simply run the installer one more time, because it overwrites all the files, and the printed paths are the same set.

## What the extension has to send, and what it cannot control

Two files in the repository define the contract between the extension and the client, and the README only names them.

config.js carries the complete list of actions and their official identifiers, which is the mapping from a message to a command. messaging.js is the protocol layer, which handles the communication itself. The extension sends an action identifier, and the client runs the corresponding command.

That framing also explains the limits. The client is a launcher, not a supervisor. It opens a browser, hands a file to GIMP, starts VLC, or exports and calls FFmpeg. It does not, on the evidence of the documentation, manage long running processes, return results to the extension, or arbitrate what the launched program does afterwards. A workflow that needs a result back, such as converting a file and then doing something with the result, has to arrange that outside the extension.

The security story is the usual one for this pattern, and the README is not the place to look for it. A native messaging host is a local program that the browser starts on the user's behalf, and it runs with the user's privileges. The configuration decides what it will launch, so a user who can edit config.js can change what the extension can cause to happen on the machine, and the extension itself decides which action identifiers it will use. Anyone deploying this should read the code in host.js and config.js rather than trusting the action list, which is the point of the code being on GitHub and MPL licensed.

## Where native-client is the wrong choice

Three situations argue against it.

The first is an extension that only opens a URL in another browser. That is the common case for the popular add-ons in this space, and the browser can do it without a local process: the extension hands the URL to the operating system's own handler, and the user gets the browser they chose. Requiring a Node runtime, an installer, a manifest registration and a program to be kept in step with the browser versions is a lot of machinery for one action.

The second is a machine without NodeJS. The installer copies a node executable only if one is not already in the PATH, which means the client brings its own runtime, and that runtime is then a piece of software you are shipping to every user and keeping current. On a locked down corporate machine, or one where the user does not want a second Node installation, this is a poor trade.

The third is a task that the browser can now do itself, or that a native addon would do better. Modern browsers can hand a file to the operating system, and for genuinely tight integration with an application, a proper native addon or the application's own command line interface is a better shape than a generic launcher host.

Where it is the right tool is the awkward middle ground: an extension that needs to hand a file to a specific desktop program, or run a media conversion, on a machine where the user is willing to install a helper. For that case it saves you from writing and maintaining a launcher per platform.

## Conclusion

native-client fits a browser extension author who needs to launch a desktop program, hand over a file or convert media, because the native messaging protocol requires a local host program and this is a working one that covers the common targets on three operating systems. It is the wrong choice if the extension only needs to open a URL in another browser, since the browser can do that without a local process, and it is the wrong choice if you cannot accept a NodeJS runtime on the user's machine. Before deploying it, read the installer output because it prints the exact paths it creates, and remember that on Windows the two registry entries are what let the browsers find the executable, so removing the application directory without uninstall.bat leaves them behind.

## FAQ

### How do I install native-client?

Through npm, with npm install native-client followed by npm run install --prefix node_modules/native-client, using the native-client-npm repository. The README also links video instructions, one for Windows and one for Linux and Mac.

### What can the native-client extension open?

The README lists opening a URL in Firefox, Google Chrome, IE, Chrome, Edge and Safari, opening a file or URL in GIMP, opening a URL in VLC, and a Media Converter and Muxer that downloads FFmpeg, opens it and exports media to a temporary directory before calling it.

### How do I uninstall native-client on Linux and macOS?

As of version 0.2.1 the installer prints every directory it creates or writes into. Two generated manifest JSON files are inserted into predefined directories and a root directory holds the files, so you delete that root directory and those two JSON files, using the paths printed during installation.

### What does installing native-client do on Windows?

A directory is created in the %LocalAPPData% location with all the files inside, and two registry entries are added so Chrome, Opera and Firefox can find the executable. The paths of the registry entries are printed during installation, and uninstall.bat removes both the files and the registry entries.

### Does native-client need NodeJS installed?

On Linux and Mac the installer only copies the node executable if one is not already in the PATH environment variable, so an up to date NodeJS is needed. You can also set a custom install root with the --custom-dir= option, for example ./install.sh --custom-dir=~/Desktop/.

## Sources

- [andy-portmen/native-client on GitHub](https://github.com/andy-portmen/native-client)
- [License: MPL-2.0](https://github.com/andy-portmen/native-client/blob/master/LICENSE)
- [Project website](https://webextension.org/listing/open-in.html)
- [README](https://github.com/andy-portmen/native-client/blob/master/README.md)
- [Releases](https://github.com/andy-portmen/native-client/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/andy-portmen-native-client
