Connect FlutterFlow to Datadog using a Custom Action that wraps the `datadog_flutter_plugin` pub.dev SDK to send RUM sessions, crashes, logs, and traces from your app. Configure the SDK with a write-only client token plus your Datadog site region — the most common setup mistake is using the wrong region. To read metrics back into an in-app ops dashboard, proxy the secret API and Application keys through a Firebase Cloud Function.
| Fact | Value |
|---|---|
| Tool | Datadog |
| Category | Analytics |
| Method | Custom Action (Dart) |
| Difficulty | Intermediate |
| Time required | 40 minutes |
| Last updated | July 2026 |
Add Datadog RUM, Logs, and Traces to Your FlutterFlow App
Datadog is an observability platform built for engineering teams who want hard numbers about their app: crash rates, RUM session durations, slow network calls, custom error logs, and distributed traces. Where FullStory gives you qualitative session replays, Datadog gives you quantitative telemetry — metrics you can graph, alert on, and slice by user segment or app version. For a FlutterFlow app with real users in production, Datadog is the tool that tells you whether something is broken before users file support tickets.
The integration has two distinct lanes. The first is telemetry: getting RUM sessions, logs, and traces out of your app and into Datadog. This uses Datadog's official `datadog_flutter_plugin` package, wrapped in a FlutterFlow Custom Action. The SDK requires a client token — a write-only credential that can only append data to Datadog — plus a RUM application ID and, critically, your Datadog site region. Datadog runs on multiple regional clusters (`datadoghq.com` for US1, `datadoghq.eu` for EU1, `us5.datadoghq.com` for US5, and others). Sending data to the wrong region results in telemetry silently disappearing with no error — this is the single most common Datadog setup mistake on any platform, and it is doubly easy to get wrong in FlutterFlow where the site is configured as an enum constant in Dart code.
The second lane is reading data back. Datadog's query API — used to retrieve metrics, logs, and RUM data programmatically — requires an API key plus an Application key, both of which are full-account secrets with broad read access. These must never appear in a FlutterFlow API Call header or Dart Custom Action because doing so embeds them in the app binary. The solution is a Firebase Cloud Function or Supabase Edge Function proxy. Your FlutterFlow app calls the proxy; the proxy calls Datadog's API with the secrets held in server-side environment variables. This optional second lane lets you build an in-app ops dashboard showing live error rates, crash counts, or session metrics for a founder or engineering lead.
Integration method
Datadog instrumentation in FlutterFlow uses a Custom Action wrapping the official `datadog_flutter_plugin` package. The SDK is initialized with a write-only client token and a Datadog site region enum (us1, eu1, us5, etc.) and runs natively on iOS and Android. A second integration layer — a FlutterFlow API Call group pointing to a Firebase or Supabase proxy — handles reading metrics and logs back via Datadog's query API, because the API key and Application key required for reads are full-account secrets that must never ship in the app bundle.
Prerequisites
- A Datadog account — free trial available; RUM is billed per 1,000 sessions on paid plans
- A Datadog RUM application created in your Datadog account — this generates the client token and application ID
- Your Datadog site region noted (US1: datadoghq.com, EU1: datadoghq.eu, US5: us5.datadoghq.com — must match your account)
- A FlutterFlow project with Custom Code enabled
- A Firebase project or Supabase project for the proxy (required only for reading metrics via the query API)
Step-by-step guide
Create a Datadog RUM application and note your site region
Before writing any FlutterFlow code, you need three values from the Datadog console: a client token, a RUM application ID, and your site region. Getting the site region wrong is the most common cause of 'no data appears' issues — and it produces no error, just silence. Log in to your Datadog account. First, identify your site: look at the URL in your browser. If it is `app.datadoghq.com`, your site is US1. If it is `app.datadoghq.eu`, your site is EU1. If it is `app.us5.datadoghq.com`, your site is US5. Keep this value visible — you will need it in the next step and in your proxy configuration. Next, go to Digital Experience → Real User Monitoring in the Datadog sidebar. Click New Application. Select Mobile as the platform and Flutter as the framework. Give the application a name matching your FlutterFlow app name. Datadog will generate a Client Token and a RUM Application ID. Copy both and store them somewhere accessible — you will paste them into your Custom Action in the next step. The client token is a write-only credential: it can only append data to Datadog under this application, so it is relatively safe to include in the app, but it is still best practice to keep it out of version control. Separately, if you plan to build a metrics read-back dashboard (Steps 4-5), go to Organization Settings → API Keys to get an API Key, and Organization Settings → Application Keys to create an Application Key. These are full-account secrets — do not use them anywhere except your server-side proxy.
Pro tip: Your Datadog site region is determined when your account is created and cannot be changed afterward. It is critical that the site you configure in the Flutter SDK and any proxy base URLs exactly match your account's site — even sending to a valid Datadog region that is not your account's will silently discard all data.
Expected result: You have your client token, RUM application ID, and site region written down. The new RUM application appears in Datadog's RUM Applications list with a 'Waiting for data' status.
Add the datadog_flutter_plugin Custom Action and initialize with the correct site
In FlutterFlow, open the left nav, click Custom Code, then click + Add and select Action. Name the action InitDatadog. In the Dependencies field, add the pub.dev package `datadog_flutter_plugin` (check pub.dev for the current stable version). FlutterFlow handles the package resolution — no terminal commands needed. In the Dart code editor, import the package and write the initialization call. The most critical part is the site parameter — it must be a `DatadogSite` enum value that matches your account's region. For US1: `DatadogSite.us1`. For EU1: `DatadogSite.eu1`. For US5: `DatadogSite.us5`. For AP1: `DatadogSite.ap1`. For US3: `DatadogSite.us3`. Getting this wrong means all telemetry will be sent to the right Datadog infrastructure but the wrong organization — no error is thrown, data just never appears in your account. Add a `kIsWeb` guard at the top — `if (kIsWeb) return;` — because the `datadog_flutter_plugin` package is native-only. Import `package:flutter/foundation.dart` for the `kIsWeb` constant. Without this guard, web builds will fail to compile. Once the Custom Action is saved, wire it to your app's root widget On Page Load action. This ensures Datadog is initialized before any navigation events or logs are captured. Save the action. Remember: Custom Actions do not run in FlutterFlow's browser-based Test Mode. You must use Run Mode connected to a real iOS or Android device, or a physical device build, to verify Datadog is receiving data.
1import 'package:flutter/foundation.dart';2import 'package:datadog_flutter_plugin/datadog_flutter_plugin.dart';34Future initDatadog() async {5 // datadog_flutter_plugin is native-only6 if (kIsWeb) return;78 final configuration = DatadogConfiguration(9 clientToken: 'YOUR_CLIENT_TOKEN', // write-only, safe-ish in client10 env: 'production', // or 'development'11 site: DatadogSite.us1, // CRITICAL: match your account region12 // US1: DatadogSite.us113 // EU1: DatadogSite.eu114 // US5: DatadogSite.us515 // AP1: DatadogSite.ap116 nativeCrashReportEnabled: true,17 loggingConfiguration: DatadogLoggingConfiguration(),18 rumConfiguration: DatadogRumConfiguration(19 applicationId: 'YOUR_RUM_APPLICATION_ID',20 sessionSamplingRate: 100.0, // capture 100% of sessions21 ),22 );2324 await DatadogSdk.instance.initialize(25 configuration,26 TrackingConsent.granted, // call .pending and request consent if needed27 );28}Pro tip: The client token and API key are completely different credentials in Datadog. The client token (pub_ prefix) is write-only and bound to a single RUM application. The API key is a full-account read/write secret. Never use the API key in your Flutter app — only the client token belongs in the SDK initialization.
Expected result: The Custom Action saves without errors. When tested in Run Mode on a real device, the RUM application in Datadog changes from 'Waiting for data' to showing a session count within a few minutes of app launch.
Track navigation events as RUM views and send custom logs
Datadog RUM auto-instrumentation is limited on Flutter compared to web — screen views do not automatically map to RUM views. You need to explicitly start and stop RUM views as the user navigates between screens so your RUM dashboard shows meaningful per-screen data like time on screen, error rate by screen, and session replay (if enabled). Create a Custom Action named TrackRumView with two String arguments: viewName (the screen name you want to show in Datadog) and viewUrl (a slug-style path like '/home' or '/checkout'). In the function body, call `DatadogSdk.instance.rum?.startView(viewUrl, viewName)`. Call this action On Page Load for each significant screen in your FlutterFlow app, passing the screen name and a URL-style path. For custom logging, create a Custom Action named SendDatadogLog with three arguments: level (String: 'info', 'warn', or 'error'), message (String), and attributes (JSON — a Map of extra context). In the function body, get the logger via `DatadogSdk.instance.logs?.createLogger(DatadogLoggerConfiguration())` and call `.log(LogLevel.info, message, attributes: attributes)`. Use this action to log important app events like purchase completions, sync failures, or API errors. For custom RUM attributes — adding user context to all subsequent RUM events — call `DatadogSdk.instance.rum?.addAttribute('user_id', userId)` in a Custom Action that runs after sign-in. This lets you filter RUM sessions by user ID in the Datadog dashboard, similar to FullStory's identify call but for quantitative RUM data. Wire TrackRumView to the On Page Load action of each important FlutterFlow screen. If you have many screens, add it to a reusable component or wrapper widget. Consistent view naming is critical — inconsistent view names fragment your RUM data into many small segments that are hard to analyze.
1import 'package:flutter/foundation.dart';2import 'package:datadog_flutter_plugin/datadog_flutter_plugin.dart';34// Arguments: viewName (String), viewUrl (String)5Future trackRumView(String viewName, String viewUrl) async {6 if (kIsWeb) return;7 DatadogSdk.instance.rum?.startView(8 viewUrl, // e.g. '/checkout'9 viewName, // e.g. 'Checkout'10 attributes: {'ff_screen': viewName},11 );12}1314// Arguments: level (String), message (String)15Future sendDatadogLog(String level, String message) async {16 if (kIsWeb) return;17 final logger = DatadogSdk.instance.logs?.createLogger(18 DatadogLoggerConfiguration(name: 'app'),19 );20 switch (level) {21 case 'error':22 logger?.error(message);23 break;24 case 'warn':25 logger?.warn(message);26 break;27 default:28 logger?.info(message);29 }30}Pro tip: Name RUM views consistently and use URL-style paths (lowercase, hyphens, no spaces) — for example '/onboarding/step-1', '/home', '/profile'. Datadog's RUM Explorer groups sessions by view path, so consistent naming makes it easy to build per-screen performance dashboards and funnel analyses.
Expected result: The Datadog RUM Explorer shows named views matching the screen names you configured. Sessions show the navigation path each user took through the app. Custom log events appear in Datadog Log Management filterable by level and custom attributes.
Deploy a proxy to hold the Datadog API and Application keys
Datadog's metrics and logs query API uses two secrets: an API key (header `DD-API-KEY`) and an Application key (header `DD-APPLICATION-KEY`). Both have broad account-level access — the Application key in particular can create dashboards, manage alerts, and read all telemetry data. Placing either in a FlutterFlow API Call header compiles them into the app binary. Deploy a Firebase Cloud Function or Supabase Edge Function that holds both keys as secrets and forwards requests to the Datadog query API. The function must also use the correct region-specific base URL matching your Datadog account's site — for US1 that is `https://api.datadoghq.com`, for EU1 it is `https://api.datadoghq.eu`, for US5 it is `https://api.us5.datadoghq.com`. The proxy should accept a `path` query parameter (like `/api/v1/query`) and forward the request to `{DATADOG_BASE_URL}{path}` with both secret headers injected. Add CORS headers so web builds can call the proxy from a browser environment. Store the API key and Application key using Firebase's secret manager (`defineSecret`) or Supabase's Edge Function secrets panel. This is also a good place to add authentication to the proxy itself — require a Firebase ID token or Supabase JWT so only signed-in users of your app can trigger Datadog queries, preventing abuse of your Datadog query quota. For teams who want help architecting this proxy and the FlutterFlow dashboard binding that reads from it, RapidDev builds FlutterFlow integrations like this weekly — free scoping call at rapidevelopers.com/contact.
1// Firebase Cloud Function (Node.js) — Datadog query API proxy2const { onRequest } = require('firebase-functions/v2/https');3const { defineSecret } = require('firebase-functions/params');4const axios = require('axios');56const DD_API_KEY = defineSecret('DD_API_KEY');7const DD_APP_KEY = defineSecret('DD_APP_KEY');8// Set DD_BASE_URL to match your account site:9// US1: https://api.datadoghq.com10// EU1: https://api.datadoghq.eu11// US5: https://api.us5.datadoghq.com12const DD_BASE_URL = 'https://api.datadoghq.com';1314exports.datadogProxy = onRequest(15 { secrets: [DD_API_KEY, DD_APP_KEY] },16 async (req, res) => {17 res.set('Access-Control-Allow-Origin', '*');18 if (req.method === 'OPTIONS') {19 res.set('Access-Control-Allow-Headers', 'Content-Type');20 return res.status(204).send('');21 }2223 const path = req.query.path || '/api/v1/query';24 try {25 const response = await axios({26 method: req.method,27 url: `${DD_BASE_URL}${path}`,28 headers: {29 'DD-API-KEY': DD_API_KEY.value(),30 'DD-APPLICATION-KEY': DD_APP_KEY.value(),31 'Content-Type': 'application/json',32 },33 params: req.method === 'GET' ? req.query : undefined,34 data: req.method !== 'GET' ? req.body : undefined,35 });36 return res.json(response.data);37 } catch (err) {38 return res.status(err.response?.status || 500).json({39 error: err.message,40 });41 }42 }43);Pro tip: The DD_BASE_URL in the proxy must match your account's site exactly. If your FlutterFlow SDK uses DatadogSite.eu1 but your proxy sends query requests to api.datadoghq.com (US1), you will see 403 or empty responses — the data lives in the EU region and cannot be queried from the US endpoint.
Expected result: The Cloud Function deploys and appears in Firebase Console → Functions. Calling the function URL with a valid Datadog metrics query path returns metrics data, confirming both the API key and Application key are working and the region is correct.
Build a FlutterFlow API Call group for the metrics dashboard
With the proxy deployed, create a FlutterFlow API Group to read metrics from Datadog. In the left nav, click API Calls → + Add → Create API Group. Name it DatadogMetrics. Set the Base URL to your deployed proxy function URL. Add an API Call inside the group: name it QueryMetrics. Set the method to GET. In the endpoint field, use `/` and pass the Datadog API path as a query variable named `path`. Add another variable named `query` for the Datadog metrics query string (for example `avg:rum.sessions.count{env:production}`). Add a `from` and `to` variable for the time range as Unix timestamps. In the Response & Test tab, paste a sample Datadog metrics query response and click Generate JSON Paths. The Datadog metrics API returns a `series` array where each item has a `pointlist` — an array of [timestamp, value] pairs. Map the fields you need into a Data Type named DatadogMetric with fields: metricName (String) and the latest value (Double). For an ops dashboard screen, add a Row of stat card Containers, each bound to a different QueryMetrics call with a different metric query: crash rate, session count, error count. Add a refresh IconButton that triggers all three queries. Display the values with appropriate units (percent for rates, integer for counts) and use conditional color — a green/red Container background based on whether the value exceeds a threshold you define in App State. Cache the query results in Firestore or your Supabase database if multiple users will open this dashboard — Datadog's query API has rate limits and there is no reason to query the live API on every screen open when metrics only change every few minutes.
1{2 "group_name": "DatadogMetrics",3 "base_url": "https://YOUR_REGION-YOUR_PROJECT.cloudfunctions.net/datadogProxy",4 "calls": [5 {6 "name": "QueryMetrics",7 "method": "GET",8 "endpoint": "/",9 "query_params": {10 "path": "/api/v1/query",11 "query": "{{metricQuery}}",12 "from": "{{fromTimestamp}}",13 "to": "{{toTimestamp}}"14 },15 "variables": [16 { "name": "metricQuery", "type": "String" },17 { "name": "fromTimestamp", "type": "Integer" },18 { "name": "toTimestamp", "type": "Integer" }19 ],20 "json_paths": {21 "metricName": "$.series[0].metric",22 "latestValue": "$.series[0].pointlist[-1][1]"23 }24 }25 ]26}Pro tip: Datadog metrics queries return rate-limited responses — the query API rate limit is per organization and is documented in Datadog's API reference with X-RateLimit-* response headers. Cache query results in Supabase or Firestore and refresh on a schedule rather than querying on every dashboard open to stay within limits.
Expected result: The API Group appears in FlutterFlow's left nav. The Test tab returns a Datadog metrics response for the metric query you entered. The ops dashboard screen shows live stat cards populated from Datadog metrics with color-coded health indicators.
Common use cases
Mobile app with crash reporting and RUM session monitoring
Build a FlutterFlow app that automatically reports crashes, slow network calls, and real user sessions to Datadog from day one in production. The datadog_flutter_plugin Custom Action initializes on app start, and navigation events are tracked as RUM views so you can see drop-off by screen. When a crash occurs, Datadog captures the stack trace, device model, OS version, and which RUM view the user was on.
Initialize Datadog RUM on app start with the correct site region, track each FlutterFlow screen navigation as a RUM view, and send a custom error log with the error message and stack trace whenever a caught exception occurs in the app.
Copy this prompt to try it in FlutterFlow
In-app ops dashboard showing live error rates for a founder
Build a screen in a FlutterFlow app that shows the current error rate, crash count, and active RUM session count for the production app — a founder-facing mobile dashboard that surfaces whether the app is healthy right now. The data comes from Datadog's query API via a proxy and is displayed as stat cards and a simple time-series chart.
Add an ops dashboard screen that queries a proxy endpoint for today's crash count and error rate from Datadog, displays them as stat cards with color-coded health indicators (green < 1%, yellow 1-5%, red > 5%), and includes a refresh button to re-fetch the data.
Copy this prompt to try it in FlutterFlow
Custom log pipeline for a background sync service
A FlutterFlow app with a background data sync feature uses Datadog's logger to emit structured JSON logs for every sync attempt, including the user ID, record count, duration, and success/failure status. Engineers query these logs in Datadog Log Management to debug sync failures for specific users and track sync performance over time without adding custom analytics infrastructure.
Add a sendDatadogLog Custom Action that accepts a log level (info, warn, error), a message string, and a map of key-value attributes, then calls Datadog's logger to emit a structured log with all attributes so it is queryable by field in Datadog Log Management.
Copy this prompt to try it in FlutterFlow
Troubleshooting
No RUM sessions or logs appear in Datadog after running on a real device
Cause: The most likely cause is a wrong site region in the SDK initialization. If the DatadogSite enum value does not match your account's actual site, data is sent to a valid Datadog infrastructure but the wrong organization — no error is thrown, data simply never appears in your account.
Solution: Double-check your account's site by looking at the URL when you are logged in to Datadog: app.datadoghq.com = us1, app.datadoghq.eu = eu1, app.us5.datadoghq.com = us5. Update the DatadogSite enum in your InitDatadog Custom Action to match. Also confirm you are testing in Run Mode on a real device, not in FlutterFlow's browser-based Test Mode — Custom Actions do not execute there.
403 Forbidden or empty response from the metrics proxy
Cause: The DD_BASE_URL in the proxy does not match the Datadog site region of your account. For example, the proxy is sending to api.datadoghq.com (US1) but your account is on EU1.
Solution: Update the DD_BASE_URL constant in your Firebase Cloud Function or Supabase Edge Function to match your account's site: api.datadoghq.eu for EU1, api.us5.datadoghq.com for US5. Redeploy the function and retry the query.
XMLHttpRequest error when calling the Datadog proxy from a FlutterFlow web build
Cause: The proxy function is missing CORS headers, so browser-based web builds are blocked by the browser's same-origin policy. Native iOS and Android builds do not enforce CORS.
Solution: Add `Access-Control-Allow-Origin: *` to the proxy response headers and handle OPTIONS preflight requests with a 204 status. The proxy code example in Step 4 includes this pattern. Redeploy the function after adding the headers.
Custom Action SDK builds fail on web with 'MissingPluginException' or compile errors
Cause: The `datadog_flutter_plugin` package has native platform code that does not compile for web targets without a platform guard.
Solution: Add `if (kIsWeb) return;` as the first line of every Datadog Custom Action function body, and add `import 'package:flutter/foundation.dart';` at the top. This prevents the native code path from being executed during web compilation and web runtime.
1import 'package:flutter/foundation.dart';2// Add this as the first line of every Datadog Custom Action:3if (kIsWeb) return;Best practices
- Always verify your Datadog site region before writing any code — wrong region = silent data loss with no error message.
- Never place the Datadog API key or Application key in a FlutterFlow API Call header — both are full-account secrets that must live in a Firebase Cloud Function or Supabase Edge Function proxy.
- Add kIsWeb guards in every Datadog Custom Action — the datadog_flutter_plugin package is native-only and will cause compile failures on web targets without the guard.
- Track RUM views explicitly on each FlutterFlow screen navigation using startView — Datadog Flutter RUM does not auto-detect screen transitions the way web SDKs do.
- Use consistent, URL-style view names across all screens so Datadog's RUM funnel analysis works correctly — inconsistent naming fragments your session data.
- Cache Datadog query API responses in Supabase or Firestore and refresh on a schedule — the query API has rate limits, and metrics change slowly enough that live polling every screen open is wasteful.
- Test Datadog initialization exclusively in Run Mode on a real device — Custom Actions do not run in FlutterFlow's browser-based preview canvas.
- Add user context attributes to Datadog RUM (user_id, user_plan) immediately after sign-in so sessions in Datadog are filterable by user segment.
Alternatives
New Relic offers a similar RUM and APM feature set with a mobile Flutter SDK, and its free tier includes more data than Datadog's — a better fit for early-stage apps with limited observability budget.
Sumo Logic focuses on log aggregation via a simple HTTP POST to a tokenized URL with no SDK required — a much simpler setup for teams that only need centralized logging rather than full RUM and APM.
Grafana is an open-source visualization layer that can display metrics from many backends including Prometheus — a good choice for teams already running their own infrastructure who want to avoid Datadog's per-session pricing.
Frequently asked questions
Can I use the datadog_flutter_plugin in FlutterFlow without writing any code?
No — Datadog does not have a native FlutterFlow integration, so you must use a Custom Action to wrap the pub.dev SDK. However, the code required is straightforward: one initialization Custom Action, one view-tracking Custom Action, and optionally one logging Custom Action. FlutterFlow handles the pub.dev dependency installation when you add the package name in the Custom Action dependencies field.
What is the difference between a Datadog client token and an API key?
A client token (prefix pub_) is write-only: it can only send data to Datadog under the specific RUM application it was generated for. It cannot read data back. An API key is a full-account secret used by the query API to read metrics, logs, and RUM data — it belongs only in your server-side proxy, never in the app. The Application key is a third credential needed alongside the API key for certain query operations. All three are different credentials with different access scopes.
Why does my Datadog RUM show no screen names, just generic views?
Datadog Flutter RUM does not auto-detect FlutterFlow screen navigations the way a web SDK detects page URL changes. You must explicitly call the startView action on each screen's On Page Load event, passing a consistent view name and URL-style path. Without this, Datadog records a single unnamed view for the entire session regardless of which screens the user visited.
Does Datadog have a free tier for Flutter RUM?
Datadog offers a free trial period. After the trial, RUM is billed per 1,000 sessions on paid plans — check Datadog's current pricing page for exact costs, as plans change. Some Datadog features like log management and APM traces have separate pricing from RUM. For early-stage apps with low session volume, the cost is typically modest; it scales with your user base.
Can I send logs to Datadog without using the SDK?
Yes — Datadog has an HTTP log intake API that accepts JSON log entries via a direct POST request. If you only need centralized logging and not full RUM or APM, you can use a FlutterFlow API Call through a proxy to POST logs directly without the Custom Action SDK approach. However, RUM features (session tracking, screen views, crash reports) require the SDK.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation