Skip to main content
RapidDev - Software Development Agency
flutterflow-integrationsFlutterFlow API Call

Prometheus

Connect FlutterFlow to Prometheus using API Calls against the Prometheus HTTP Query API (`/api/v1/query`) — but never expose port 9090 to your app directly. Put a Cloud Function or reverse proxy in front so credentials stay off the device, and parse the `data.result[].value` JSON path to bind PromQL results to widgets.

What you'll learn

  • Why Prometheus's pull-based model means a FlutterFlow app never sends metrics directly to it
  • How to read Prometheus metric values using the HTTP Query API via a backend proxy
  • How to parse the `data.result[].value` response format and bind it to charts in FlutterFlow
  • How to push app-side counters into Prometheus via a Cloud Function and the Pushgateway
  • How to avoid exposing an unauthenticated Prometheus port 9090 to your mobile app
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced16 min read45 minutesAnalyticsLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to Prometheus using API Calls against the Prometheus HTTP Query API (`/api/v1/query`) — but never expose port 9090 to your app directly. Put a Cloud Function or reverse proxy in front so credentials stay off the device, and parse the `data.result[].value` JSON path to bind PromQL results to widgets.

Quick facts about this guide
FactValue
ToolPrometheus
CategoryAnalytics
MethodFlutterFlow API Call
DifficultyAdvanced
Time required45 minutes
Last updatedJuly 2026

Prometheus Is a Pull System — Your App Is Not a Metrics Target

Prometheus works differently from most analytics tools founders encounter. Instead of receiving events that clients push to it, Prometheus periodically scrapes HTTP endpoints (called targets) that expose metrics. Server processes, Kubernetes nodes, and databases expose a `/metrics` endpoint in a specific text format, and Prometheus pulls from those endpoints on a schedule. Your FlutterFlow app — running on a user's phone — cannot be a scrape target because it has no stable public URL and is ephemeral.

This means the integration with FlutterFlow goes in one of two directions. If you want to READ metric data (query your infrastructure counters, gauge values, or alert states) and display them in a FlutterFlow admin screen, you call the Prometheus HTTP Query API with a PromQL expression. The API returns instant vectors (current values) or ranges (time series) as JSON. The catch: your Prometheus server is typically running on an internal network or exposed on port 9090 without authentication — you must put a backend proxy in front before your app can safely call it.

If you want to PUSH app-side counters into Prometheus (for example, counting how many users complete a specific screen in your app), the right tool is the Prometheus Pushgateway. Your Firebase Cloud Function accepts counters from the app, formats them as Prometheus text exposition format, and POSTs them to the Pushgateway at `/metrics/job/<job>`. Prometheus then scrapes the Pushgateway on its normal interval. There is no official Prometheus client SDK for Flutter — the `prometheus_client` pub.dev package targets long-lived server processes, not ephemeral mobile apps.

Integration method

FlutterFlow API Call

Prometheus exposes an HTTP Query API that FlutterFlow can call via an API Group to read instant metric values and time-series data. Because Prometheus has no authentication layer of its own and is typically deployed without auth on port 9090, you must put a backend proxy — a Firebase Cloud Function or a reverse proxy with Basic Auth — between your app and Prometheus. For pushing app-side counters into Prometheus, your Cloud Function writes to the Pushgateway endpoint that Prometheus then scrapes. FlutterFlow calls the proxy, never Prometheus directly.

Prerequisites

  • A running Prometheus server accessible from the internet (or accessible via a Firebase Cloud Function deployed in the same network/VPC)
  • A Firebase project connected to your FlutterFlow app (for deploying the Cloud Function proxy)
  • Firebase CLI installed on your machine, or a developer who can deploy Cloud Functions on your behalf
  • Basic understanding of PromQL — at minimum, a metric name and label selector like `http_requests_total{job="api"}` to query
  • For the Pushgateway write path: a Prometheus Pushgateway instance deployed and accessible from your Cloud Function

Step-by-step guide

1

Secure the Prometheus Endpoint with a Backend Proxy

Before writing a single line in FlutterFlow, you need to address the most critical issue with Prometheus: by default, it runs on port 9090 with no authentication. Pointing your FlutterFlow API Call directly at `http://your-server:9090` would expose your entire metrics database to anyone who reverse-engineers your app. The correct approach is to deploy a Firebase Cloud Function that acts as a proxy. The Cloud Function sits between your FlutterFlow app and Prometheus, and it can enforce its own authentication (Firebase App Check, a shared secret in a request header, or simply being a private function only called from within your Firebase project). Here is a minimal Firebase Cloud Function proxy that accepts a PromQL query parameter from your FlutterFlow API Call, forwards it to the Prometheus Query API, and returns the result: Deploy this Cloud Function to your Firebase project. The Prometheus URL is configured inside the function — it never appears in your FlutterFlow app. If your Prometheus server sits behind a reverse proxy with Basic Auth, add the Authorization header in the Cloud Function, not in FlutterFlow. Alternatively, if you already have a reverse proxy (nginx, Traefik, Caddy) in front of Prometheus with HTTPS and Basic Auth, you can point FlutterFlow's API Group directly at the proxy URL and store the Base64-encoded Basic Auth credentials in FlutterFlow's API Group headers. This is simpler but less secure than the Cloud Function approach because the credentials still ship in your app binary.

index.js
1// Firebase Cloud Function: Prometheus query proxy
2// functions/index.js
3const functions = require('firebase-functions');
4const https = require('https');
5const http = require('http');
6
7// Set PROMETHEUS_URL in Firebase environment config
8// firebase functions:config:set prometheus.url="http://your-prometheus:9090"
9const PROMETHEUS_URL = process.env.PROMETHEUS_URL || 'http://localhost:9090';
10
11exports.prometheusQuery = functions.https.onRequest(async (req, res) => {
12 res.set('Access-Control-Allow-Origin', '*');
13 if (req.method === 'OPTIONS') {
14 res.set('Access-Control-Allow-Methods', 'GET, POST');
15 res.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
16 return res.status(204).send('');
17 }
18
19 const query = req.query.query;
20 const time = req.query.time || Math.floor(Date.now() / 1000);
21
22 if (!query) {
23 return res.status(400).json({ error: 'Missing query parameter' });
24 }
25
26 const targetUrl = `${PROMETHEUS_URL}/api/v1/query?query=${encodeURIComponent(query)}&time=${time}`;
27 const protocol = targetUrl.startsWith('https') ? https : http;
28
29 protocol.get(targetUrl, (promRes) => {
30 let data = '';
31 promRes.on('data', chunk => data += chunk);
32 promRes.on('end', () => {
33 try {
34 const parsed = JSON.parse(data);
35 return res.json(parsed);
36 } catch (e) {
37 return res.status(502).json({ error: 'Invalid response from Prometheus' });
38 }
39 });
40 }).on('error', (err) => {
41 console.error('Prometheus proxy error:', err);
42 return res.status(502).json({ error: err.message });
43 });
44});

Pro tip: Set the Prometheus URL as a Firebase environment variable using `firebase functions:config:set prometheus.url="http://..."` instead of hardcoding it in the function. Retrieve it with `functions.config().prometheus.url`.

Expected result: Your deployed Cloud Function URL returns a JSON response when you call it with a `?query=up` parameter, showing Prometheus data without exposing port 9090 to the internet.

2

Create the API Group and API Call in FlutterFlow

With your Cloud Function proxy deployed and tested, you can now set up the FlutterFlow side of the integration. Click 'API Calls' in the left navigation panel (the plug icon), then click '+ Add' and select 'Create API Group'. Give it a name like 'PrometheusProxy', set the Base URL to your deployed Cloud Function URL (for example, `https://us-central1-your-project.cloudfunctions.net`), and leave the authentication type as 'No Auth' since your Cloud Function handles security internally. Next, click '+ Add API Call' within the new group. Name it 'QueryInstant'. Set the method to GET and the endpoint path to `/prometheusQuery` (matching your function name). In the Variables tab, add a variable named `query` of type String — this is where your PromQL expression will go. In the URL tab, add it as a query parameter: `?query={{query}}`. In the Response & Test tab, paste a sample Prometheus API response. A typical instant query response looks like the JSON below. Click 'Test API Call', enter a test PromQL expression in the query field (for example, `up` to see which targets are up), and confirm you get back a result. Then click 'Generate JSON Paths' to automatically extract paths like `$.data.result[0].value[1]` (the metric value as a string) and `$.data.result[0].metric.instance` (the target label). Name these paths clearly — for example, 'metricValue' and 'instanceLabel' — so you can bind them to widget properties. Important: Prometheus returns metric values as strings inside JSON arrays — the format is `[unix_timestamp, "string_value"]`. You will need to convert the string to a number before displaying it in a numeric widget or chart. Use a FlutterFlow Custom Function (left nav → Custom Code → + Add → Function) to parse the string to a double.

sample_response.json
1// Sample Prometheus instant query API response
2// GET /api/v1/query?query=http_requests_total
3{
4 "status": "success",
5 "data": {
6 "resultType": "vector",
7 "result": [
8 {
9 "metric": {
10 "__name__": "http_requests_total",
11 "instance": "localhost:8080",
12 "job": "api-server",
13 "method": "GET",
14 "status": "200"
15 },
16 "value": [
17 1704067200,
18 "1234.0"
19 ]
20 }
21 ]
22 }
23}

Pro tip: When creating JSON Paths for the value field, target `$.data.result[0].value[1]` to get the metric value string. For multiple time series (multiple targets), you'll need to loop through `$.data.result[*]` and use a list widget.

Expected result: The API Call test in FlutterFlow returns a 200 response with Prometheus data, and the generated JSON Paths correctly extract the metric value from the response.

3

Parse String Values and Bind to Chart Widgets

Prometheus metric values arrive as strings inside JSON arrays (the format `[unix_timestamp, "string_value"]`), which means you cannot directly bind them to a number widget or a chart data series without type conversion. If you try to bind the raw string path to a Chart widget, it will show NaN or fail to render. Create a Custom Function to handle the conversion. Go to left nav → Custom Code → + Add → Function. Name it 'parseMetricValue'. Set the return type to Double and add one argument named 'rawValue' of type String. Paste the Dart function body that parses the string to a double (see code block). Save it — FlutterFlow will compile it into your project. Now bind your API Call data to widgets. Select a Text widget on your screen and set its value to the API response variable. In the data binding popup, choose the API Call response → select the JSON path for the value field → apply the 'parseMetricValue' custom function transformation. The widget will now display a proper number. For time-series data (using `/api/v1/query_range` instead of `/api/v1/query`), the response contains an array of `[timestamp, value]` pairs. You'll need to map these into a list of FlutterFlow chart data points. This is more complex and typically requires a Custom Action that transforms the API response array into the format expected by the FlutterFlow Chart widget or a custom charting package. For simple use cases — showing a single current metric value in a stat card — the instant query API and a single JSON path binding with the custom function is all you need. For rich time-series charts showing metric history, consider using a Grafana embed via Custom Widget instead, since Grafana already handles PromQL visualization natively.

custom_function.dart
1// Custom Function: parseMetricValue
2// Convert Prometheus string metric value to double
3// Arguments: rawValue (String)
4// Return type: double
5double parseMetricValue(String rawValue) {
6 if (rawValue.isEmpty) return 0.0;
7 final parsed = double.tryParse(rawValue);
8 if (parsed == null) return 0.0;
9 // Handle Prometheus special values
10 if (parsed.isNaN || parsed.isInfinite) return 0.0;
11 return parsed;
12}

Pro tip: For displaying multiple metrics at once (for example, CPU across 5 servers), use a FlutterFlow List widget with the API Call response as its data source, and bind the metric label and value fields to each list item's Text widgets.

Expected result: A Text or stat card widget on your screen correctly displays a numeric metric value (not a string or NaN) fetched from Prometheus via the proxy API Call.

4

(Optional) Push App Counters to Prometheus via Cloud Function and Pushgateway

If you want app-side events (like 'user completed onboarding') to appear in Prometheus alongside your infrastructure metrics, the Pushgateway is the correct mechanism. The Pushgateway is a separate component — you need it deployed alongside Prometheus — that acts as an intermediary store. Prometheus scrapes the Pushgateway, and anything pushed there becomes available as a normal metric. The flow is: FlutterFlow API Call → Firebase Cloud Function → Pushgateway. The Cloud Function accepts a counter increment request from your app, formats it in Prometheus text exposition format, and POSTs it to `http://your-pushgateway:9091/metrics/job/<job_name>`. Prometheus scrapes the Pushgateway on its normal interval (typically every 15-30 seconds). In FlutterFlow, set up a new API Call in your PrometheusProxy API Group pointing to a new Cloud Function endpoint (for example, `/pushMetric`). Pass the metric name, value, and any labels as query parameters or JSON body. Call this API Call from your Action Flow at the moment you want to record the event. Important limitations to understand: Pushgateway metrics persist until explicitly deleted — if you push an `app_users_onboarded_total` counter of 5, it stays at 5 even after the user closes the app. Pushgateway is designed for batch jobs (short-lived processes that finish and exit), not real-time per-user event streams. High-cardinality labels (a unique label per user) will cause Prometheus memory issues — keep labels to low-cardinality categories only.

index.js
1// Firebase Cloud Function: push metrics to Pushgateway
2// functions/index.js (add this alongside the query proxy)
3const PUSHGATEWAY_URL = process.env.PUSHGATEWAY_URL || 'http://localhost:9091';
4
5exports.pushMetric = functions.https.onRequest(async (req, res) => {
6 res.set('Access-Control-Allow-Origin', '*');
7 if (req.method === 'OPTIONS') {
8 res.set('Access-Control-Allow-Methods', 'POST');
9 res.set('Access-Control-Allow-Headers', 'Content-Type');
10 return res.status(204).send('');
11 }
12
13 const { metricName, value, jobName, labels } = req.body;
14 if (!metricName || value === undefined || !jobName) {
15 return res.status(400).json({ error: 'metricName, value, and jobName are required' });
16 }
17
18 // Build Prometheus text exposition format
19 let labelStr = '';
20 if (labels && typeof labels === 'object') {
21 const parts = Object.entries(labels).map(([k, v]) => `${k}="${v}"`);
22 labelStr = `{${parts.join(',')}}`;
23 }
24 const metricsBody = `# TYPE ${metricName} counter\n${metricName}${labelStr} ${value}\n`;
25
26 const pushUrl = `${PUSHGATEWAY_URL}/metrics/job/${encodeURIComponent(jobName)}`;
27 const axios = require('axios');
28
29 try {
30 await axios.post(pushUrl, metricsBody, {
31 headers: { 'Content-Type': 'text/plain' }
32 });
33 return res.json({ success: true });
34 } catch (err) {
35 console.error('Pushgateway error:', err.message);
36 return res.status(502).json({ error: err.message });
37 }
38});

Pro tip: Keep Pushgateway metrics to aggregate counters (total completions, total errors) rather than per-session or per-user values. High-cardinality label sets (unique per user) cause Prometheus to consume excessive memory.

Expected result: After an action in your FlutterFlow app triggers the Push Metric API Call, the counter appears in Prometheus's `/api/v1/query?query=<your_metric_name>` response and is visible in Grafana dashboards.

Common use cases

Infrastructure monitoring dashboard in a FlutterFlow admin app

An engineering team's internal FlutterFlow app shows a real-time dashboard of key infrastructure metrics — CPU usage, request rate, error rate — fetched from Prometheus via PromQL queries through a secure Cloud Function proxy. Cards on the screen update every 30 seconds using a periodic action, giving on-call engineers a mobile view of their systems.

FlutterFlow Prompt

Build an admin dashboard screen that fetches CPU usage and HTTP request rate from a Prometheus proxy endpoint and displays them as numeric stat cards that refresh every 30 seconds.

Copy this prompt to try it in FlutterFlow

App event counter feeding into Prometheus via Pushgateway

A FlutterFlow app sends a counter increment to a Firebase Cloud Function each time users complete a key action (for example, completing a tutorial). The Cloud Function writes to the Prometheus Pushgateway using the text exposition format. Prometheus scrapes the Pushgateway and the metric appears in Grafana dashboards alongside server-side metrics, giving the team a unified observability view.

FlutterFlow Prompt

When a user taps 'Complete Tutorial', send a count increment to a Firebase Cloud Function that pushes it to the Prometheus Pushgateway as a counter metric named 'app_tutorial_completions_total'.

Copy this prompt to try it in FlutterFlow

Alert status screen showing active Prometheus alerts

A DevOps FlutterFlow app queries the Prometheus Alerts API (`/api/v1/alerts`) through a backend proxy to display a list of currently firing alerts with their labels and severity. Engineers can view active incidents from their phone without needing to log into Grafana or AlertManager.

FlutterFlow Prompt

Build a screen that lists all currently firing Prometheus alerts (name, state, labels) fetched from a backend proxy of the Alerts API, sorted by severity.

Copy this prompt to try it in FlutterFlow

Troubleshooting

FlutterFlow API Call returns 'XMLHttpRequest error' or CORS error when calling Prometheus

Cause: For web builds, the browser enforces CORS. Prometheus's HTTP API does not send CORS headers by default, so browser-based calls to port 9090 are blocked. This also means the app is calling Prometheus directly — which it should not do even on mobile builds, for security reasons.

Solution: Route all Prometheus requests through a Firebase Cloud Function or a reverse proxy configured to add `Access-Control-Allow-Origin: *` response headers. Point the FlutterFlow API Group at the proxy URL, never at Prometheus's port 9090 directly.

Metric values display as 'NaN' or '0' in FlutterFlow chart or text widgets

Cause: Prometheus returns metric values as strings inside JSON arrays (`[timestamp, "value_string"]`). Binding the raw JSON path to a Number widget without type conversion treats the string as an invalid number.

Solution: Create a FlutterFlow Custom Function (return type: Double) that calls `double.tryParse(rawValue) ?? 0.0` and apply it as a transformation when binding the API response to your widget. Make sure you're targeting the correct JSON path (`$.data.result[0].value[1]`, index 1 for the value, not index 0 which is the timestamp).

typescript
1double parseMetricValue(String rawValue) {
2 return double.tryParse(rawValue) ?? 0.0;
3}

The API Call returns 200 but `data.result` is an empty array

Cause: The PromQL query returned no matching time series. This usually means the metric name doesn't exist in Prometheus, a label selector doesn't match any targets, or the time range specified has no data.

Solution: Test the same PromQL expression directly in the Prometheus web UI (port 9090 → Graph tab) or in Grafana to confirm the metric name and labels are correct. A common mistake is using a metric name from a different environment (staging vs production). For time-range queries, check that the `start` and `end` timestamps overlap with when data was collected.

Pushgateway metrics appear in Prometheus at a fixed old value and never update

Cause: Pushgateway stores the last pushed value until it is explicitly deleted with an HTTP DELETE request. If your app pushes an absolute value (e.g., '5 completions') rather than an incrementing counter, the metric stays at 5 even as new completions occur.

Solution: For cumulative counters, read the current value from Prometheus first, increment it, and push the new total. Alternatively, push a gauge metric (current measurement) rather than a counter, or use the Pushgateway DELETE endpoint (`DELETE /metrics/job/<job>`) after reading to clear stale values. For high-frequency app events, consider an analytics tool better suited to ephemeral client events (Amplitude, Segment) rather than Pushgateway.

Best practices

  • Never expose Prometheus port 9090 directly to your FlutterFlow API Group — always route through a Cloud Function or reverse proxy with auth.
  • Parse Prometheus metric values (string format) to doubles with a Custom Function before binding to number or chart widgets to avoid NaN display issues.
  • Use the instant query endpoint (`/api/v1/query`) for current values and dashboard cards; reserve `/api/v1/query_range` for sparkline history charts, keeping the step parameter coarse to limit response size.
  • For app-side event counting, prefer Amplitude, Segment, or a purpose-built analytics tool over the Pushgateway — Prometheus was designed for server scraping, not mobile event ingestion.
  • Keep Pushgateway label cardinality low — never use per-user or per-session unique values as label dimensions, as this causes Prometheus memory growth.
  • Add a periodic refresh action (Actions → Wait/Timer) to dashboard screens that poll Prometheus metrics, but keep the interval at 30 seconds or longer to avoid unnecessary Cloud Function invocations.
  • If you're building a monitoring dashboard, consider embedding a Grafana panel (via Custom Widget + InAppWebView) instead of rebuilding PromQL charting in FlutterFlow — it leverages Grafana's native rendering.

Alternatives

Frequently asked questions

Can I send events directly from my FlutterFlow app to Prometheus without a backend?

No — Prometheus is a pull-based system that scrapes metrics from server targets on a schedule. Mobile apps cannot be scrape targets because they lack a stable public URL and are ephemeral. For pushing app-side events into Prometheus, you need a backend proxy (Firebase Cloud Function) that writes to the Prometheus Pushgateway, which Prometheus then scrapes. For event-based analytics from mobile apps, tools like Segment or Amplitude are a better fit.

Is there a `prometheus_client` Flutter/Dart package I can use in a Custom Action?

There are `prometheus_client` packages on pub.dev, but they target long-lived server processes — they expose a `/metrics` HTTP endpoint that Prometheus scrapes, which is not possible from a mobile app. Do not use a prometheus_client package in a FlutterFlow Custom Action; use the Pushgateway write path via a Cloud Function instead for app-side metrics.

Why do my Prometheus metric values show as strings in the API response?

Prometheus's JSON API returns metric values as strings inside arrays for historical reasons related to precision — floating-point numbers can lose precision in JSON serialization, so Prometheus serializes them as quoted strings. This is intentional, not a bug. You need to parse the string to a number (Dart's `double.tryParse()`) before binding to numeric FlutterFlow widgets or chart data points.

Can I use this integration to show Prometheus metrics in a FlutterFlow app used by non-technical team members?

Yes, but plan the UI carefully. Non-technical users need simple stat cards and trend indicators, not raw PromQL output. Design your Cloud Function to query specific, named metrics and return clean JSON (no raw Prometheus label dictionaries) so you can bind values directly to labeled cards in FlutterFlow without exposing PromQL complexity in the app itself.

Does this integration work for Grafana Cloud's managed Prometheus?

Yes — Grafana Cloud's managed Prometheus exposes the same HTTP Query API at a cloud URL with HTTP Basic Auth (using your Grafana Cloud username and API key). Set the Basic Auth credentials in your Firebase Cloud Function rather than in the FlutterFlow API Group, and point the proxy at your Grafana Cloud Prometheus URL. The PromQL queries and response format are identical to self-hosted Prometheus.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire FlutterFlow integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.