# Zabbix

- Tool: FlutterFlow
- Difficulty: Intermediate
- Time required: 40 minutes
- Last updated: July 2026

## TL;DR

Connect FlutterFlow to Zabbix by creating a single FlutterFlow API Group pointing at your Zabbix JSON-RPC endpoint (/api_jsonrpc.php) and adding separate API Calls for each method — problem.get, host.get, trigger.get — where the method name lives in the POST body, not the URL. Pass a Bearer token or include the auth field in the body, then map the nested result[] array to FlutterFlow list widgets for a mobile infrastructure monitoring dashboard.

## Build a Mobile Infrastructure Monitoring Dashboard with FlutterFlow and Zabbix

Zabbix is used by operations teams worldwide to monitor thousands of hosts, collect performance metrics, and fire alerts when thresholds are breached. With over 174,000 active deployments and a fully open-source codebase, it is one of the most widely deployed monitoring platforms in the enterprise. A FlutterFlow mobile app backed by Zabbix gives on-call engineers instant visibility into active problems, host status, and recent triggers — all from their phones, without needing to log into the Zabbix web UI.

The defining feature of this integration — and the most common source of confusion — is that Zabbix does not have a traditional REST API with separate URLs for each resource. Instead, everything goes through a single JSON-RPC 2.0 endpoint at /api_jsonrpc.php. The method you want (problem.get, host.get, trigger.get, item.get) is specified as a field inside the POST body, not in the URL path. In FlutterFlow, this means every API Call in your API Group points at the exact same URL, and the only difference between calls is the JSON body content. Getting that model right in your head before you start building is the key to a smooth integration.

Zabbix is free and open-source. Most installations are self-hosted on private infrastructure, which introduces a connectivity challenge: a phone on cellular data cannot reach a server inside your corporate network unless it is exposed through a public HTTPS reverse proxy, a VPN, or a Cloud Function relay. Plan for this before building the FlutterFlow side.

## Before you start

- A running Zabbix instance (version 5.0+ recommended; 6.4+ for bearer token auth) accessible via HTTPS from the public internet or via a proxy
- A Zabbix user account with a limited role (Read access to Hosts and Problems only) and an API token generated in the Zabbix web UI
- A FlutterFlow project with at least one screen
- Basic familiarity with FlutterFlow API Calls and JSON Path response mapping
- (Optional) A Firebase project for a Cloud Function proxy if your Zabbix server is on a private network

## Step-by-step guide

### 1. Create a limited Zabbix API user and generate an API token

Security first: Zabbix API tokens are scoped to a user's permissions. Before creating any token, create a dedicated monitoring-read user so that if the token is ever compromised, an attacker can only read monitoring data, not modify hosts or silence alerts.

In your Zabbix web UI, go to Administration → Users → Create user. Set the username (e.g., flutterflow-reader), choose a strong password, and set the Role to Operator (which grants read access to hosts and problems) or create a custom role with only the permissions you need. Save the user.

Next, generate an API token. In Zabbix 5.4+, go to Administration → API tokens → Create API token. Select the flutterflow-reader user, give the token a name (e.g., FlutterFlow Mobile), set an expiry if desired, and click Add. Copy the token value immediately — Zabbix will not show it again. In Zabbix 6.4+ you can also use this token as a Bearer header (the preferred approach). Older Zabbix versions require passing the token as the auth field in each JSON-RPC request body instead.

Finally, confirm that your Zabbix instance is reachable at an HTTPS URL from outside your network. Test by opening https://your-zabbix/api_jsonrpc.php in a browser on cellular data — you should get a JSON response (not a timeout). If it times out, you need a reverse proxy or Cloud Function relay before continuing.

**Expected result:** You have a Zabbix API token, a limited-permission user, and confirmed HTTPS public reachability for your Zabbix instance.

### 2. Create the FlutterFlow API Group pointing at the JSON-RPC endpoint

In FlutterFlow, click API Calls in the left navigation panel. Click + Add → Create API Group. Name it Zabbix. In the Base URL field, enter your full Zabbix JSON-RPC URL — for example: https://zabbix.yourcompany.com/api_jsonrpc.php. Note: unlike typical REST APIs, the entire URL is the base URL. There are no path segments after it — all calls go to this single URL.

In the Headers tab of the API Group, add two headers that will be shared by all calls in this group:
  Key: Content-Type   Value: application/json
  Key: Authorization  Value: Bearer {{ apiToken }}

Go to the Variables tab and add apiToken (String). This variable will be passed from an App State variable (or hardcoded in App Values for a personal tool) when each call is made. The token never goes into a publicly visible app constant — store it in App State and populate it from a Supabase/Firestore table or from a Cloud Function if you need to keep it off the device entirely.

Note for Zabbix versions older than 6.4: Bearer header auth may not be supported. In that case, remove the Authorization header from the group and include "auth": "{{ apiToken }}" as a field in every request body instead.

```
{
  "baseUrl": "https://zabbix.yourcompany.com/api_jsonrpc.php",
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "Bearer {{ apiToken }}"
  }
}
```

**Expected result:** The Zabbix API Group is created in FlutterFlow with the correct base URL, Content-Type, and Authorization headers. No individual API Calls added yet.

### 3. Add the problem.get API Call and map active alerts

Now add your first real API Call inside the Zabbix group. Click + Add API Call inside the Zabbix group. Name it GetProblems. Set the method to POST and leave the endpoint field empty — all calls hit the base URL directly, so no path is added here.

In the Body tab, choose JSON and enter the JSON-RPC envelope for problem.get:

{
  "jsonrpc": "2.0",
  "method": "problem.get",
  "params": {
    "output": "extend",
    "recent": true,
    "sortfield": ["eventid"],
    "sortorder": "DESC",
    "limit": 50
  },
  "id": 1
}

Go to Response & Test and click Test. A successful call returns a JSON body with a result[] array containing active problems. Each problem object has fields like eventid, name, severity, clock (Unix timestamp), and objectid (host ID). In the JSON Paths section, add:
  $.result[*].name → problemName (String, List)
  $.result[*].severity → severity (String, List)
  $.result[*].clock → triggeredAt (String, List)

You now have a list data source you can bind to a ListView in FlutterFlow. For each item in the list, show the problem name, a severity badge (0=Not classified, 1=Info, 2=Warning, 3=Average, 4=High, 5=Disaster), and a formatted timestamp by converting the Unix epoch in clock to a human-readable date using a Dart Custom Function.

```
{
  "jsonrpc": "2.0",
  "method": "problem.get",
  "params": {
    "output": "extend",
    "recent": true,
    "sortfield": ["eventid"],
    "sortorder": "DESC",
    "limit": 50
  },
  "id": 1
}
```

**Expected result:** The GetProblems call returns a result[] array in the test view. JSON Paths are configured and map severity, name, and triggeredAt as list variables.

### 4. Add the host.get call and build a hosts status screen

Add a second API Call inside the Zabbix group for host data. Click + Add API Call, name it GetHosts, set method to POST, leave endpoint empty. Use the following JSON-RPC body:

{
  "jsonrpc": "2.0",
  "method": "host.get",
  "params": {
    "output": ["hostid", "host", "name", "available"],
    "limit": 100
  },
  "id": 2
}

In the Response & Test tab, map the following JSON Paths:
  $.result[*].name → hostName (String, List)
  $.result[*].available → available (String, List)
  $.result[*].host → hostAddress (String, List)

The available field is an integer: 0 = Unknown, 1 = Available, 2 = Unavailable. Use this to color host rows green for 1, red for 2, grey for 0.

Create a new FlutterFlow screen named Hosts Status. Add a Column with:
- A summary row showing the count of available vs. unavailable hosts (use Dart inline math via a Custom Function if needed, or pull two filtered sets)
- A ListView bound to the GetHosts call, rendering each host as a Card with hostName, hostAddress, and a colored status dot driven by the available value
- A RefreshIndicator widget wrapping the ListView, with its onRefresh action set to re-trigger the GetHosts API Call backend query

Wire this screen into your app's bottom navigation bar alongside the Problems screen built in the previous step.

```
{
  "jsonrpc": "2.0",
  "method": "host.get",
  "params": {
    "output": ["hostid", "host", "name", "available"],
    "limit": 100
  },
  "id": 2
}
```

**Expected result:** A Hosts Status screen is live showing host names and color-coded availability status, refreshable by pull-to-refresh.

### 5. Handle connectivity for private Zabbix servers via a Cloud Function proxy

If your Zabbix server is on a private network (behind a corporate firewall, accessible only on VPN), phones on cellular data cannot reach it directly. The cleanest solution is a lightweight Firebase Cloud Function that acts as a relay: FlutterFlow calls the Cloud Function over public HTTPS, and the Cloud Function calls the internal Zabbix server from within your VPC or over a VPN tunnel.

Deploy a Firebase Cloud Function (Node.js) that accepts the Zabbix JSON-RPC method and params from the FlutterFlow app, forwards the request to the internal Zabbix server with the stored API token, and returns the result. This also keeps the Zabbix API token off the device entirely.

In FlutterFlow, update the API Group base URL from the direct Zabbix URL to your Cloud Function HTTPS endpoint. No other changes are needed — the JSON structure passed to the proxy is the same. Enable CORS in the Cloud Function to support FlutterFlow web builds.

For teams that want even simpler access from mobile, configure a VPN profile on company devices so they can reach the Zabbix server directly without any proxy. Both approaches are valid; the Cloud Function proxy is better for apps deployed to many users without enforced VPN.

```
// Firebase Cloud Function proxy for Zabbix JSON-RPC
const functions = require('firebase-functions');
const axios = require('axios');

const ZABBIX_URL = functions.config().zabbix.url;
const ZABBIX_TOKEN = functions.config().zabbix.token;

exports.zabbixProxy = functions.https.onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');
  if (req.method === 'OPTIONS') { res.status(204).send(''); return; }

  try {
    const payload = {
      jsonrpc: '2.0',
      method: req.body.method,
      params: req.body.params,
      id: 1
    };
    const response = await axios.post(ZABBIX_URL, payload, {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${ZABBIX_TOKEN}`
      }
    });
    res.json(response.data);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});
```

**Expected result:** FlutterFlow successfully calls the Cloud Function proxy, which relays requests to the internal Zabbix server. The Problems and Hosts screens load data on real devices without VPN.

## Best practices

- Use a dedicated Zabbix user with a read-only role (not Super Admin) for the API token — this limits exposure if the token is ever compromised.
- Never exceed the minimum output fields in JSON-RPC params — use output: ["hostid", "host", "name"] instead of output: extend for large host lists to keep responses fast.
- Cache the last fetched problems list in App State so the screen shows data immediately on open, then pull-to-refresh updates it — prevents a blank screen during load.
- Always check Zabbix version compatibility: Bearer header auth (Authorization: Bearer {token}) was added in 6.4; older versions require the auth field in the JSON-RPC body.
- Limit JSON-RPC result sets with a limit parameter (e.g., limit: 50) to keep response times acceptable on mobile — Zabbix can return thousands of records without pagination.
- Display the severity integer as a human-readable label (Disaster, High, Average, Warning, Info) with color coding — raw numbers are meaningless to on-call engineers at 3am.
- For private-network Zabbix servers, use a Cloud Function proxy rather than exposing the server directly to the internet — it also keeps the API token off the device.

## Use cases

### On-call engineer alert dashboard

On-call engineers need to see all active problems the moment they are paged. A FlutterFlow app queries Zabbix's problem.get method every time the screen is opened and shows a list of active alerts with severity color coding — Critical in red, High in orange, Warning in yellow — so the engineer knows at a glance what needs immediate action.

Prompt example:

```
Build an alerts screen that fetches all active Zabbix problems, shows their severity, host name, and time since trigger, and color-codes each row by severity level. Add a pull-to-refresh gesture.
```

### Host health overview for a small infrastructure team

DevOps teams managing a fleet of servers want a quick hosts-up / hosts-down count on their phone. A FlutterFlow app calls Zabbix's host.get method and renders a summary card with total hosts, a breakdown by status (available vs. unavailable), and a scrollable list showing each host's name, IP address, and current availability.

Prompt example:

```
Create a screen showing the total count of monitored Zabbix hosts split into Available and Unavailable groups, with a list of unavailable hosts highlighted in red, each showing hostname and IP.
```

### Trigger history viewer for post-incident review

After an incident, engineers review which triggers fired and when. A FlutterFlow app calls Zabbix's trigger.get method to pull recently fired triggers for a specific host group, displaying trigger description, last change time, and current value — enabling a fast timeline reconstruction on mobile without opening the Zabbix web UI.

Prompt example:

```
Build a trigger history screen that lists the last 20 fired Zabbix triggers for a selected host group, showing trigger name, severity, and the time it last changed state.
```

## Troubleshooting

### Zabbix returns {"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"}} on every call

Cause: The Content-Type header is wrong or missing. Zabbix's JSON-RPC parser is strict — it expects application/json (or application/json-rpc) and rejects requests with a missing or malformed content type.

Solution: In your FlutterFlow API Group headers, confirm Content-Type is set to application/json. If the header is present but the body is not valid JSON, check the Body tab in the API Call for syntax errors — missing commas, unmatched braces, or invalid variable placeholders.

### API Call test succeeds but the ListView on the app screen shows no data

Cause: The JSON Path for the list is incorrect. Zabbix nests all data under $.result[], and if the path is missing the [*] wildcard or is typed as $.results (with an 's'), it returns nothing.

Solution: In the API Call Response & Test tab, verify your JSON Paths use exactly $.result[*].fieldName (not $.results or $.data). Use the Test button in the API Call panel to inspect the raw response and confirm the correct path.

### XMLHttpRequest error when testing the app in the FlutterFlow web Preview

Cause: CORS is being enforced by the browser. Zabbix does not typically set CORS headers for browser clients, so web builds receive a blocked request.

Solution: For web builds, route the API calls through the Firebase Cloud Function proxy described in Step 5. The proxy can set Access-Control-Allow-Origin: * in its response, satisfying the browser. Native iOS/Android builds are unaffected by CORS.

### All API calls return {"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid params.","data":"No permissions to referred object."}}

Cause: The Zabbix API user used to generate the token does not have read permission for the host groups or problem data you are requesting.

Solution: In Zabbix admin, navigate to Administration → Users → your API user → Permissions. Confirm the user's role includes at minimum read access to the host groups containing the hosts you are querying. If your Zabbix uses host group permissions, add the relevant groups to the user's Read access list.

## Frequently asked questions

### Do I need to self-host Zabbix, or is there a cloud version?

Zabbix is primarily a self-hosted, open-source tool. There is no official Zabbix SaaS offering — you install it on your own servers. Some managed Zabbix-as-a-Service providers exist, but they are third-party. The self-hosted nature is why the private-network connectivity challenge is central to this tutorial.

### Why does every Zabbix API call use POST with a body? Doesn't GET /hosts exist?

No. Zabbix uses JSON-RPC 2.0, which routes all operations through a single endpoint (/api_jsonrpc.php) via POST. The operation you want is specified by the method field in the request body — for example, method: host.get. There are no REST-style URL paths like /api/hosts. Every FlutterFlow API Call in your group will point at the same URL with a different JSON body.

### Can I write data to Zabbix from FlutterFlow — for example, acknowledge an alert?

Yes, Zabbix's event.acknowledge method lets you acknowledge or close a problem via the API. Add another API Call to your group with the event.acknowledge method and the eventids and action fields in the params body. Be mindful that write operations are more sensitive — use a separate token with limited write permissions rather than a full admin token.

### The test in the FlutterFlow API Call panel works, but the app shows a loading spinner forever. What is wrong?

This usually means the backend query on the screen is not being triggered correctly. In FlutterFlow, open the screen, select the ListView, go to its Backend Query settings, confirm it is set to API Call → Zabbix → GetProblems (or GetHosts), and verify the apiToken variable is wired to your App State value. Also check that the page does not have an error in the Action Flow that silently prevents the query from firing.

---

Source: https://www.rapidevelopers.com/flutterflow-integrations/zabbix
© RapidDev — https://www.rapidevelopers.com/flutterflow-integrations/zabbix
