Today I came across the news that a famous Chrome extension for JSON formatting changed its business model and instead of being useful free extension, it became adware where it injects ads into many pages. This is actually not uncommon for free extensions specially those on Chrome extension store. Many extensions are free, but they make money by injecting ads into pages or by selling user data.

On Firefox, the situation is a bit better, but still there are many extensions that are not trustworthy. I actually have the default JSON viewer in Firefox and I didn't think before about installing a JSON formatter extension. It is actually tempted, I deal with JSON data a fair amount of time and having to copy or download it to open it with VSCode or some other tool is a bit annoying. But I was hesitant to install an extension from an unknown source or even from a known source that might change its business model or just sell out its users in the future.

Then I thought, how difficult would it be actually to write my own JSON formatter extension for Firefox? I have some experience with web development and Firefox extensions, and so I know that writing a browser extension is not that hard. So I decided to give it a try. I started by defining the scope and the user target which is basically myself. I want a simple and clean interface for formatting JSON, and I will not even distribute it to others via the AMO store (will use personal distribution channel to sign it though). I just want to have it for my personal use, so I would just focus on what features I would need and how to implement them without worrying about the user experience or the security implications of distributing it to others. Although I will still try to make it secure and not do anything that could harm my browser or introduce an attack vector.

So I sat down with a clear mental checklist of what I actually wanted:

As you can see, nothing fancy here, nothing I don't use. The entire project ended up being just four source files: a manifest, a content script, a stylesheet, and build script. No frameworks, no bundlers, no dependencies. Just vanilla JavaScript (that I still hate so much) and some CSS.

The first thing I ran into was something I didn't expect: Firefox already has a built-in JSON viewer. And it intercepts JSON pages before any extension content script can touch them. I loaded my first attempt, navigated to a .json URL, and… Firefox's own viewer showed up instead. Actually to be honest, I knew about the built-in JSON viewer, but I thought that it would be possible to override it with an extension. But it turned out that Firefox's JSON viewer is actually a built-in feature that is not implemented as an extension, and it takes precedence over any extension content script. So I had to find a way to disable the built-in JSON viewer in order to test my extension.

It turns out this is a known issue. Firefox's native JSON viewer runs at a lower level than the WebExtensions content script pipeline. Even if your extension matches <all_urls> and runs at document_start, the browser catches the response first and renders it. Looking at how other popular Firefox JSON viewer extensions handle this, the answer was unanimous: they all (at least the couple I checked) instruct users to manually disable Firefox's built-in viewer in about:config by toggling devtools.jsonview.enabled to false. It's a one-time setting change, and it's the standard approach across the entire Firefox extension ecosystem for this category. Once that's done, the page returns raw JSON text and the content script can take over.

With that solved, the detection logic became straightforward. The content script checks whether the page's content type is JSON, or if the page is a single <pre> element containing parsable JSON. If either is true, it clears the page and builds the viewer from scratch.

Then we come to the tree render question. The tree renderer is recursive. It walks the JSON structure and creates a DOM node for each value. Objects and arrays get a toggle arrow and a hidden children container. Primitives get styled spans with syntax highlighting classes. The indent guidelines are simply the border-left on nested .jf-children containers, so they scale naturally with depth and never overlap with the actual content.

Path tracking is handled by storing the full JSON path (like data.users[0].name) as a data-path attribute on each line. On hover, the path appears in a bar at the bottom. Click the key to pin it. There's a copy button right next to it.

It seems very straightforward, but then we think about security implications. Even though this is a personal extension, I figured it was worth doing a proper security review. After all, the content script runs on every page and processes arbitrary JSON from any server. Here's what I found and fixed:

And as I said before, No clipboardWrite permission needed because Firefox allows clipboard writes from user click handlers by default. So the extension runs with zero elevated permissions. No background scripts, no storage permissions. The content script does everything and only runs on JSON pages. So that's fine for me.

I also wanted a clean build process. I set up a Makefile with shell scripts that verify the manifest.json, check that all icons are valid PNGs, lint the manifest.json structure, and package everything into a .xpi file. A GitHub Actions workflow triggers on version tags, runs the same checks, and creates a release with both the .xpi and a updates.json file that Firefox uses to auto-deploy updates to installed users (Basically me). For the AMO submission, I added data_collection_permissions with required: ["none"] to declare that the extension collects no data, and bumped the minimum Firefox version to 140 since that's when this manifest key was introduced.

This was about few hours of work, and I now have a JSON viewer that does exactly what I need, with zero ads, zero telemetry, and zero trust required in a third-party developer. If I ever want to add a feature, I change it myself. If I ever want to remove one, I remove it. The source code is right there, and it's small enough that I can understand every line in minutes. The full source is on GitHub at MohamedElashri/JSON-formatter if anyone wants to use it, contributions are welcome, but I won't be publishing it on AMO or any other store. You will need to build it yourself and load it as a temporary extension in Firefox. Insructions are in the README.