Hotjar works only on FlutterFlow's published web app — it cannot record native iOS or Android sessions. Inject the Hotjar JavaScript snippet into your web build's index.html using FlutterFlow's custom head code field, then switch the Flutter web renderer from CanvasKit to HTML mode so Hotjar can read the DOM and generate meaningful heatmaps. Native mobile apps need a different analytics tool.
| Fact | Value |
|---|---|
| Tool | Hotjar |
| Category | Analytics |
| Method | Custom Widget |
| Difficulty | Beginner |
| Time required | 25 minutes |
| Last updated | July 2026 |
Understanding What Hotjar Can (and Cannot) Do in FlutterFlow
Before investing time in this integration, it is critical to understand the honest scope: Hotjar is a JavaScript-based website analytics tool. It records browser sessions by reading the DOM, listening to mouse movements and clicks, and capturing screenshots of the page layout. It has no mobile SDK, no Dart package on pub.dev, and no way to instrument a native iOS or Android app. If your primary FlutterFlow deployment is a mobile app, Hotjar is simply the wrong tool — see the Alternatives section for mobile session recording options.
Hotjar works with FlutterFlow under one specific condition: your app is published as a web app (via FlutterFlow's web deployment or exported and hosted on Netlify/Firebase Hosting). Even then, there is a critical technical hurdle. Flutter Web defaults to the CanvasKit renderer, which draws your entire app UI onto a single HTML canvas element. Hotjar cannot read individual UI components from a canvas — it sees one opaque image, so heatmaps will show all clicks landing on a single point and session recordings will show a blank or scrambled canvas. The fix is to switch Flutter Web to the HTML renderer mode, which generates a proper (though non-semantic) shadow DOM tree that Hotjar can interpret. This trade-off reduces visual fidelity slightly but makes Hotjar's data meaningful.
Hotjar's Site ID is a public identifier — it appears in the script snippet visible to anyone who views your page source. There is no secret to protect on the Hotjar side. The integration cost is Hotjar's pricing tier: a free plan is available with limited recordings and heatmaps; check hotjar.com/pricing for current limits as they change periodically.
Integration method
Hotjar is a client-side JavaScript tracking tool with no Flutter SDK and no mobile support. The integration works by injecting Hotjar's tracking script into the HTML head of your FlutterFlow web build. Because Flutter Web renders to either a single canvas element (CanvasKit) or an HTML shadow DOM (HTML renderer), you must switch to the HTML renderer to give Hotjar readable DOM nodes for heatmaps and session recordings. This integration is strictly for web — native iOS and Android builds cannot use Hotjar.
Prerequisites
- A FlutterFlow project that targets the web deployment (either via FlutterFlow's Publish to Web feature or by exporting and hosting the build)
- A Hotjar account with a site created — the free Basic plan works for initial testing
- Your Hotjar Site ID (found in Hotjar → Sites & Organizations → your site → Tracking Code — it is a public number like 3456789)
- Understanding that this integration will NOT work on iOS or Android native builds — those require a different tool
- Access to FlutterFlow's project settings to modify web platform configuration
Step-by-step guide
Create a Hotjar site and copy your Site ID
Go to hotjar.com and sign in or create a free account. Once inside the Hotjar dashboard, click 'Add new site' in the top navigation. Enter your website URL — this should match the URL where your FlutterFlow web app will be published (e.g., `https://myapp.flutterflow.app` or your custom domain). Give the site a name and select your industry for better default settings. After creating the site, Hotjar will show you a JavaScript snippet to install. The snippet looks like this: ``` (function(h,o,t,j,a,r){ h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)}; h._hjSettings={hjid:YOUR_SITE_ID,hjsv:6}; ... })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv='); ``` The critical value in this snippet is `hjid: YOUR_SITE_ID` — a number like `3456789`. This is your Hotjar Site ID. Copy the entire snippet, not just the ID number. The Site ID is not a secret — it is a public tracker identifier that appears in your page's HTML source code for anyone to see. There is nothing to protect here. Keep this snippet copied to your clipboard for the next step.
Pro tip: Set up two Hotjar sites — one for your production URL and one for your staging URL — to avoid mixing development traffic with real user data in your heatmaps and recordings.
Expected result: You have the Hotjar tracking snippet and your Site ID copied, and the Hotjar dashboard is showing 'Waiting for data...' — it will stay in this state until you inject the script and send traffic.
Inject the Hotjar script into your FlutterFlow web build
FlutterFlow provides a way to add custom code to the HTML head of your web build without manually editing files after every export. In FlutterFlow, click the gear icon in the bottom-left navigation → 'Web Settings' (this may appear as 'Settings' → 'Web Platform' depending on your FlutterFlow version). Look for a field labeled 'Custom Code in Head' or 'Head HTML'. Paste the full Hotjar tracking snippet into this field. Click Save. This tells FlutterFlow to inject the snippet into the `<head>` section of the generated `web/index.html` file every time you publish or export the web build. If you do not see a 'Custom Code in Head' field in your FlutterFlow version (some older versions do not expose it), the alternative is to manually add the snippet to the `web/index.html` file after exporting your project. Export your project as a ZIP (Settings → Export → Download Project), unzip it, open `web/index.html`, and paste the Hotjar snippet between the `<head>` and `</head>` tags. Then re-host the build. Note that every new FlutterFlow export will overwrite this manual edit — use FlutterFlow's built-in head code field if possible to avoid this maintenance burden. Do NOT add any server-side secrets here. The Hotjar snippet contains only your public Site ID and references Hotjar's CDN — nothing sensitive.
1<!-- Hotjar Tracking Code - paste into FlutterFlow Web Settings > Custom Code in Head -->2<script>3 (function(h,o,t,j,a,r){4 h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};5 h._hjSettings={hjid:YOUR_SITE_ID,hjsv:6};6 a=o.getElementsByTagName('head')[0];7 r=o.createElement('script');r.async=1;8 r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;9 a.appendChild(r);10 })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');11</script>Pro tip: Replace YOUR_SITE_ID with your actual numeric Site ID from the Hotjar dashboard. The snippet above is a template — Hotjar's dashboard gives you the pre-filled version with your ID already inserted.
Expected result: The Hotjar snippet appears in FlutterFlow's Custom Code in Head field. On the next publish, the script will be included in your web build's HTML.
Switch the Flutter web renderer to HTML mode
This is the most important and least obvious step. Flutter Web has two rendering modes: CanvasKit (the default) and HTML. CanvasKit renders the entire Flutter UI onto a single HTML `<canvas>` element using WebAssembly — this gives excellent visual fidelity and performance but produces a page that is essentially a black box to JavaScript tools like Hotjar. When Hotjar tries to detect clicks, it sees only the canvas; when it generates a heatmap, all clicks appear to land on the same canvas element; session recordings show the page correctly visually but Hotjar cannot identify which widget was clicked. HTML renderer mode renders Flutter widgets into an HTML DOM tree (using shadow DOM elements and CSS). The result looks slightly different (some shadows, gradients, and custom fonts render differently) but gives Hotjar enough structure to generate meaningful heatmaps and click maps. To switch to HTML renderer in FlutterFlow: go to Settings → Web Settings (or Web Platform) → look for 'Renderer' or 'Web Renderer' dropdown. Select 'HTML' instead of 'CanvasKit' or 'Auto'. If you do not see this setting in your FlutterFlow version, you can set the renderer at the URL level: when your web app loads, append `?renderer=html` to the URL. This is a quick test method — use FlutterFlow's setting for the permanent production configuration. After switching the renderer, republish your web app and test: open the site in Chrome → DevTools → Elements. You should see HTML elements like `<flt-scene>` and `<flt-clip>` in the DOM tree rather than a single `<canvas>` element. This confirms HTML renderer is active and Hotjar can read the page.
Pro tip: Test both renderers on your most complex screen before committing to HTML mode for production. Some FlutterFlow UI components (particularly complex animations and custom shaders) may look slightly different in HTML mode. For a marketing page or onboarding flow, the difference is usually negligible.
Expected result: Your published FlutterFlow web app loads with the HTML renderer active (visible as DOM elements in browser DevTools rather than a single canvas), and Hotjar's status in its dashboard changes from 'Waiting for data' to 'Tracking' within a few minutes of the first real browser visit.
Publish your web app and verify Hotjar is tracking
Click the Publish button in FlutterFlow (the rocket icon or 'Publish' in the top-right area) and publish your web app. Wait for the deployment to complete (usually 30-90 seconds). Open the published URL in an incognito browser window — using incognito prevents any Hotjar ignore-list rules from filtering out your own visits if you have the Hotjar browser extension installed. Browse through a few pages, click around, and scroll up and down. Go back to the Hotjar dashboard → your site. The status indicator should change from 'Waiting for data' to an active/green state within a few minutes of your first page visit. Open 'Heatmaps' in the Hotjar left sidebar and create a new heatmap for your main page URL. Similarly, check 'Recordings' to see if your session was captured. If Hotjar shows tracking as active but heatmaps appear blank or show clicks only in one spot, the HTML renderer is still not active — re-confirm the renderer setting and republish. For production use, configure Hotjar's suppression rules to exclude certain user segments (internal team, specific IP ranges) so that employee usage does not pollute your heatmap data. This is in Hotjar → Settings → Suppress → Suppress from Recordings. Also review Hotjar's consent requirements for your region: in the EU/EEA, GDPR typically requires user consent before Hotjar can record sessions — Hotjar has a built-in consent widget you can enable.
Pro tip: After your first publish with Hotjar enabled, wait at least 5-10 real user visits (not just your own test visit) before evaluating heatmaps. Hotjar needs a minimum sample to generate statistically meaningful maps.
Expected result: Hotjar's dashboard shows your site as actively tracking. Session recordings and heatmap data begin appearing within a few minutes of real user visits.
Understand the limitations and plan for mobile analytics
Now that Hotjar is running on your web build, it is important to document the known limitations for your team so expectations are correctly set: Hotjar heatmaps in HTML renderer mode capture meaningful click and scroll data, but because Flutter's HTML renderer does not generate semantic HTML elements (no standard `<button>`, `<nav>`, or `<article>` tags), Hotjar cannot label click targets by their role. Every click target is an anonymous `<flt-*>` shadow DOM element. Heatmaps will show WHERE users click on the visual layout, but Hotjar cannot tell you 'users clicked the Submit button' the way it would on a standard HTML website. This is a fundamental Flutter Web limitation, not a Hotjar configuration issue. For native iOS and Android builds, Hotjar simply cannot run. If you need session recording, crash replay, or touch heatmaps on your native app, consider these alternatives that do have Flutter/Dart SDKs: Microsoft Clarity (free, has a Flutter plugin), PostHog (open source, has an unofficial Flutter library), or Instabug (mobile-focused crash reporting and user feedback with session replay). For in-app behavioral analytics (not visual recording), Mixpanel or Amplitude via API Call are the correct tools. If you're building both a mobile app and a web app, the recommended setup is: Hotjar for web heatmaps + Amplitude/Mixpanel API Calls for mobile behavioral events. RapidDev's team can help set up both analytics layers in a single FlutterFlow project — free scoping call at rapidevelopers.com/contact.
Pro tip: Document clearly in your project README that Hotjar is web-only. Future team members discovering the integration may incorrectly assume it covers mobile builds and be confused when no mobile data appears in the Hotjar dashboard.
Expected result: Your team understands Hotjar's web-only scope, the HTML renderer trade-off, and which tools to use for mobile session analytics.
Common use cases
Web-based onboarding flow with heatmap analysis
A FlutterFlow web app published for desktop/browser use captures Hotjar heatmaps on the onboarding screen. The team identifies that users are clicking on a decorative element thinking it is a button, which reveals a confusing UI pattern. They fix the layout and re-test with a new Hotjar heatmap to confirm the improvement.
I want to see heatmaps on my web app's onboarding page to find out where users click and scroll — set up Hotjar tracking on my FlutterFlow web build.
Copy this prompt to try it in FlutterFlow
Session recording for a support team's internal web tool
A FlutterFlow web tool used by a support team on desktop browsers has Hotjar session recording enabled. When a support agent reports a confusing workflow, the product team reviews Hotjar recordings of real sessions to see exactly which steps cause hesitation. This replaces hours of user interviews with direct observation.
Enable Hotjar session recording on our internal web dashboard so we can watch how support agents use the tool and identify friction points.
Copy this prompt to try it in FlutterFlow
Landing page funnel with Hotjar scroll maps
A marketing landing page built in FlutterFlow and deployed as a web app uses Hotjar scroll maps to determine how far down the page most visitors read before leaving. The team discovers that the pricing section is below the fold for 70% of mobile browser users and moves it higher, increasing conversion.
I want scroll maps on my FlutterFlow web landing page to see how far visitors scroll before leaving — add Hotjar tracking so I can analyze the data.
Copy this prompt to try it in FlutterFlow
Troubleshooting
Hotjar dashboard shows 'Waiting for data' after publishing — no tracking activity detected
Cause: The tracking script was not successfully injected into the published web build's HTML head, or the FlutterFlow web build was published before saving the custom head code snippet.
Solution: Open your published web app URL in Chrome → right-click → 'View Page Source'. Search for 'hotjar' in the source. If you do not find it, the snippet was not injected. Re-check FlutterFlow's Web Settings → Custom Code in Head field, confirm the snippet is saved there, and republish. If you edited web/index.html manually after export, remember that republishing overwrites manual file edits.
Hotjar heatmaps show all clicks in one spot or the recordings show a blank/garbled canvas
Cause: Your FlutterFlow web app is using the CanvasKit renderer (the default). CanvasKit renders the entire Flutter UI onto a single HTML canvas element, making all click coordinates land on the same canvas target and making the visual content opaque to Hotjar.
Solution: Switch the Flutter web renderer to HTML mode in FlutterFlow's Web Settings → Renderer → set to 'HTML'. Republish the app. Verify the switch worked by opening DevTools → Elements and confirming you see `<flt-scene>` elements instead of a single `<canvas>`. After switching, new heatmap sessions will show individual click positions spread across the page layout.
Hotjar records sessions on web but shows zero data for mobile app users
Cause: This is expected behavior, not a bug. Hotjar is a browser-only JavaScript tool. When users open your FlutterFlow app on iOS or Android (native builds), they are running compiled Dart code in a native runtime — no JavaScript, no DOM, no Hotjar.
Solution: Accept that Hotjar covers only your web deployment. For native mobile session recording, evaluate Microsoft Clarity (free Flutter plugin), PostHog, or Instabug. For behavioral event analytics on mobile, use Mixpanel or Amplitude via FlutterFlow API Calls — both have HTTP ingestion endpoints that work on all platforms.
FlutterFlow re-exports overwrite the manually edited web/index.html and remove the Hotjar snippet
Cause: FlutterFlow generates web/index.html from scratch on every export. Any manual edits to this file are lost when you export again.
Solution: Use FlutterFlow's built-in 'Custom Code in Head' field in Web Settings instead of manually editing the exported file. The built-in field is preserved across exports and publishes. If your FlutterFlow version does not have this field, check for a newer FlutterFlow version or use the URL query parameter `?renderer=html` as a temporary workaround while you file a feature request.
Best practices
- Always clarify to your team upfront that Hotjar tracks only your FlutterFlow web build — never native iOS or Android sessions. Document this in your project README to prevent confusion.
- Use HTML renderer mode (not CanvasKit) when Hotjar is active. Heatmaps and session recordings are meaningless with CanvasKit because all clicks land on a single canvas element.
- Use FlutterFlow's Custom Code in Head field to inject the Hotjar snippet rather than manually editing exported files — manual edits are overwritten on every export or publish.
- Set up two Hotjar sites — one for production and one for staging — to prevent developer/test traffic from polluting your heatmap data.
- Configure Hotjar's consent banner if your users are in the EU/EEA. GDPR requires explicit consent before recording sessions. Hotjar's built-in consent widget integrates with your privacy policy URL.
- Gate Hotjar injection to production only. If your web app has environment-specific builds, ensure the Hotjar snippet only appears in your production URL's HTML, not in development or preview URLs.
- Use Hotjar's suppression feature to exclude recordings of form fields that contain personal data (passwords, credit card numbers). Hotjar can automatically mask `<input>` fields, but because Flutter HTML renderer uses custom elements, you may need to configure manual suppression by coordinate region.
- Pair Hotjar (web heatmaps) with Amplitude or Mixpanel (cross-platform event analytics) for complete coverage of user behavior across both your web and native mobile deployments.
Alternatives
Mixpanel works on both native mobile and web via a FlutterFlow API Call — the right choice when you need cross-platform event analytics that covers iOS, Android, and web in one tool.
Amplitude offers the same cross-platform event tracking as Mixpanel with a particularly clean HTTP V2 ingestion API and strong retention analysis built for mobile-first teams.
FullStory offers both web session recording (similar to Hotjar) and a mobile SDK for native iOS/Android session replay, making it a better choice if you need visual session recording across all platforms.
Frequently asked questions
Can Hotjar record sessions in my FlutterFlow iOS or Android app?
No. Hotjar is a JavaScript-only tool designed for web browsers. When users open your FlutterFlow app on iOS or Android, they are running compiled Dart code in a native environment with no browser, no JavaScript engine, and no DOM. Hotjar has no Flutter SDK and no way to instrument native apps. For mobile session recording, look at Microsoft Clarity (free, Flutter plugin available) or Instabug.
Why do my Hotjar heatmaps look blank or show all clicks in one spot?
This almost always means your FlutterFlow web app is using the CanvasKit renderer. CanvasKit draws the entire Flutter UI onto a single HTML canvas element, so Hotjar cannot distinguish individual click targets — all clicks register as hitting the canvas. Switch to the HTML renderer in FlutterFlow's Web Settings and republish. After the switch, new sessions will generate proper click distribution maps.
Does Hotjar require GDPR consent if my users are in Europe?
Yes. GDPR classifies session recordings and heatmaps as processing of personal data (they can capture behavioral data and potentially sensitive information). If your web app serves EU/EEA users, you must obtain explicit consent before Hotjar begins tracking. Hotjar provides a built-in consent widget you can enable in the Hotjar dashboard under Settings → Consent and GDPR. The widget displays a banner and only activates tracking after the user accepts.
Will the Hotjar script slow down my FlutterFlow web app?
The Hotjar script loads asynchronously (note the `r.async=1` in the snippet), so it does not block your FlutterFlow web app from rendering. However, it does add an additional network request to Hotjar's CDN and runs JavaScript in the background to capture mouse movements and DOM changes. On typical web connections this impact is negligible, but on very slow connections or low-powered devices you may notice a slight increase in memory usage. The performance impact is similar to any third-party analytics script.
What does Hotjar's free plan include?
Hotjar's free Basic plan includes a limited number of daily session recordings and heatmap snapshots — check hotjar.com/pricing for current limits as they are updated periodically. The free plan is sufficient to validate whether Hotjar provides useful data on your FlutterFlow web app before committing to a paid tier. For most early-stage products with fewer than a few hundred daily users, the free plan provides enough data to make design decisions.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation