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.
| Fact | Value |
|---|---|
| Tool | Prometheus |
| Category | Analytics |
| Method | FlutterFlow API Call |
| Difficulty | Advanced |
| Time required | 45 minutes |
| Last updated | July 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
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
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.
1// Firebase Cloud Function: Prometheus query proxy2// functions/index.js3const functions = require('firebase-functions');4const https = require('https');5const http = require('http');67// Set PROMETHEUS_URL in Firebase environment config8// firebase functions:config:set prometheus.url="http://your-prometheus:9090"9const PROMETHEUS_URL = process.env.PROMETHEUS_URL || 'http://localhost:9090';1011exports.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 }1819 const query = req.query.query;20 const time = req.query.time || Math.floor(Date.now() / 1000);2122 if (!query) {23 return res.status(400).json({ error: 'Missing query parameter' });24 }2526 const targetUrl = `${PROMETHEUS_URL}/api/v1/query?query=${encodeURIComponent(query)}&time=${time}`;27 const protocol = targetUrl.startsWith('https') ? https : http;2829 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.
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.
1// Sample Prometheus instant query API response2// GET /api/v1/query?query=http_requests_total3{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.
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.
1// Custom Function: parseMetricValue2// Convert Prometheus string metric value to double3// Arguments: rawValue (String)4// Return type: double5double 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 values10 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.
(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.
1// Firebase Cloud Function: push metrics to Pushgateway2// functions/index.js (add this alongside the query proxy)3const PUSHGATEWAY_URL = process.env.PUSHGATEWAY_URL || 'http://localhost:9091';45exports.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 }1213 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 }1718 // Build Prometheus text exposition format19 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`;2526 const pushUrl = `${PUSHGATEWAY_URL}/metrics/job/${encodeURIComponent(jobName)}`;27 const axios = require('axios');2829 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.
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.
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.
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).
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
Choose Grafana over Prometheus for your FlutterFlow dashboard if you want to embed pre-built, interactive metric dashboards via a Custom Widget InAppWebView instead of building custom PromQL parsing and chart widgets from scratch.
Choose Datadog if you want a fully managed observability platform with a client SDK, a generous free tier, and no need to manage Prometheus infrastructure — with simpler FlutterFlow API Call integration via the Metrics API.
Choose New Relic if you need a hosted APM with a Flutter mobile agent that auto-captures crashes and HTTP timing without writing PromQL queries or managing your own metrics infrastructure.
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation