How to Use Ionic Camera Plugin with Capacitor

 In this article we are going to learn how to use camera plugin in ionic with capacitor. Will cover each and everything from installing the plugin, configure permissions, capture a photo, show it in the template. Step by step, nothing skipped.

This tutorial shows how to:

  • Install and configure the Capacitor Camera plugin
  • Set up permissions for Android and iOS
  • Capture a photo using the camera
  • Pick an image from the gallery
  • Display the captured image in an Ionic component

Why Capacitor Camera Plugin

Ionic used to rely on Cordova plugins for native features. Capacitor is the modern replacement — faster, easier to debug, and much better maintained. The @capacitor/camera plugin gives you camera and gallery access with one consistent API across Android and iOS.

You don't write any native code. You call a JavaScript function, Capacitor handles the native side, and you get back the image data. That's the whole idea.


Step 1 : Install the Camera Plugin

Open your terminal in the Ionic project folder and run :

npm install @capacitor/camera
npx cap sync

That's it for installation. The sync command copies the plugin to your Android and iOS native projects. If you skip the sync, the plugin won't be available on the device even though it's in node_modules.

If you haven't added Android or iOS platform yet, do that first :

ionic build
npx cap add android
npx cap add ios

Then sync again after adding platforms.


Step 2 : Set Up Android Permissions

This is where a lot of people get stuck. On Android, camera and storage access require explicit permissions in the manifest file.

Open this file :

android/app/src/main/AndroidManifest.xml

Add these permissions inside the <manifest> tag, before the <application> tag :

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

On Android 13 and above, READ_EXTERNAL_STORAGE is replaced by more specific permissions. Add these too :

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

Adding all of them and letting Android figure out which ones apply based on the OS version is the safest approach.

Save the file and rebuild the Android project.


Step 3 : Set Up iOS Permissions

iOS needs privacy usage descriptions in the Info.plist file. Without these, Apple will reject your app and the camera won't work even in testing.

Open :

ios/App/App/Info.plist

Add these entries inside the main <dict> tag :

<key>NSCameraUsageDescription</key>
<string>This app needs camera access to take photos.</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to your photo library to select images.</string>

<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs permission to save photos to your library.</string>

The string values are what iOS shows to the user when asking for permission. Keep them clear and honest — something like "This app needs camera access to take photos" works fine.


Step 4 : Capture a Photo from Camera

Now the actual code. Open your component file and import the Camera plugin :

import { Component } from '@angular/core';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { IonicModule } from '@ionic/angular';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-camera',
  standalone: true,
  imports: [IonicModule, CommonModule],
  template: `
    <ion-header>
      <ion-toolbar>
        <ion-title>Camera</ion-title>
      </ion-toolbar>
    </ion-header>

    <ion-content class="ion-padding">
      <ion-button expand="block" (click)="takePhoto()">Take Photo</ion-button>

      <img *ngIf="photoUrl" [src]="photoUrl" style="width:100%; margin-top:20px;" />
    </ion-content>
  `
})
export class CameraComponent {
  photoUrl: string = '';

  async takePhoto() {
    const image = await Camera.getPhoto({
      quality: 90,
      allowEditing: false,
      resultType: CameraResultType.Uri,
      source: CameraSource.Camera
    });

    this.photoUrl = image.webPath ?? '';
  }
}

Let me explain the options inside getPhoto() :

  • quality — image quality from 1 to 100. 90 is a good balance between size and clarity.
  • allowEditing — if true, iOS shows a crop/edit screen after capture. Usually set to false unless you specifically need it.
  • resultType — how you want the image back. Uri gives you a file path that works directly in an img tag. Base64 gives you the raw base64 string. DataUrl gives base64 with the data:image/jpeg prefix already included.
  • source — CameraSource.Camera opens the camera. CameraSource.Photos opens the gallery. CameraSource.Prompt lets the user choose.

For displaying the image in the template, webPath is what you need when using Uri result type. It's the path the browser can actually load.


Step 5 : Pick Image from Gallery

Same code, just change the source to Photos :

async pickFromGallery() {
  const image = await Camera.getPhoto({
    quality: 90,
    allowEditing: false,
    resultType: CameraResultType.Uri,
    source: CameraSource.Photos
  });

  this.photoUrl = image.webPath ?? '';
}

Add a second button in the template :

<ion-button expand="block" (click)="pickFromGallery()">Pick from Gallery</ion-button>

That's it. Same function, different source. The rest is identical.


Step 6 : Get Image as Base64

Sometimes you need base64 — when you're uploading the image to a server as part of a JSON body, for example. Change resultType to Base64 :

async takePhotoBase64() {
  const image = await Camera.getPhoto({
    quality: 80,
    allowEditing: false,
    resultType: CameraResultType.Base64,
    source: CameraSource.Camera
  });

  const base64String = image.base64String ?? '';
  const fullBase64 = `data:image/jpeg;base64,${base64String}`;

  this.photoUrl = fullBase64;

  // To upload to server :
  // const response = await this.http.post('/api/upload', { image: base64String }).toPromise();
}

Note — base64 images can be large. A 90% quality photo can be 2-3MB as base64. If you're uploading to a server, consider reducing quality to 70 or 60. Your server and your users' data plan will thank you.


Step 7 : Handle Multiple Photos

Capacitor Camera plugin also supports picking multiple images from gallery at once. Use pickImages() instead of getPhoto() :

import { Camera, CameraResultType, GalleryPhoto } from '@capacitor/camera';

photos: string[] = [];

async pickMultiple() {
  const result = await Camera.pickImages({
    quality: 80
  });

  this.photos = result.photos.map(photo => photo.webPath ?? '');
}

Template to display all selected images :

<ion-button expand="block" (click)="pickMultiple()">Pick Multiple</ion-button>

<div *ngFor="let photo of photos">
  <img [src]="photo" style="width:100%; margin-bottom:10px;" />
</div>

pickImages() only works for gallery selection. It doesn't open the camera. For multi-capture from camera you'd need a different approach — like looping getPhoto() calls or using a native camera app.


Common Issues and Fixes

Camera opens but image doesn't show in template

You're probably using Base64 resultType but trying to bind image.webPath which is undefined in that mode. Match the resultType to what you're reading. Uri → use webPath. Base64 → use base64String.

Permission denied on Android

Make sure the permissions are in AndroidManifest.xml and also that you rebuilt the native project after adding them. Changes to AndroidManifest.xml don't take effect until you rebuild in Android Studio.

Works in browser but not on device

The browser uses a file input fallback — it doesn't actually access the camera. On a real device, the native camera is used. If it's not working on device, check the native logs in Android Studio (Logcat) or Xcode console. The error message there is much more useful than what you see in the browser.

Image URL shows but image is blank

This happens when webPath points to a file:// URL that the browser inside the WebView can't load directly. Switch to DataUrl resultType instead of Uri:

resultType: CameraResultType.DataUrl

Then use image.dataUrl directly as the src. No extra prefix needed.


Summary

You learned how to use the Capacitor Camera plugin in an Ionic app. You covered :

  • Installing @capacitor/camera and running npx cap sync
  • Adding camera and storage permissions in AndroidManifest.xml
  • Adding NSCameraUsageDescription and photo library permissions in iOS Info.plist
  • Taking a photo with Camera.getPhoto() using CameraSource.Camera
  • Picking from gallery with CameraSource.Photos
  • Getting the image as base64 for server uploads
  • Picking multiple images with Camera.pickImages()
  • Fixing common issues like blank images and permission errors

Camera plugin is one of those things that feels complicated the first time because of all the permission setup. But once you've done it once, it's straightforward. The Capacitor API itself is just one function call — getPhoto(). Everything else is just configuration.

I hope you like this article...

Happy coding! 🚀

Post a Comment

0 Comments