Building a better Zabbix frontend

Recently, I ended up looking into Zabbix as a server monitoring solution. I was very impressed, but I felt that the reporting features left something to be desired; they were very robust, but it was hard to get all the information I wanted on one page.

Zabbix’s bulky monitoring screens
Zabbix’s bulky monitoring screens

It was great for monitoring one server on a screen – giving me history of resource usage in pretty graphs and so on – but there really wasn’t a good way to get a view that would give me all of this information in a compact manner for all of the servers I wanted to monitor, at the same time. (Plus, some of the graphs are more than just a little misleading; look at that RAM usage graph! The bottom of the graph is 10 GB – what?!)

So, instead of struggling through Zabbix monitoring using a hilariously bulky system, I took a page out of Phyramid’s book. They used a Node.js server as their monitoring solution, with aprebuilt API client available on GitHub. I thought that was really freaking cool, but there were a few problems that prevented me from implementing an identical solution.


The biggest issue, of course, was that I wasn’t running a Node server, meaning that I couldn’t pull in the zabbix.js library. That meant I had to figure out how to talk to the Zabbix server myself. This was interesting for me, because it meant I had to learn a few different things. First, I had to figure out the Zabbix API itself, which was interesting – the documentation is extensive, but not exactly easy to understand, and the examples are fairly limited. Second, I had to put together something in JavaScript to talk to the API – something of a challenge, because I had no idea where to start with writing my own jQuery plugin. Other problems would arise as the project moved forward, of course, but these were the biggest things that came up immediately.

Learning the API turned out to be a lot easier than I expected. Basically, the only call I needed to actually make to the server was the host.get call. What this one did, when properly filtered, was give me all of the information I needed for every server that I had set up monitoring for, including a full inventory with current usage statistics as well as any errors or alerts associated with the server.

Getting the call to go to the server was a problem, though. My initial implementation of a Zabbix API client was basically just a modification of the Node.js library to make it work in a traditional environment. In fact, it was mostly just plain old JavaScript with a touch of jQuery to do an AJAX call. Was it good? No. But it worked.

My API call returned a bunch of data – quite a bit to sort through, to be honest. It was formatted kind of strangely, too. There were some properties on the top level of the JSON object that it returned, and others that I needed were in an ‘items’ array. Some of these required cycling through multiple entries to get results – like figuring out disk usage when there were multiple hard drives on the system.

The full response that I received from the Zabbix server. So much data to parse through!
The full response that I received from the Zabbix server. So much data to parse through!

I wrote more JavaScript to handle that, naturally. By this time, I’d written more JavaScript than I had for anything I’d ever written before. The page itself was 95% JavaScript (mostly jQuery, to be honest) – the other 5% being the empty div tags that I put the data in! I was able to eventually get everything put together, though, and get it parsed into something usable. All that was left was to get it displaying nicely on the screen.

Displaying the Data

Now that I had all of my Zabbix data, I faced the challenge of actually making it look nice. I settled on a Bootstrap grid layout with meters showing the CPU and RAM usage, with separate text for disk capacities and network stats. Kottenator’s jquery-circle-progress plugin worked really well for the meters – my only frustration was no radial gradients, but at the end of the day that’s really more of a CSS limitation than anything else. It certainly wouldn’t stop me from recommending this plugin.

I wanted to use the meters for disk usage, too, but that just wasn’t an option – some of our servers only had one drive, while others had as many as four. Doing meters wouldn’t have fit nearly as nicely into the grid layout I had planned.

I finished off the first take on the layout with an alert system – whenever something went wrong, like the web service or the server being unreachable, that server’s grid area would flash red, a tornado siren sound would go off, and the screen would display whatever error message that Zabbix threw for that server instead of displaying the meters.

The original frontend design.
The original frontend design.

The first iteration of the display worked fairly well. The data displayed, at least. Unfortunately, it just took up too much real estate per server. I was trying to display the data on a TV hooked up to a Raspberry Pi, and could only fit 8 servers on the screen. It just wasn’t good enough. I had to improve the layout and make it more of an “at-a-glance” display, so I decided to make four major visual changes.


First, I condensed the “Disks” display into a Bootstrap collapsible accordion, meaning that I could just have a button instead of a long list. I went one step further, though – since disk usage is still pretty critical information, I decided it would be best to make sure that critically low disk space would still be visually represented. I used the panel-warning and panel-danger classes to change the color of the button whenever disk usage hit 75% or 90% respectively, and suddenly it became easy to spot potential issues from across the room.

Second, I condensed the text that was displayed for the operating system. Instead of displaying the raw string, I filtered the OS info that Zabbix gave me and output a human-readable string like “CentOS 6.5″ or “Win Server 2008 R2″. I also moved it right next to the name of the server, so everything would appear on one line.

I also swapped the Bootstrap theme to a sleeker, higher-contrast theme, which helped as well; it made it easier to see the board from across the room by providing a bigger difference between the white text and the black background.

Finally, I modified the jquery-circle-progress plugin so that all of the meters were no longer circles – instead, I made them semicircles. This was a bit of a challenge for me, but it both saved space and made the meters more intuitive.

The new Zabbix frontend with all of the changes.
The new Zabbix frontend with all of the changes.

Once I put all of these changes together, it turned out to be a very workable system. We’re now able to display up to 16 servers on the same screen, and it looks pretty beautiful to boot.

We’re currently in the process of getting this display put up on a large screen here in the office so that we can see immediately when a server or web service goes down. So far, it’s been working really well, and I’m excited to put it into production.

Interested in trying it out for yourself? I’ve made a versionavailable for download; please credit me if you use it. If you’re sickened by the awful Zabbix library that I wrote, check out jqZabbix on GitHub; it’s a much more solid Zabbix API client.

I’ve been doing a lot of cool tech stuff recently, so you’ll probably see more blogs in the same vein as this one soon; I’ve already got one planned for MyLeaf, a “what should I read next” application I built for a friend a month or two ago, as well as a preview of my next big project.

22 thoughts on “Building a better Zabbix frontend

  1. Hi Andrew.
    Liked your work. It’s simple and have everything we need for the Zabbix dash.
    Sadly, I can’t get this to work on Zabbix 3.2 appliance.
    I have an empty dark colored page displayed with your credentials.
    Maybe I did something wrong or the script isn’t adopted?
    Will appreciate for any help.

      1. Hello Andrew, i have the same issue in zabbix 3.0, when you said “try updating the version number” on line 162 ( zabbix.authenticate(); ) What do you mean?
        Will appreciate for any help. Thanks

          1. Hi Andrew, thanks for replay, I’ve try the 0.2 release, but the problem continue.

            zabbix = new $.zabbix (‘http://SEVER-IP/zabbix/api_jsonrpc.php’, ‘USER’, ‘PASS’); //Change to your server’s IP, guest to a Zabbix user and the blank to the password
            if(zabbix.getApiVersion() >= ‘3.0.5’) {
            throw new Error(‘Zabbix has been updated, check the new documentation then update the code and Zabbix api version’);
            //API changes can be problematic. The current code seems to work well with 2.2, 2.4 and 2.5 (unreleased, used by version
            zabbix.authenticate(); //this gives us our API key, which gets assigned to the zabbix object

  2. Hi,
    I have the same problem.
    I have Zabbix 3.0.1.
    I pulled the latest revision from Github.
    What can I do?
    Thanks in advanced.

  3. Hello Andrew, thank you for this! The issue I’ve run into is that I can get the page displayed, but the percentage charts stay at 0.0%. I’ve checked to make sure that there is data in zabbix, and All items have data except inactive memory.

    I’m hoping you have a little insight as to the issue, but I am at a loss right now.

    It’s so close to working right now!

    1. Try hitting F12 when the page loads, and see what response you’re getting from Zabbix when the page makes the API call. Is there data in the JSON object that’s being returned or are you getting any errors that might help shed some light here?

  4. Hi I am getting the page to load but there is no data. When I look at the console tab under JS I see the error.
    TypeError: a is undefined
    .each() jquery.min.js:2
    filterHostsAndOutput() zabbixweb:230
    m.Callbacks/j() jquery.min.js:2
    m.Callbacks/k.fireWith() jquery.min.js:2
    .ready() jquery.min.js:2
    J() jquery.min.js:2

    I verified the path and the user creds are accurate.

    1. Odd. I just looked through the code and I can’t see where this would happen. Can you double check to make sure you grabbed the latest revision from GitHub and then if the issue persists, open an issue on the repository?

  5. Hi Andrew,

    Thank you for your code! Looks amazing.
    I’ve had the same issues as the other users (no information, empty response from server) and I managed to solve it (or at least work around it) by commenting out the section for the api version.

    I had the empty screen with only your name and the settings link. I changed the zabbix_library.js to:

    /*this.getApiVersion = function() {
    var self = this;
    var result =‘apiinfo.version’, {});
    self.apiversion = result;
    return result;

    this.authenticate = function() {
    this.rpcid = 0;
    var self = this;
    //if(self.apiversion >= ‘2.4’) {
    var authID =‘user.login’, {
    ‘user’: this.user,
    ‘password’ : this.password
    /*} else {
    var authID =‘user.authenticate’, {
    ‘user’: this.user,
    ‘password’ : this.password
    self.authid = authID;

    So basically I just forced the use of user.login instead of user.authenticate

    1. Nice! Quick question – what version of Zabbix were you running? I’m going to try and implement this this week, want to make sure I maintain backwards compatibility.

    2. You know what, actually, going to just branch the old code and call it a day. Thanks a lot – I’ll credit you in the commit. Appreciate your comment!

  6. I’m using Zabbix 3.0.7 and I read somewhere that they’re using the new zabbix.login() since version 2.4 so that got me on the trail…

    Now I still need to fix the counters but I will get to that this weekend.

    I was thinking of using flags for OS instead of names…that would make it difficult to differentiate between windows server os’s

    Would love to help you on this project…maybe turn it into something more including graphs and stuff?

    1. If I had to guess, this is related to the metrics that the page is looking for not being collected by Zabbix, or being collected under another metric name. Make sure the system.cpu.load, system.cpu.num, system.cpu.util, vm.memory.size[free], vm.memory.size[cached], and vm.memory.size[used] are being reported correctly.

Leave a Reply

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