Add augmented reality to FlutterFlow using ar_flutter_plugin as a Custom Widget. Configure ARCore (Android) and ARKit (iOS) permissions and capabilities in the platform files. Show the AR camera view, enable plane detection, and let users tap to place .glb/.gltf 3D models anchored to real-world surfaces. Always check AR device support before initializing and show a 3D model viewer fallback for unsupported devices.
Add 'view in your room' AR product visualization or any 3D placement feature to your FlutterFlow app
Augmented reality lets users place virtual objects in their real environment through the camera — the most impactful use case for e-commerce apps is 'view in your room', letting customers see how furniture or decor looks in their space before buying. FlutterFlow supports AR through Custom Widgets using the ar_flutter_plugin package, which wraps ARCore (Android) and ARKit (iOS) in a unified Flutter API. This tutorial covers installing the package, configuring platform permissions, building the AR view with plane detection and tap-to-place interaction, loading 3D models from Firebase Storage, and handling the wide range of AR-capable and AR-incapable devices your users will have.
Prerequisites
- FlutterFlow Pro plan (AR Custom Widget requires downloading code and configuring iOS/Android platform files)
- A 3D model in .glb or .gltf format (convert from common formats using Blender or online converters at gltf.report)
- An Android device with ARCore support (Pixel 2+, Samsung Galaxy S8+, most modern Android phones) or iPhone 6s+ for testing
- Firebase project with Storage enabled for hosting 3D model files
Step-by-step guide
Add ar_flutter_plugin as a Custom Widget and configure Pubspec
Add ar_flutter_plugin as a Custom Widget and configure Pubspec
In FlutterFlow, go to Custom Code → Pubspec Dependencies → Add Dependency → type ar_flutter_plugin and add the current stable version. Also add vector_math and flutter_cache_manager as dependencies — ar_flutter_plugin uses these internally. Click Save. Next, add the Custom Widget: Custom Code → Custom Widgets → Add Widget. Name it ARView. Set the widget dimensions to take the full available space (isFullPage: true or give it flexible width/height). In the Custom Widget code editor, import the ar_flutter_plugin package and create the ARWidget. Add a parameter to the Custom Widget: modelUrl (String) — this will receive the 3D model URL from the parent page. Add optional parameters: onObjectPlaced (Action) to notify the parent page when a model is placed, and initialScale (double) defaulting to 0.5 for the model size. The ARView Custom Widget is a StatefulWidget that creates an ARSessionManager and ARObjectManager in initState and disposes them in dispose.
1// Custom Widget: ARView2// Pubspec: ar_flutter_plugin, vector_math3// Parameters: modelUrl (String), initialScale (double)45import 'package:flutter/material.dart';6import 'package:ar_flutter_plugin/ar_flutter_plugin.dart';7import 'package:ar_flutter_plugin/datatypes/config_planedetection.dart';8import 'package:ar_flutter_plugin/datatypes/node_types.dart';9import 'package:ar_flutter_plugin/managers/ar_anchor_manager.dart';10import 'package:ar_flutter_plugin/managers/ar_location_manager.dart';11import 'package:ar_flutter_plugin/managers/ar_object_manager.dart';12import 'package:ar_flutter_plugin/managers/ar_session_manager.dart';13import 'package:ar_flutter_plugin/models/ar_anchor.dart';14import 'package:ar_flutter_plugin/models/ar_node.dart';15import 'package:vector_math/vector_math_64.dart' as vector;1617class ARViewWidget extends StatefulWidget {18 final String modelUrl;19 final double initialScale;20 const ARViewWidget({21 required this.modelUrl,22 this.initialScale = 0.5,23 Key? key,24 }) : super(key: key);2526 @override27 State<ARViewWidget> createState() => _ARViewWidgetState();28}2930class _ARViewWidgetState extends State<ARViewWidget> {31 ARSessionManager? arSessionManager;32 ARObjectManager? arObjectManager;33 ARAnchorManager? arAnchorManager;34 ARNode? placedNode;35 List<ARAnchor> anchors = [];3637 @override38 void dispose() {39 arSessionManager?.dispose();40 super.dispose();41 }4243 @override44 Widget build(BuildContext context) {45 return ARView(46 onARViewCreated: _onARViewCreated,47 planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical,48 );49 }5051 void _onARViewCreated(52 ARSessionManager sessionMgr,53 ARObjectManager objectMgr,54 ARAnchorManager anchorMgr,55 ARLocationManager locationMgr,56 ) {57 arSessionManager = sessionMgr;58 arObjectManager = objectMgr;59 arAnchorManager = anchorMgr;6061 arSessionManager!.onInitialize(62 showFeaturePoints: false,63 showPlanes: true, // Show detected planes as translucent surfaces64 showWorldOrigin: false,65 );66 arObjectManager!.onInitialize();6768 // Place object when user taps on a detected plane69 arSessionManager!.onPlaneOrPointTap = _onPlaneTapped;70 }7172 Future<void> _onPlaneTapped(List<ARHitTestResult> hits) async {73 if (hits.isEmpty) return;7475 // Remove previously placed node76 if (placedNode != null) {77 arObjectManager?.removeNode(placedNode!);78 }7980 final hit = hits.first;81 final anchor = ARPlaneAnchor(transformation: hit.worldTransform);82 final bool anchorAdded = await arAnchorManager!.addAnchor(anchor);83 if (!anchorAdded) return;84 anchors.add(anchor);8586 // Place the 3D model at the tapped location87 final node = ARNode(88 type: NodeType.webGLB, // Remote .glb URL89 uri: widget.modelUrl,90 scale: vector.Vector3(91 widget.initialScale,92 widget.initialScale,93 widget.initialScale,94 ),95 position: vector.Vector3(0.0, 0.0, 0.0),96 rotation: vector.Vector4(1.0, 0.0, 0.0, 0.0),97 );9899 await arObjectManager!.addNode(node, planeAnchor: anchor);100 placedNode = node;101 }102}Expected result: ARView Custom Widget compiles successfully and appears in your FlutterFlow widget library. The widget takes a modelUrl parameter.
Configure Android ARCore and iOS ARKit platform requirements
Configure Android ARCore and iOS ARKit platform requirements
After downloading your FlutterFlow project code, configure the native platform files for AR. For Android: open android/app/build.gradle and confirm minSdkVersion is 24 (ARCore requires Android 7.0+). Open android/app/src/main/AndroidManifest.xml and add inside the manifest element: <uses-permission android:name='android.permission.CAMERA' />, and inside the application element: <meta-data android:name='com.google.ar.core' android:value='required' /> (use 'optional' if AR is a bonus feature, not required). For iOS: open ios/Runner/Info.plist and add: NSCameraUsageDescription key with value explaining why you need camera access ('This app uses the camera to view 3D models in your space'). Open ios/Runner.xcodeproj in Xcode → select Runner target → Signing & Capabilities → + Capability → add 'Camera'. Minimum iOS version must be 11.0. In your Flutter project root, the pubspec.yaml should have arcore_flutter_plugin under dependency_overrides if you encounter version conflicts. These platform configurations are required for App Store and Google Play submission.
Expected result: The app builds on Android and iOS without permission errors. The device prompts for camera permission on first AR session initialization.
Check device AR support and show a 3D model viewer fallback
Check device AR support and show a 3D model viewer fallback
Not all devices support AR — ARCore is available on most Android devices from 2018 onward, but older Android and some budget devices are not supported. ARKit requires iPhone 6s+ (iOS 11+). Your app must check support before initializing AR and show a fallback experience. Create a Custom Action named checkARSupport that returns a Boolean — true if AR is supported, false if not. In FlutterFlow, on the AR feature page: on page load, call checkARSupport Custom Action. If the result is true, show the ARView Custom Widget. If false, show a fallback Container with a model_viewer Custom Widget (using the model_viewer_plus package) that displays the 3D model in an interactive 3D viewer without AR — users can rotate and zoom the model but cannot place it in their room. The fallback must show the model, not just an error message — 'View in 3D' is a valuable fallback even without AR.
1// Custom Action: checkARSupport2// Returns: bool — true if device supports AR3import 'package:ar_flutter_plugin/ar_flutter_plugin.dart';45Future<bool> checkARSupport() async {6 try {7 // Check if ARCore (Android) or ARKit (iOS) is available8 final bool isARCoreSupported = await ArCoreController.checkIfARCoreApkIsUpdated()9 .then((_) => true)10 .catchError((_) => false);11 return isARCoreSupported;12 } catch (e) {13 return false;14 }15}1617// Alternative: simpler platform check18import 'dart:io';19Future<bool> checkARSupportSimple() async {20 if (Platform.isIOS) {21 // ARKit available on iPhone 6s+ with iOS 11+22 // Basic check — full check requires ARSession.isSupported23 return true; // Handle unsupported in ARKit error callback24 } else if (Platform.isAndroid) {25 // ARCore check via ar_flutter_plugin26 try {27 final availability = await checkARCoreAvailability();28 return availability == ARCoreAvailability.supportedAndUpdated ||29 availability == ARCoreAvailability.supportedApkTooOld;30 } catch (e) {31 return false;32 }33 }34 return false;35}Expected result: On AR-supported devices, the ARView widget appears with the camera and plane detection. On unsupported devices, a 3D model viewer is shown instead.
Upload 3D models to Firebase Storage and load them dynamically
Upload 3D models to Firebase Storage and load them dynamically
Static AR demos use hardcoded model URLs, but production AR features load models dynamically — different products show their own 3D models. Upload your .glb files to Firebase Storage: in Firebase Console → Storage → Upload file, or use FlutterFlow's File Upload button with a Cloud Function to handle admin uploads. Store the model URL in the Firestore product document: a field named arModelUrl (String). In FlutterFlow, on the ProductDetail page, the Backend Query fetches the product including the arModelUrl field. Pass this URL as the modelUrl parameter to your ARView Custom Widget using Set from Variable → Backend Query Result → arModelUrl. Add an 'AR View' button on the product page that navigates to a fullscreen AR page, passing the arModelUrl as a page parameter. On the AR page, place the ARView Custom Widget and bind modelUrl to the page parameter. Add a back arrow overlay button in a Stack on top of the AR view so users can return to the product page.
Expected result: Different products on the catalog page each have their own 3D model URL. Tapping 'View in AR' launches the AR page with that product's specific .glb model loaded.
Add AR controls overlay — scale, rotate, and remove object
Add AR controls overlay — scale, rotate, and remove object
The basic tap-to-place interaction is the minimum viable AR experience, but users also need to resize and rotate the placed object. Add an overlay UI on top of the ARView using a Stack widget: place the ARView as the bottom layer, and a Column of controls as the top layer positioned at the bottom of the screen. Add a Slider widget for scale: bind to a Page State variable objectScale (Double, initial: 0.5, min: 0.1, max: 2.0). On slider change, call a Custom Action named updateNodeScale that calls arObjectManager.updateNodeScale(placedNode, newScale). Add rotation buttons: left arrow and right arrow icon buttons, each calling updateNodeRotation Custom Action with +/- 15 degree increments. Add a trash icon button that removes the placed object: calls arObjectManager.removeNode(placedNode) and arAnchorManager.removeAnchor(lastAnchor). Add a 'Capture' icon button that calls Custom Action takeScreenshot to capture the AR view as an image: uses RenderRepaintBoundary to capture the screen and saves to the camera roll or Firebase Storage for sharing.
Expected result: Users can scale the AR object with a slider, rotate it with arrow buttons, remove it with a trash icon, and capture a screenshot of the AR scene.
Complete working example
1Pubspec Dependencies2=====================3ar_flutter_plugin: ^0.7.34vector_math: ^2.1.45flutter_cache_manager: ^3.3.16model_viewer_plus: ^1.8.0 (fallback viewer)78Android Platform Config (AndroidManifest.xml)9===============================================10<uses-permission android:name='android.permission.CAMERA' />11<application>12 <meta-data13 android:name='com.google.ar.core'14 android:value='optional' />15</application>16minSdkVersion: 24 (Android 7.0)1718iOS Platform Config (Info.plist)19==================================20NSCameraUsageDescription: 'Camera is used to place 3D models in your space'21Minimum iOS version: 11.02223FlutterFlow Page Architecture24==============================25ProductDetail (param: productId)26 Backend Query: products/{productId}27 Fields: title, price, imageUrl, arModelUrl28 ├── Image (imageUrl)29 ├── Text (title + price)30 └── Button: 'View in AR'31 Navigate → ARViewPage (param: modelUrl = arModelUrl)3233ARViewPage (param: modelUrl)34 Stack:35 ├── ARViewWidget (modelUrl = page param)36 │ AR Features:37 │ PlaneDetection: horizontal + vertical38 │ OnTap: place model at hit location39 │ NodeType: webGLB (remote URL)40 └── Overlay Column (bottom of screen)41 ├── Slider (scale: 0.1 → 2.0)42 ├── Row (rotate left | rotate right)43 ├── IconButton (remove model)44 └── IconButton (capture screenshot)4546Page State Variables:47 objectScale: Double (0.5)48 isARSupported: Boolean (checked on init)49 isModelLoading: Boolean (true while .glb downloads)5051Firestore Product Document:52 arModelUrl: String53 → Firebase Storage path54 → gs://project.appspot.com/models/sofa.glb55 → or public HTTPS URL5657Fallback (non-AR devices):58 → ModelViewerWidget (model_viewer_plus)59 → Interactive 3D viewer: rotate, zoom60 → No plane detection or real-world placementCommon mistakes
Why it's a problem: Not checking device AR support before initializing ARCore/ARKit and showing a crash or blank screen to users on unsupported devices
How to avoid: Call checkARSupport() on page load using a Custom Action. If false, show a 3D model viewer fallback using model_viewer_plus instead of the AR view. Never initialize the ARSessionManager on an unsupported device. Display a clear message: 'Your device does not support AR — here is a 3D view instead'.
Why it's a problem: Loading large 3D model files (10-50MB) directly in the AR view without optimization, causing 30+ second load times or out-of-memory crashes
How to avoid: Optimize 3D models before upload: use Blender, Draco compression, or gltf.report to reduce file size to under 5MB. Reduce texture resolution to 1024×1024 maximum. Use Draco geometry compression (built into glTF). A well-optimized furniture model for 'view in room' AR should be under 3MB and load in under 5 seconds on LTE.
Why it's a problem: Testing AR features in FlutterFlow's browser preview or on an emulator and concluding the AR integration is broken when it shows nothing
How to avoid: AR features MUST be tested on physical devices. Use FlutterFlow's Run mode on a connected physical phone (Android via USB debugging, or TestFlight for iOS). Download the code and run it natively for full AR testing. Keep an ARCore-supported Android phone or iPhone 6s+ as your primary AR testing device.
Best practices
- Always test AR on physical devices — emulators and browser preview cannot run AR sessions
- Use 'optional' rather than 'required' for ARCore in AndroidManifest.xml unless AR is the core value proposition — 'required' excludes non-ARCore devices from downloading the app at all
- Optimize 3D models to under 5MB before uploading to Firebase Storage — use Draco compression and 1024x1024 textures
- Show plane detection visualization (translucent surfaces) while scanning so users know where they can tap to place objects
- Provide a scale slider immediately — first-time AR users almost always place objects at the wrong scale and need to resize
- Add a 'Capture Screenshot' feature — users sharing AR product photos to social media is the highest organic marketing channel for e-commerce AR features
- Cache downloaded 3D models using flutter_cache_manager so repeat AR sessions for the same product do not re-download the model
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I am building a FlutterFlow e-commerce app and want to add AR 'view in room' product visualization using ar_flutter_plugin. Write a Flutter Custom Widget StatefulWidget that: (1) initializes an ARSessionManager and ARObjectManager, (2) enables horizontal plane detection, (3) places a .glb model from a URL parameter at the location where the user taps a detected plane, (4) disposes the AR session in the dispose method. Include vector_math imports and the AR anchor placement pattern.
Add an ARViewPage to my project with an ARView Custom Widget that takes a modelUrl page parameter. Add a Stack with the AR view as the background and an overlay at the bottom containing a Slider for scale (0.1 to 2.0), left/right rotation buttons, and a remove button. Add a back arrow button at the top left to return to the product page.
Frequently asked questions
What devices support ARCore and ARKit?
ARCore (Android): most Android devices running Android 7.0+ from major manufacturers (Google, Samsung, OnePlus, Xiaomi, Sony, LG from ~2018 onward). Check the full supported devices list at developers.google.com/ar/devices. ARKit (iOS): iPhone 6s and newer, iPad (5th generation and newer), iPad Pro all models, iPod touch 7th generation. Requires iOS 11+. ARKit is available on a broader percentage of iOS devices than ARCore is on Android, since Apple controls the hardware platform.
What 3D file formats work with ar_flutter_plugin?
ar_flutter_plugin supports .glb (binary GLTF) and .gltf (JSON-based GLTF) formats. These are the standard formats for web and mobile AR. To convert from other formats: OBJ → glb using Blender (File → Export → glTF 2.0). FBX → glb using Blender (import FBX, export glTF). USDZ (Apple format) → use Reality Composer or a converter. Aim for .glb (binary) rather than .gltf (separate JSON + textures) for AR use — it is a single file, easier to host and cache.
Can I add lighting and shadows to placed AR objects?
Yes — ARCore and ARKit provide environmental light estimation: the AR session detects real-world lighting conditions and applies them to virtual objects automatically. ar_flutter_plugin exposes this through ARSessionManager settings. Enable it with showLightEstimation: true in onInitialize. The 3D model material must support PBR (physically based rendering) materials — standard in .glb files exported from Blender with the Principled BSDF shader. Shadows on real-world surfaces require a shadow plane mesh placed at the detected floor level.
How do I let users rotate the placed AR object with finger gestures?
ar_flutter_plugin's ARObjectManager supports gesture-based transformation. Add a GestureDetector wrapper around your ARView widget that detects ScaleStart, ScaleUpdate (for pinch-to-scale), and RotateStart, RotateUpdate (for rotation). In the gesture callbacks, call arObjectManager.transformationUtils.rotateObject() and scaleObject() with the gesture delta values. Alternatively, use the overlay buttons approach from Step 5 of this tutorial — buttons are simpler to implement and work reliably across all devices.
Can I place multiple objects in the same AR scene?
Yes — call arObjectManager.addNode() multiple times, each time with a different anchor from a separate tap event. Each node is tracked independently. Store all placed nodes in a List<ARNode> state variable and all anchors in a List<ARAnchor>. For a clear all button, loop through the lists and call removeNode()/removeAnchor() for each. Note that placing many high-polygon models simultaneously will impact device performance — test with your target 3D models on mid-range devices.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation