diff --git a/.changeset/rotten-garlics-run.md b/.changeset/rotten-garlics-run.md
new file mode 100644
index 0000000..6805b6d
--- /dev/null
+++ b/.changeset/rotten-garlics-run.md
@@ -0,0 +1,5 @@
+---
+'@capacitor-mlkit/barcode-scanning': minor
+---
+
+feat: add web support
diff --git a/packages/barcode-scanning/src/definitions.ts b/packages/barcode-scanning/src/definitions.ts
index fd98804..0187e64 100644
--- a/packages/barcode-scanning/src/definitions.ts
+++ b/packages/barcode-scanning/src/definitions.ts
@@ -157,6 +157,14 @@ export interface StartScanOptions {
    * @since 0.0.1
    */
   lensFacing?: LensFacing;
+  /**
+   * The HTML video element to use for the camera preview.
+   *
+   * Only available on Web.
+   *
+   * @since 5.1.0
+   */
+  videoElement?: HTMLVideoElement;
 }
 
 /**
diff --git a/packages/barcode-scanning/src/web.ts b/packages/barcode-scanning/src/web.ts
index eaa84c1..440fb9c 100644
--- a/packages/barcode-scanning/src/web.ts
+++ b/packages/barcode-scanning/src/web.ts
@@ -1,6 +1,7 @@
 import { CapacitorException, ExceptionCode, WebPlugin } from '@capacitor/core';
 
 import type {
+  BarcodeScannedEvent,
   BarcodeScannerPlugin,
   IsSupportedResult,
   IsTorchAvailableResult,
@@ -11,17 +12,64 @@ import type {
   ScanResult,
   StartScanOptions,
 } from './definitions';
+import { BarcodeValueType } from './definitions';
 
 export class BarcodeScannerWeb
   extends WebPlugin
   implements BarcodeScannerPlugin
 {
-  async startScan(_options?: StartScanOptions): Promise<void> {
-    throw this.createUnavailableException();
+  public static readonly ERROR_VIDEO_ELEMENT_MISSING =
+    'videoElement must be provided.';
+  private readonly _isSupported = 'BarcodeDetector' in window;
+  private intervalId: number | undefined;
+  private stream: MediaStream | undefined;
+
+  async startScan(options?: StartScanOptions): Promise<void> {
+    if (!this._isSupported) {
+      this.throwUnsupportedError();
+    }
+    if (!options?.videoElement) {
+      throw new Error(BarcodeScannerWeb.ERROR_VIDEO_ELEMENT_MISSING);
+    }
+    this.stream = await navigator.mediaDevices.getUserMedia({
+      video: {
+        facingMode: {
+          ideal: 'environment',
+        },
+      },
+      audio: false,
+    });
+    options.videoElement.srcObject = this.stream;
+    await options.videoElement.play();
+    const barcodeDetector = new window.BarcodeDetector({
+      formats: ['qr_code'],
+    });
+    this.intervalId = window.setInterval(async () => {
+      const barcodes = await barcodeDetector.detect(options.videoElement);
+      if (barcodes.length === 0) {
+        return;
+      } else {
+        for (const barcode of barcodes) {
+          this.handleScannedBarcode(barcode);
+        }
+      }
+    }, 1000);
   }
 
   async stopScan(): Promise<void> {
-    throw this.createUnavailableException();
+    if (!this._isSupported) {
+      this.throwUnsupportedError();
+    }
+    if (this.intervalId) {
+      window.clearInterval(this.intervalId);
+      this.intervalId = undefined;
+    }
+    if (this.stream) {
+      this.stream.getTracks().forEach(track => {
+        track.stop();
+      });
+      this.stream = undefined;
+    }
   }
 
   async readBarcodesFromImage(
@@ -35,7 +83,9 @@ export class BarcodeScannerWeb
   }
 
   async isSupported(): Promise<IsSupportedResult> {
-    throw this.createUnavailableException();
+    return {
+      supported: this._isSupported,
+    };
   }
 
   async enableTorch(): Promise<void> {
@@ -76,4 +126,28 @@ export class BarcodeScannerWeb
       ExceptionCode.Unavailable,
     );
   }
+
+  private throwUnsupportedError(): never {
+    throw this.unavailable(
+      'Barcode Detector API not available in this browser.',
+    );
+  }
+
+  private handleScannedBarcode(barcode: any): void {
+    const result: BarcodeScannedEvent = {
+      barcode: {
+        displayValue: barcode.rawValue,
+        rawValue: barcode.rawValue,
+        format: barcode.format,
+        valueType: BarcodeValueType.Unknown,
+      },
+    };
+    this.notifyListeners('barcodeScanned', result);
+  }
+}
+
+declare global {
+  interface Window {
+    BarcodeDetector: any;
+  }
 }