Capacitor + QRScanner

From what I understand I cannot use ionic-native if I’m using capacitor and not Cordova, even though I tried it anyways.

What is the best way to integrate QRscanner into capacitor apps on iOS? Im using a package for angular to scan which works fine on any browser, but I don’t want to use browser. Don’t know if capacitor will ever have api for qrscanner.

I believe Capacitor supports cordova (and hence ionic native) for many plugins. Some may conflict.
Haven’t tried QR but I would defintely give it a try.

There is a list of community plugins for Capacitor. And no one knows of course when the QR will arrive, unless you build it yourself.

I’m not sure you need a native scanner anymore as browsers support QR code scanning??

Do a Google search for JS QR Scanner, there are several on Github.


why use browser scanning? Then user would need to switch back and forth app and browser.

I don’t think so, Ionic apps run within a browser, you just don’t see it.

Exactly the route i will be taken as the process starts with qr and the users will be more used to open the camera app then something else

With deeplink and pwa, we have lift off!


Okay, well I’m like I said I tried it and it doesn’t work on iOS.

Sorry, I missed that you had tried a JS solution.

There is nothing stopping you from using a Cordova plugin with Capacitor, although I see you said you had tried that too?

1 Like

The BarcodeScanner plugin

  • reads QR codes
  • works with Capacitor (at least on Android)
1 Like

Thanks. Will give it a try

I took the QR js code of this package and injected it separately in the app, so I can use it in PWA and test without having to run ionic cordova run browser.

And works fine. No camera preview of course, but that is a web issue I believe.

1 Like

I have a similar component for display purposes. Does yours work for scanning as well?

Yup, here the code that does the scanning, but no Preview though;

In index.html, stripped from the dist folder in browser plugin (the js lib)

<script src="assets/lib/cordova-plugin-qrscanner-lib.min.js"></script>

The ts part:

import { QRScanner, QRScannerStatus } from '@ionic-native/qr-scanner/ngx';

this.qrScanner = new QRScanner();

 // start scanning - as seen in the documentation.....
 const scanSub = this.qrScanner.scan().subscribe((text: any) => {
            console.log('Scanned something', text);

              // here the result
              if (text.result) {


              this.qrScanner.hide(); // hide camera preview
              scanSub.unsubscribe(); // stop scanning

You know the drill…

1 Like

Yeah I’ve done this. It doesn’t work. Just a blank screen, I guess it’s the no preview. Works fine on browser, on iOS doesn’t do what I need it to do. sigh

So QRScanner doesn’t work on iOs even though it says it does?

I got it working on iOS awhile ago.

This is the npm package:

This is the code I made to read the barcode.

And this is how it works on firebase

It works in Safari, Firefox and Chrome but on Firefox Preview (now it is on Nightly channel) it works kinda iffy.

Also, if you are using TypeScript you will have to change the index.d.ts file (not sure if it’s called index, but you will see an error that quagga is not a module or something related) on the node_modules because the definition package is all janked up but it is an easy fix (don’t export as module but as a default variable, and export everything in that file). I tried pushing a change, but they revert to the one that gave issues for some reason.

There are others packages that does the same as this one that I always find just looking around.

1 Like

Your project food-tracker seems PWA only but this topic is about native apps build in Capacitor.

Wrap it in Capacitor and it works.

This is what I use. Works well.

cozmo/jsQR: A pure javascript QR code reading library. This library takes in raw images and will locate, extract and parse any QR code found within. (

import jsQR from "jsqr";
    @ViewChild('video', { static: false }) video: ElementRef;
    @ViewChild('canvas', { static: false }) canvas: ElementRef;

    canvasElement: any;
    videoElement: any;
    canvasContext: any;

    ngAfterViewInit() {
        this.canvasElement = this.canvas.nativeElement;
        this.canvasContext = this.canvasElement.getContext('2d');
        this.videoElement =;
    async startScan() {
        // Not working on iOS standalone mode!
        const stream = await navigator.mediaDevices.getUserMedia({
            video: { facingMode: 'environment' }

        this.videoElement.srcObject = stream;
        // Required for Safari
        this.videoElement.setAttribute('playsinline', true);

        this.loading = await this.loadingController.create({});
        await this.loading.present();;

    async scan() {
        if (this.videoElement.readyState === this.videoElement.HAVE_ENOUGH_DATA) {
            if (this.loading) {
                await this.loading.dismiss();
                this.loading = null;
                this.scanActive = true;

            this.canvasElement.height = this.videoElement.videoHeight;
            this.canvasElement.width = this.videoElement.videoWidth;

            const imageData = this.canvasContext.getImageData(
            const code = jsQR(, imageData.width, imageData.height, {
                inversionAttempts: 'dontInvert'

            if (code) {
                this.scanActive = false;
                this.scanResult =;
            } else {
                if (this.scanActive) {
        } else {


    <ion-button expand="block" (click)="startScan()" *ngIf="!scanActive && !scanResult">
        <ion-icon slot="start" name="qr-code-outline"></ion-icon>
        Start Scanning

    <ion-button expand="block" (click)="reset()" color="warning" *ngIf="scanResult">
        <ion-icon slot="start" name="refresh"></ion-icon>

    <!-- Shows our camera stream -->
    <video #video [hidden]="!scanActive" width="100%"></video>

    <!-- Used to render the camera stream images -->
    <canvas #canvas hidden></canvas>

    <!-- Stop our scanner preview if active -->
    <ion-button expand="block" (click)="stopScan()" color="danger" *ngIf="scanActive">
        <ion-icon slot="start" name="close"></ion-icon>
        Stop Scanning


this plugin works like a charm:

1 Like