Connect FlutterFlow to Honeycomb by routing event batches through a Firebase Cloud Function proxy that holds your `X-Honeycomb-Team` ingest key — the key must never appear in a Dart API Call header or Custom Action. Call the proxy from FlutterFlow using a POST to `/1/batch/{dataset}`, and for full OpenTelemetry tracing, use a Custom Action wrapping an OTLP Dart exporter pointed at the same proxy.
| Fact | Value |
|---|---|
| Tool | Honeycomb |
| Category | Analytics |
| Method | FlutterFlow API Call |
| Difficulty | Advanced |
| Time required | 45 minutes |
| Last updated | July 2026 |
Push Events Safely: Honeycomb's Ingest Key Must Stay Server-Side
Honeycomb is an observability and tracing platform built around structured events. Unlike Prometheus (which pulls metrics from servers), Honeycomb is push-based: your code sends JSON events with whatever fields you want — timestamps, user IDs, action names, timing data — and Honeycomb stores them in a way that lets you query across high-cardinality dimensions in real time. This makes it well-suited for understanding what specific users experienced in your FlutterFlow app at a granular level.
The primary authentication mechanism is an ingest API key sent in the `X-Honeycomb-Team` request header. This is where the security problem arises: FlutterFlow compiles to Flutter code that runs on the user's device. Any value you put in an API Call header ships inside the compiled app binary and can be extracted by anyone who downloads it. An extracted Honeycomb ingest key would let an attacker flood your dataset with fake events, exhausting your event quota.
The solution is straightforward: deploy a Firebase Cloud Function that holds the ingest key in its server-side environment variables, accepts batched events from your FlutterFlow app, and forwards them to Honeycomb. Your FlutterFlow API Call points at the Cloud Function URL — no Honeycomb key appears anywhere in your app.
Honeycomb offers a free tier with a generous event allowance (check their current pricing, as free tier limits change). Usage-based paid plans scale with event volume. One important cost consideration for mobile: if you send a separate Honeycomb event for every user tap or scroll action, you can exhaust your free tier quickly. Use the `/1/batch/{dataset}` endpoint to send multiple events in a single HTTP request, and queue events on the device before flushing.
Integration method
FlutterFlow sends structured event batches to a Firebase Cloud Function proxy that holds the Honeycomb ingest key (`X-Honeycomb-Team`) and forwards them to Honeycomb's Events API (`/1/batch/{dataset}`). The Cloud Function keeps the ingest key off the device. For full distributed tracing with OpenTelemetry spans, a Custom Action wrapping an OTLP Dart exporter can be added — but it requires a device build and should also route through the proxy to protect the key. Direct calls to `api.honeycomb.io` from FlutterFlow code are not safe because the ingest key would ship inside the compiled app binary.
Prerequisites
- A Honeycomb account with at least one dataset created (app.honeycomb.io → Datasets → Create Dataset)
- A Honeycomb ingest API key — found in Honeycomb under Team Settings → API Keys → Create Key with 'Send Events' permission
- A Firebase project connected to your FlutterFlow app (for deploying the Cloud Function proxy)
- Firebase CLI installed, or a developer who can deploy Cloud Functions on your behalf
- Basic understanding of JSON objects — Honeycomb events are arbitrary JSON key-value pairs
Step-by-step guide
Create a Honeycomb Dataset and Ingest API Key
Log in to your Honeycomb account at app.honeycomb.io. In the left sidebar, click on your team name to open the team settings, then navigate to 'Datasets'. Click 'New Dataset' and give it a name that reflects your app — for example, `flutterflow-app-events` or just your app's name. The dataset name will appear in the Honeycomb UI when you query your events. Next, create an ingest API key. Go to Team Settings → API Keys → Create API Key. Give the key a descriptive name like 'FlutterFlow Production Ingest'. Make sure the key has the 'Send Events' permission enabled. Copy the key value immediately after creation — Honeycomb shows the full key value only once at creation time. Store it somewhere secure for the next step. You'll also need the dataset name exactly as you created it — it goes in the API URL path (`/1/batch/{dataset}`). The dataset name is case-sensitive. Note on the API key: Honeycomb has two types of keys — 'Classic' API keys (which need an explicit dataset name in the URL) and newer 'Environment & Services' keys (which use the `X-Honeycomb-Dataset` header instead). The difference affects how you structure the Cloud Function proxy request. If you're on a new Honeycomb account, you're likely using Environment & Services keys. The code example in Step 2 covers the Classic approach with the dataset name in the URL — adjust if your team uses the newer format.
Pro tip: Create separate ingest keys for development and production — for example, 'FlutterFlow Dev Ingest' and 'FlutterFlow Prod Ingest'. This lets you have separate Honeycomb datasets for test events and real user events without mixing data.
Expected result: You have a Honeycomb dataset name and a valid ingest API key with Send Events permission, stored securely for use in the Cloud Function proxy.
Deploy a Firebase Cloud Function Proxy for Honeycomb Events
The Cloud Function is the critical piece that keeps the Honeycomb ingest key off your device. It accepts batched event arrays from your FlutterFlow app, adds the `X-Honeycomb-Team` header server-side, and forwards the request to Honeycomb's batch events endpoint. In your Firebase Cloud Functions project (in the `functions/` directory alongside your Firebase project), install the `axios` package for HTTP requests. Create the Cloud Function shown in the code block below. Set the Honeycomb API key as a Firebase environment variable using `firebase functions:config:set honeycomb.api_key="your-key-here" honeycomb.dataset="your-dataset-name"` — this keeps it out of your source code entirely. Deploy the function with `firebase deploy --only functions`. Copy the deployed function URL — it will look like `https://us-central1-your-project.cloudfunctions.net/sendHoneycombEvents`. Test the Cloud Function directly before setting up FlutterFlow. Using curl or Postman, POST a simple event array to the function URL. Verify in your Honeycomb dataset that the test event appears within a few seconds of sending. If it does, the proxy is working correctly and you're ready to configure FlutterFlow. The Cloud Function accepts an array of event objects in the Honeycomb batch format: each object has a `time` field (ISO 8601 or Unix timestamp) and a `data` object with your custom key-value pairs. You can include any fields you want in `data` — Honeycomb's schema-on-read approach means you don't need to pre-define columns.
1// Firebase Cloud Function: Honeycomb Events Proxy2// functions/index.js3const functions = require('firebase-functions');4const axios = require('axios');56// Set env config: firebase functions:config:set7// honeycomb.api_key="your-ingest-key"8// honeycomb.dataset="your-dataset-name"9const HONEYCOMB_API_KEY = process.env.HONEYCOMB_API_KEY ||10 (functions.config().honeycomb && functions.config().honeycomb.api_key);11const HONEYCOMB_DATASET = process.env.HONEYCOMB_DATASET ||12 (functions.config().honeycomb && functions.config().honeycomb.dataset);1314exports.sendHoneycombEvents = functions.https.onRequest(async (req, res) => {15 res.set('Access-Control-Allow-Origin', '*');16 if (req.method === 'OPTIONS') {17 res.set('Access-Control-Allow-Methods', 'POST');18 res.set('Access-Control-Allow-Headers', 'Content-Type');19 return res.status(204).send('');20 }2122 if (req.method !== 'POST') {23 return res.status(405).json({ error: 'Method not allowed' });24 }2526 const events = req.body;27 if (!Array.isArray(events) || events.length === 0) {28 return res.status(400).json({ error: 'Request body must be a non-empty array of events' });29 }3031 // Add a timestamp to any events missing one32 const now = new Date().toISOString();33 const batch = events.map(event => ({34 time: event.time || now,35 data: event.data || event36 }));3738 try {39 const response = await axios.post(40 `https://api.honeycomb.io/1/batch/${encodeURIComponent(HONEYCOMB_DATASET)}`,41 batch,42 {43 headers: {44 'X-Honeycomb-Team': HONEYCOMB_API_KEY,45 'Content-Type': 'application/json'46 }47 }48 );49 return res.json({ success: true, results: response.data });50 } catch (err) {51 console.error('Honeycomb API error:', err.response?.data || err.message);52 return res.status(502).json({ error: err.message });53 }54});Pro tip: After deploying, test with a curl command: `curl -X POST https://YOUR_FUNCTION_URL -H 'Content-Type: application/json' -d '[{"data":{"test":"event","source":"curl"}}]'`. If you see the event appear in Honeycomb within seconds, the proxy is working.
Expected result: The Cloud Function deploys successfully and a test POST returns a `{success: true}` response. The test event appears in your Honeycomb dataset within seconds, visible in the Honeycomb UI under your dataset's Recent Data.
Create the API Group and API Call in FlutterFlow
With the Cloud Function proxy deployed and verified, set up the FlutterFlow side to call it. Click 'API Calls' in the left navigation panel (the plug icon), then click '+ Add' and choose 'Create API Group'. Name it 'HoneycombProxy'. Set the Base URL to your deployed Cloud Function URL (for example, `https://us-central1-your-project.cloudfunctions.net`). Leave authentication as 'No Auth' — security is handled inside the Cloud Function. Click '+ Add API Call' within the group. Name it 'BatchEvents'. Set the method to POST. Set the endpoint to `/sendHoneycombEvents` (matching your function name). In the Body section, set the content type to JSON and add a body variable named 'events' of type JSON. This variable will hold your array of event objects. In the Response & Test tab, paste a sample successful response from your earlier test: `{"success": true, "results": [{"status": 202}]}` Click 'Generate JSON Paths' if you want to check the success field. Then test the API Call by entering a sample events array in the variable field: `[{"data": {"event_type": "test", "source": "flutterflow"}}]` Click 'Test API Call' and confirm you get a 200 response with success: true. Check Honeycomb to confirm the test event arrived. Now add this API Call to your Action Flows. For example, to fire an event when a button is tapped: select the button → Actions panel → + Add Action → Backend/API Calls → API Call (select BatchEvents) → set the events variable to a JSON array constructed from your page/widget state values. You can use FlutterFlow's JSON builder to construct the event object dynamically with field values from your app state.
1// Sample events array to test in FlutterFlow API Call body2// Paste into the 'events' variable field in the Test tab3[4 {5 "time": "2026-07-09T12:00:00Z",6 "data": {7 "event_type": "button_tap",8 "button_name": "complete_purchase",9 "user_id": "user_12345",10 "product_id": "prod_abc",11 "duration_ms": 342,12 "app_version": "1.2.0",13 "platform": "android"14 }15 }16]Pro tip: Name your Honeycomb event fields consistently across all events — for example, always use `user_id` (not `userId` or `user` in some places) so Honeycomb's query UI can group and filter across all event types cleanly.
Expected result: The BatchEvents API Call test returns 200 with `{success: true}`, and a test event appears in your Honeycomb dataset. Adding the API Call to an Action Flow allows you to fire structured events from any user interaction in your app.
Batch Events from the Device and (Advanced) Add OTLP Custom Action Tracing
Sending a separate HTTP request to the Cloud Function for every user action is inefficient on mobile — it generates many short-lived network requests and can quickly consume your Honeycomb event quota on high-traffic actions. A better pattern is to queue events on the device and flush them in batches. For simple batching without custom code: use FlutterFlow's App State (left nav → App State → + Add Field) to maintain a list variable called `pendingHoneycombEvents`. Append event objects to this list using Update App State actions. On screen navigation or after collecting 10+ events, fire the BatchEvents API Call with the entire list, then clear the list. This is achievable with FlutterFlow's built-in state and action system, no custom code required. For full OpenTelemetry distributed tracing (the most powerful Honeycomb use case), the path requires a Custom Action. Go to left nav → Custom Code → + Add → Action. Name it 'SendOTLPTrace'. In the Dependencies field, add an OpenTelemetry Dart package that supports OTLP export — search pub.dev for `opentelemetry` packages compatible with Flutter. The Custom Action initializes an OTLP trace exporter pointed at your Cloud Function's OTLP endpoint (you'd need to add OTLP support to the proxy, or use Honeycomb's OTLP endpoint directly if you're comfortable with the key exposure trade-off during development). Important constraints on the Custom Action path: - Custom Actions don't run in FlutterFlow's web Run preview — test on a real device only. - For production, the OTLP exporter should point at a Cloud Function proxy, not directly at `api.honeycomb.io`, so the `X-Honeycomb-Team` header stays server-side. - High-frequency per-tap OTLP spans can quickly exhaust free tier event budgets — sample aggressively (trace 1 in 100 sessions, not every action). For most FlutterFlow apps, the simple batch Events API Call approach in Steps 2-3 gives excellent observability without needing OTLP. Reserve the OTLP Custom Action for cases where you need trace IDs that correlate mobile spans with backend spans in a distributed tracing setup.
1// FlutterFlow Custom Action: Send queued events to Honeycomb proxy2// Dart — for batching events stored in App State3// Arguments:4// events: List<dynamic> (list of event JSON objects from App State)5// proxyUrl: String (your Cloud Function URL)6// Return type: bool7import 'dart:convert';8import 'package:http/http.dart' as http;910Future<bool> sendHoneycombBatch(11 List<dynamic> events,12 String proxyUrl,13) async {14 if (events.isEmpty) return true;1516 try {17 final response = await http.post(18 Uri.parse('$proxyUrl/sendHoneycombEvents'),19 headers: {'Content-Type': 'application/json'},20 body: jsonEncode(events),21 );2223 if (response.statusCode == 200) {24 return true;25 } else {26 debugPrint('Honeycomb proxy error: ${response.statusCode} ${response.body}');27 return false;28 }29 } catch (e) {30 debugPrint('Honeycomb send error: $e');31 return false;32 }33}Pro tip: If you'd rather skip the Cloud Function and Custom Action setup entirely, RapidDev's team builds FlutterFlow integrations like this every week — free scoping call at rapidevelopers.com/contact.
Expected result: Events queued in App State are flushed to Honeycomb in batches on navigation events or after accumulating 10+ events. In Honeycomb's UI, you can see multiple events from a single user session with correct timestamps and field values.
Common use cases
Mobile app performance monitoring with per-screen timing events
A FlutterFlow app records the time each screen takes to load by capturing a start timestamp at navigation and an end timestamp when content is visible, then batches the timing event to Honeycomb via the Cloud Function proxy. Engineers query Honeycomb with high-cardinality filters (by device type, OS version, user segment) to identify which screens are slow for which users — something Firebase Performance Monitoring can't do at this granularity.
Track screen load time on the Product Detail screen — capture time_to_interactive in milliseconds, the user's device model, and the product ID, and send it to Honeycomb as a structured event when the screen finishes loading.
Copy this prompt to try it in FlutterFlow
Error tracking with full request context for FlutterFlow API failures
When a FlutterFlow API Call returns an error (4xx or 5xx), an On Error action fires and sends a structured event to Honeycomb containing the endpoint, response code, error message, user ID, and timestamp. Teams can then query across all API errors in Honeycomb to identify patterns — for example, which endpoints fail most often for users in specific regions.
When any API call in the app returns an error, send a Honeycomb event with the endpoint name, HTTP status code, error body, and current user ID so we can track API reliability by endpoint.
Copy this prompt to try it in FlutterFlow
User journey tracing for onboarding funnel analysis
A startup FlutterFlow app batches events at key onboarding steps — account creation, profile setup, first purchase — each containing the user ID, step name, duration, and whether the step was completed. Honeycomb's BubbleUp feature automatically surfaces the fields most correlated with users who fail to complete onboarding, giving product teams actionable insight faster than traditional analytics funnels.
Send a Honeycomb event at each onboarding step with the step name, whether it was completed or skipped, the time spent on that step, and the user's account type.
Copy this prompt to try it in FlutterFlow
Troubleshooting
Honeycomb API returns 401 Unauthorized from the Cloud Function
Cause: The `X-Honeycomb-Team` API key stored in the Cloud Function environment is missing, incorrect, or has been revoked. This also happens when a new key is generated in Honeycomb but the Cloud Function config was not updated and redeployed.
Solution: In Firebase Console → Cloud Functions → your function → Logs, look for the Honeycomb error body. In your terminal, run `firebase functions:config:get` to verify the honeycomb.api_key value is set and matches the key in Honeycomb (Team Settings → API Keys). Update and redeploy if needed: `firebase functions:config:set honeycomb.api_key="correct-key" && firebase deploy --only functions`.
Events appear in Honeycomb with wrong timestamps or all showing the same time
Cause: The `time` field in the event objects sent from FlutterFlow is missing, null, or not in a format Honeycomb recognizes (ISO 8601 or Unix epoch). Honeycomb uses the `time` field to order events in its UI.
Solution: In your FlutterFlow Action Flow, include a `time` field in each event object set to the current timestamp in ISO 8601 format. Use a FlutterFlow Custom Function that returns `DateTime.now().toUtc().toIso8601String()` and bind it to the `time` field in the event JSON. Alternatively, the Cloud Function proxy can add a server-side timestamp if the `time` field is missing.
1// Custom Function: getCurrentTimestamp2// Return type: String3String getCurrentTimestamp() {4 return DateTime.now().toUtc().toIso8601String();5}CORS error when FlutterFlow web build calls the Cloud Function
Cause: The Cloud Function is not returning the correct CORS response headers for preflight (OPTIONS) requests from browser-based FlutterFlow web builds.
Solution: Ensure the Cloud Function handles OPTIONS requests and returns `Access-Control-Allow-Origin: *`, `Access-Control-Allow-Methods: POST`, and `Access-Control-Allow-Headers: Content-Type` headers. The code example in Step 2 already includes this — if you're seeing CORS errors, check that the OPTIONS block is present and the function was redeployed after adding it.
OTLP Custom Action sends no traces and shows no errors — events just don't appear in Honeycomb
Cause: Custom Actions that use HTTP or networking packages may silently fail in FlutterFlow's web Run preview because the environment doesn't support the full Dart platform. OTLP Custom Actions also won't run in web preview.
Solution: Test the Custom Action on a real device using Test Mode (not the web Run preview). Install a Test Mode build on a physical device, trigger the action, and check Honeycomb for events. If events still don't appear, check the device's network connection and add a `debugPrint` statement to the Custom Action to confirm it's being called.
Best practices
- Never put the `X-Honeycomb-Team` ingest key in a FlutterFlow API Call header or a Dart Custom Action — always route through a Firebase Cloud Function that adds the header server-side.
- Use the `/1/batch/{dataset}` endpoint instead of single-event `/1/events` calls — batching reduces network overhead and conserves your Honeycomb event quota from mobile.
- Queue events in FlutterFlow App State and flush them on screen transitions rather than sending individual HTTP requests per user action.
- Keep event field names consistent across all event types (always `user_id`, not sometimes `userId`) to enable cross-event type queries in Honeycomb.
- Avoid high-cardinality unbounded values as Honeycomb event fields that you plan to GROUP BY — things like free-text search queries work as filter values but not as group-by columns.
- For OTLP tracing Custom Actions, sample aggressively on mobile (trace 1-5% of sessions) to avoid exhausting your event quota on high-traffic actions.
- Create separate Honeycomb datasets for development and production environments — use different Cloud Function deployments with different ingest keys so test events don't pollute production data.
Alternatives
Choose Datadog if you need a fully managed observability platform with a Flutter mobile agent for automatic crash reporting, HTTP monitoring, and RUM — without writing custom event schemas.
Choose New Relic if you want a turnkey mobile APM with a Flutter agent that auto-captures crashes and interactions, avoiding the need to design and send custom Honeycomb event schemas.
Choose Amplitude for product analytics (funnels, retention, user journeys) rather than infrastructure observability — it has a simpler write-key model with no proxy requirement for client-side event tracking.
Frequently asked questions
Is it safe to put the Honeycomb ingest key in a FlutterFlow API Call header?
No. FlutterFlow compiles to Flutter code that runs on the user's device. Values in API Call headers are embedded in the compiled app binary and can be extracted by someone who downloads and reverse-engineers the APK or IPA. An extracted Honeycomb ingest key would allow an attacker to flood your dataset with fake events, consuming your quota and polluting your observability data. Always route Honeycomb calls through a Firebase Cloud Function that holds the key in its server-side environment.
What is the difference between Honeycomb's Events API and OTLP?
The Events API (`/1/batch/{dataset}`) accepts arbitrary JSON objects — you define whatever fields make sense for your app. It's the simpler path and works well for custom business events like 'user completed checkout' or 'screen load time.' OTLP (OpenTelemetry Protocol) is a standardized tracing format that includes concepts like trace IDs, span IDs, parent spans, and timing. OTLP is the right choice when you need to correlate mobile spans with backend spans in a distributed trace — for example, tracking the full journey of a request from the mobile app through your API server.
How quickly do events appear in Honeycomb after being sent?
Honeycomb events typically appear in your dataset within a few seconds of being received by the API. Unlike some analytics tools (like GA4, which has up to 24-hour delays in standard reports), Honeycomb's query UI shows events in near real-time. This makes it practical to test your integration by sending a test event and immediately querying for it in the Honeycomb UI.
Can I use Honeycomb's free tier for a production FlutterFlow app?
Yes, for low-volume apps. Honeycomb's free tier includes a generous monthly event allowance (check Honeycomb's current pricing as it changes). For a mobile app, the key is batching events rather than sending one per action, and being selective about which events you send. If your app has thousands of daily active users each triggering dozens of events per session, a paid plan will be needed — calculate expected monthly event volume before relying on the free tier.
Do I need both the Events API and OTLP, or should I pick one?
For most FlutterFlow apps, the Events API (Steps 2-3) is all you need. It gives you structured observability data with custom fields, works on both mobile and web builds, and doesn't require any custom Dart code. OTLP via a Custom Action is only necessary if you need distributed tracing that correlates mobile spans with backend service spans — a more advanced scenario typically needed by engineering teams building microservice backends, not solo founders building their first app.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation