# How to Integrate Augmented Reality Features in FlutterFlow

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 45-60 min
- Compatibility: FlutterFlow Pro (custom widget requires code export for final platform configuration)
- Last updated: March 2026

## TL;DR

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.

## Before you start

- 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

### 1. 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.

```
// Custom Widget: ARView
// Pubspec: ar_flutter_plugin, vector_math
// Parameters: modelUrl (String), initialScale (double)

import 'package:flutter/material.dart';
import 'package:ar_flutter_plugin/ar_flutter_plugin.dart';
import 'package:ar_flutter_plugin/datatypes/config_planedetection.dart';
import 'package:ar_flutter_plugin/datatypes/node_types.dart';
import 'package:ar_flutter_plugin/managers/ar_anchor_manager.dart';
import 'package:ar_flutter_plugin/managers/ar_location_manager.dart';
import 'package:ar_flutter_plugin/managers/ar_object_manager.dart';
import 'package:ar_flutter_plugin/managers/ar_session_manager.dart';
import 'package:ar_flutter_plugin/models/ar_anchor.dart';
import 'package:ar_flutter_plugin/models/ar_node.dart';
import 'package:vector_math/vector_math_64.dart' as vector;

class ARViewWidget extends StatefulWidget {
  final String modelUrl;
  final double initialScale;
  const ARViewWidget({
    required this.modelUrl,
    this.initialScale = 0.5,
    Key? key,
  }) : super(key: key);

  @override
  State<ARViewWidget> createState() => _ARViewWidgetState();
}

class _ARViewWidgetState extends State<ARViewWidget> {
  ARSessionManager? arSessionManager;
  ARObjectManager? arObjectManager;
  ARAnchorManager? arAnchorManager;
  ARNode? placedNode;
  List<ARAnchor> anchors = [];

  @override
  void dispose() {
    arSessionManager?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ARView(
      onARViewCreated: _onARViewCreated,
      planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical,
    );
  }

  void _onARViewCreated(
    ARSessionManager sessionMgr,
    ARObjectManager objectMgr,
    ARAnchorManager anchorMgr,
    ARLocationManager locationMgr,
  ) {
    arSessionManager = sessionMgr;
    arObjectManager = objectMgr;
    arAnchorManager = anchorMgr;

    arSessionManager!.onInitialize(
      showFeaturePoints: false,
      showPlanes: true,          // Show detected planes as translucent surfaces
      showWorldOrigin: false,
    );
    arObjectManager!.onInitialize();

    // Place object when user taps on a detected plane
    arSessionManager!.onPlaneOrPointTap = _onPlaneTapped;
  }

  Future<void> _onPlaneTapped(List<ARHitTestResult> hits) async {
    if (hits.isEmpty) return;

    // Remove previously placed node
    if (placedNode != null) {
      arObjectManager?.removeNode(placedNode!);
    }

    final hit = hits.first;
    final anchor = ARPlaneAnchor(transformation: hit.worldTransform);
    final bool anchorAdded = await arAnchorManager!.addAnchor(anchor);
    if (!anchorAdded) return;
    anchors.add(anchor);

    // Place the 3D model at the tapped location
    final node = ARNode(
      type: NodeType.webGLB, // Remote .glb URL
      uri: widget.modelUrl,
      scale: vector.Vector3(
        widget.initialScale,
        widget.initialScale,
        widget.initialScale,
      ),
      position: vector.Vector3(0.0, 0.0, 0.0),
      rotation: vector.Vector4(1.0, 0.0, 0.0, 0.0),
    );

    await arObjectManager!.addNode(node, planeAnchor: anchor);
    placedNode = node;
  }
}
```

**Expected result:** ARView Custom Widget compiles successfully and appears in your FlutterFlow widget library. The widget takes a modelUrl parameter.

### 2. 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.

### 3. 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.

```
// Custom Action: checkARSupport
// Returns: bool — true if device supports AR
import 'package:ar_flutter_plugin/ar_flutter_plugin.dart';

Future<bool> checkARSupport() async {
  try {
    // Check if ARCore (Android) or ARKit (iOS) is available
    final bool isARCoreSupported = await ArCoreController.checkIfARCoreApkIsUpdated()
        .then((_) => true)
        .catchError((_) => false);
    return isARCoreSupported;
  } catch (e) {
    return false;
  }
}

// Alternative: simpler platform check
import 'dart:io';
Future<bool> checkARSupportSimple() async {
  if (Platform.isIOS) {
    // ARKit available on iPhone 6s+ with iOS 11+
    // Basic check — full check requires ARSession.isSupported
    return true; // Handle unsupported in ARKit error callback
  } else if (Platform.isAndroid) {
    // ARCore check via ar_flutter_plugin
    try {
      final availability = await checkARCoreAvailability();
      return availability == ARCoreAvailability.supportedAndUpdated ||
             availability == ARCoreAvailability.supportedApkTooOld;
    } catch (e) {
      return false;
    }
  }
  return false;
}
```

**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.

### 4. 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.

### 5. 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 code example

File: `AR Integration Architecture`

```text
Pubspec Dependencies
=====================
ar_flutter_plugin: ^0.7.3
vector_math: ^2.1.4
flutter_cache_manager: ^3.3.1
model_viewer_plus: ^1.8.0  (fallback viewer)

Android Platform Config (AndroidManifest.xml)
===============================================
<uses-permission android:name='android.permission.CAMERA' />
<application>
  <meta-data
    android:name='com.google.ar.core'
    android:value='optional' />
</application>
minSdkVersion: 24 (Android 7.0)

iOS Platform Config (Info.plist)
==================================
NSCameraUsageDescription: 'Camera is used to place 3D models in your space'
Minimum iOS version: 11.0

FlutterFlow Page Architecture
==============================
ProductDetail (param: productId)
  Backend Query: products/{productId}
    Fields: title, price, imageUrl, arModelUrl
  ├── Image (imageUrl)
  ├── Text (title + price)
  └── Button: 'View in AR'
      Navigate → ARViewPage (param: modelUrl = arModelUrl)

ARViewPage (param: modelUrl)
  Stack:
  ├── ARViewWidget (modelUrl = page param)
  │   AR Features:
  │     PlaneDetection: horizontal + vertical
  │     OnTap: place model at hit location
  │     NodeType: webGLB (remote URL)
  └── Overlay Column (bottom of screen)
      ├── Slider (scale: 0.1 → 2.0)
      ├── Row (rotate left | rotate right)
      ├── IconButton (remove model)
      └── IconButton (capture screenshot)

Page State Variables:
  objectScale: Double (0.5)
  isARSupported: Boolean (checked on init)
  isModelLoading: Boolean (true while .glb downloads)

Firestore Product Document:
  arModelUrl: String
    → Firebase Storage path
    → gs://project.appspot.com/models/sofa.glb
    → or public HTTPS URL

Fallback (non-AR devices):
  → ModelViewerWidget (model_viewer_plus)
  → Interactive 3D viewer: rotate, zoom
  → No plane detection or real-world placement
```

## Common mistakes

- **Not checking device AR support before initializing ARCore/ARKit and showing a crash or blank screen to users on unsupported devices** — ARCore is not installed on all Android devices — budget phones, tablets, and older devices often do not support it. ARKit requires iPhone 6s or newer with iOS 11+. Initializing ar_flutter_plugin on an unsupported device throws an exception that, if unhandled, crashes the app. A significant percentage of users (estimates suggest 20-30% of Android users) have non-ARCore devices. Fix: 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'.
- **Loading large 3D model files (10-50MB) directly in the AR view without optimization, causing 30+ second load times or out-of-memory crashes** — Mobile devices have limited RAM and bandwidth. A 50MB .glb file with 4K textures takes 45+ seconds to download on an average mobile connection and can exhaust the memory available to the AR session, causing the app to crash or the model to fail to render. Users will close the app before the model loads. Fix: 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.
- **Testing AR features in FlutterFlow's browser preview or on an emulator and concluding the AR integration is broken when it shows nothing** — AR requires a physical camera with depth sensors and gyroscope data — it is fundamentally impossible to run in a browser preview or in an Android/iOS emulator without AR support. FlutterFlow's preview and emulators cannot initialize ARCore or ARKit. Fix: 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

## 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.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-integrate-augmented-reality-features-in-flutterflow
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-integrate-augmented-reality-features-in-flutterflow
