NPAPI And The Hot-Pluggable World Wide Web

In today’s Chromed-up world it can be hard to remember an era where browsers could be extended with not just extensions, but also with plugins. Although for those of us who use traditional Netscape-based browsers like Pale Moon the use of plugins has never gone away, for the rest of the WWW’s users their choice has been limited to increasingly more restrictive browser extensions, with Google’s Manifest V3 taking the cake.

Although most browsers stopped supporting plugins due to “security concerns”, this did nothing to address the need for executing code in the browser faster than the sedate snail’s pace possible with JavaScript, or the convenience of not having to port native code to JavaScript in the first place. This led to various approaches that ultimately have culminated in the WebAssembly (WASM) standard, which comes with its own set of issues and security criticisms.

Other than Netscape’s Plugin API (NPAPI) being great for making even 1990s browsers ready for 2026, there are also very practical reasons why WASM and JavaScript-based approaches simply cannot do certain basic things.

It’s A JavaScript World

One of the Achilles heels of the plugin-less WWW is that while TCP connections are easy and straightforward, things go south once you wish to do anything with UDP datagrams. Although there are ugly ways of abusing WebRTC for UDP traffic with WASM, ultimately you are stuck inside a JavaScript bubble inside a browser, which really doesn’t want you to employ any advanced network functionality.

Technically there is the WASI Sockets proposal that may become part of WASM before long, but this proposal comes with a plethora of asterisks and limitations attached to it, and even if it does work for your purposes, you are limited to whatever browsers happen to implement it. Meanwhile with NPAPI you are only limited by what the operating system can provide.

NPAPI plugin rendering YouTube videos in a Netscape 4.5 browser on Windows 98. (Credit: Throaty Mumbo, YouTube)
NPAPI plugin rendering YouTube videos in a Netscape 4.5 browser on Windows 98. (Credit: Throaty Mumbo, YouTube)

With NPAPI plugins you can even use the traditional method of directly rendering to a part of the screen, removing any need for difficult setup and configuration beyond an HTML page with an <embed> tag that set up said rendering surface. This is what Macromedia Flash and the VLC media player plugin use, for example.

These limitations of a plugin-less browser are a major concern when you’d like to have, say, a client running in the browser that wishes to use UDP for something like service discovery or communication with UDP-based services. This was a WASM deal breaker with a project of mine, as UDP-based service discovery is essential unless I wish to manually mash IP addresses into an input field. Even the WASI Sockets don’t help much, as retrieving local adapter information and the like are crucial, as is UDP broadcast.

Meanwhile the NPAPI version is just the existing client dynamic library, with a few NPAPI-specific export functions tagged onto it. This really rubs in just how straightforward browser plugins are.

Implementing It

With one’s mind set on implementing an NPAPI plugin, and ignoring that Pale Moon is only one of a small handful of modern browsers to support it, the next question is where to start. Sadly, Mozilla decided to completely obliterate every single last trace of NPAPI-related documentation from its servers. This leaves just the web.archive.org backup as the last authoritative source.

For me, this provided also a bit of an obstacle, as I had originally planned to first do a quick NPAPI plugin adaptation of the libnymphcast client library project, along with a basic front-end using the scriptable interface and possibly also direct rendering of a Qt-based GUI. Instead, I would spend a lot of time piecing back together the scraps of documentation and sample projects that existed when I implemented my last NPAPI plugin back in about 2015 or 2016, back when Mozilla’s MDN hadn’t yet carried out the purge.

One of the better NPAPI tutorials, over on the ColonelPanic blog, had also been wiped, leaving me again with no other recourse than to dive into the archives. Fortunately I was still able to get my hands on the Mozilla NPAPI SDK, containing the npruntime headers. I also found a pretty good and simple sample plugin called npsimple (forked from the original) that provides a good starting point for a scriptable NPAPI plugin.

Starting With The Basics

At its core an NPAPI plugin is little more than a shared library that happens to export a handful of required and optional functions. The required ones pertain to setting up and tearing down the plugin, as well as querying its functionality. These functions all have specific prefixes, with the NP_ prefixed functions being not part of any API, but simply used for the basic initialization and clean-up. These are:

  • NP_GetEntryPoints (not on Linux)
  • NP_Initialize
  • NP_Shutdown

During the initialization phase the browser simply loads the plugin and reads its MIME type(s) along with the resources exported by it. After destroying the last instance, the shutdown function is called to give the plugin a chance to clean up all resources before it’s unloaded. These functions are directly exported, unlike the NPP_ functions that are assigned to function pointers.

The NPP_ prefixed functions are part of the plugin (NP Plugin), with the following being required:

  • NPP_New
  • NPP_Destroy
  • NPP_GetValue

Each instance of the plugin (e.g. per page) has its own NPP_New called, with an accompanying NPP_Destroy when the page is closed again. These are set in an NPPluginFuncs struct instance which is provided to the browser via the appropriate NP_ function, depending on the OS.

Finally, there are NPN_ prefixed functions, which are part of the browser and can be called from the plugin on the browser object that is passed upon initialization. These we will need for example when we set up a scriptable interface which can be called from e.g. JavaScript in the browser.

When the browser calls NPP_GetValue with as variable an instance of NPPVpluginScriptableNPObject, we can use these NPP_ functions to create a new NPP instance and retain it by calling the appropriate functions on the browser interface instance which we got upon initialization.

Registration of the MIME type unfortunately differs per OS , along with the typical differences of how the final shared library is produced on Windows, Linux/BSD and MacOS. These differences continue with where the plugin is registered, with on Windows the registry being preferred (e.g. HKLM/Software/MozillaPlugins/plugin-identifier), while on Linux and MacOS the plugin is copied to specific folders.

Software Archaeology

It’s somewhat tragic that a straightforward technology like NPAPI-based browser plugins was maligned and mostly erased, as it clearly holds many advantages over APIs that were later integrated into browsers, thus adding to their size and complexity. With for example the VLC browser plugin, part of the VLC installation until version 4, you would be able to play back any video and audio format supported by VLC in any browser that supports NPAPI, meaning since about Netscape 2.x.

Although I do not really see mainstream browsers like the Chromium-based ones returning to plugins with their push towards a locked-down ecosystem, I do think that it is important that everything pertaining to NPAPI is preserved. Currently it is disheartening to see how much of the documentation and source code has already been erased in a mere decade. Without snapshots from archive.org and kin much it likely would already be gone forever.

In the next article I will hopefully show off a working NPAPI plugin or two in Pale Moon, both to demonstrate how cool the technology is, as well as how overblown the security concerns are. After all, how much desktop software in use today doesn’t use shared libraries in some fashion?

16 thoughts on “NPAPI And The Hot-Pluggable World Wide Web

        1. Oh, yes, it is good that they died.

          Do you remember the days when there was a remote code execution vulnerability in the flash player and java runtime environment (the two most prominent NPAPI users I’d say) like every other week and getting all the clients patched was quite some work for every admin.

          1. You guys are kidding, right? 🥲

            Flash, Shockwave, Silverlight etc. sure had its issues but were what kept the traditional, PC-based internet alive!
            The iPhone and iOS basically killed the web-based internet in the western hemisphere!

            And I’m saying that as a Mac user who used Flash on Firefox and IE 5.5 back in the day!
            Both ran fine on a Power Macintosh with Mac OS X when the iPhone came just around the corner..

            For example, as a hobby computer, I had an older 300 MHz iMac G3 in late 2000s that ran MacOS 10.0 “Cheetah” and IE 5.x with Flash Player.
            And it was good enough to watch flash videos without stuttering! 🙂

            Now macOS is being ruined by merging iOS, VisionOS and watchOS into it.
            The iPhone not only hurt the internet, but also the Macintosh platform.
            (Remember when Apple Computer was renamed into Apple inc ?)

            Apple should have stayed with the iPod..
            It would have been better for the world, IMHO!

          2. @Joshua, no, not kidding. I’ve been using Macs since the MacPlus days, and what I remember of Flash, Shockwave, Silverlight in particular was that regardless of where they started from, they came around to be native to Windows, and ported to MacOS (classic and X). As a result, running a video that barely registered in Task Manager would send even an Intel Mac’s CPU/fan into overdrive. That was never going to change, and I was happy to be shot of them.

  1. Didn’t really care for the way this article repeatedly and broadly maligned javascript. It seems like the actual objection is simply that browsers don’t let you do UDP sockets. But after that display of antipathy towards JavaScript, i was really amused by this line “It’s somewhat tragic that a straightforward technology like NPAPI-based browser plugins was maligned”. It’s reasonable and proper that NPAPI and plugins were aligned. Come on!

    The real thing is, why does this have to be part of the browser? I have never wanted to send UDP packets from the browser…it’s really not part of what i use the browser for. TBH, HTML + CSS covers 90% of what i think browsers are good for, and JS seems appropriate to filling in the rest. If HTML + CSS + JS isn’t enough, maybe what you’re trying to do would actually work better outside of the browser? I mean, it sure seems like your plugin is going to be tied to a very specific browser and thus abandon the interoperability that is IMO the raisin d’eater for the browser.

    1. My thoughts exactly. NPAPI was good for its time, opening avenues for testing what people might want to do with web pages. But today? Good riddance.

      If you want to do more than what is reasonably done within a web page, modern browsers have no issues with invoking other applications installed on your computer. Functionally that’s not all that different from what NPAPI does, unless you specifically want your program to show up inside the user’s default web browser.

    2. I second that.

      For reasons beyond my understanding, browser de-facto became an OS within OS, which is weird. Why re-implement something that’s already been implemented in the “main” OS? What was wrong with learning how to program it there instead?

  2. I remember Netscape Navigtor 2! It was my web browser in the Windows 3.1 days!
    Sweet memories of watching embedded QuickTime videos and listening to Real Audio audio clips with a 33k6 modem! ^^
    Thank you Netscape, thank you NPAPI!

  3. As long as there is an “bug bounty” highly intensive type of review of any plugins and that they are “locked” and “signed” by a previously vetted developer. Then perhaps a loosen up but ONLY under such circumstances or it would irresponsible.

  4. I can’t help but think this is one of those, “please, stop, nobody should use a browser for that,” projects. I really feels like people are trying to make browsers do too much. JavaScript made the problem, JIT engines made it bad, and WASM made the problem way worse. It seems like a browser should simply show a webpage. It shouldn’t be used to implement programs and yet people keep doing it.

    1. That mindset sort of already started in the late 90s, I think.
      When IBM realized that native support for OS/2 left a lot to be desired, OS/2 Warp 4.x was turned into a Java platform basically.
      Java and the web browser were either seen or advertised as being the future, basically.

      Still, that future was better than the mobile web we have now.
      I fondly remember when mobile web was kept separate from the real thing.
      Cell phone users had simplified WAP or i-mode sites, rather than the whole web becoming simplified.

Leave a Reply to Greg ACancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.