In this video, I explore how to access the camera from AL code, check it out:

In this video, Erik explores how to access the device camera from Business Central using AL code — no .NET interop required. He discovers two approaches (a Codeunit and a Page), walks through the stream-handling concepts, and shares a handy tip for getting camera access working in a local Docker development environment.
The Problem: Camera Access in AL Without .NET
Erik wanted to add camera support to one of his apps and, as a first step, visited the official Microsoft documentation. He found the article “Implementing the Camera in AL”, which is a solid resource — but the sample code relies on .NET interop, making it unsuitable for cloud (SaaS) deployments on AppSource. Since camera access should work in the cloud, there had to be another way. Time to explore.
Discovering the Camera Codeunit
The first approach is wonderfully simple. By declaring a variable of type Codeunit Camera (from the System.Device namespace), you gain access to two key methods:
- IsAvailable() — Checks whether the camera on the client device is accessible.
- GetPicture(InStream, Text) — Takes a picture and returns the image data via an InStream, along with a generated file name.
There’s also an obsolete AddPicture method — ignore that one.
Understanding Streams
If you’re confused about InStream vs. OutStream, here’s the short version:
- InStream — You read data from it. This is where data comes in.
- OutStream — You write data to it. This is where data goes out.
Think of them as pipes. The camera fills the InStream pipe with image data. You then connect that pipe to a destination (like a Blob field) by creating an OutStream on the Blob and using CopyStream to pump the data through.
One thing to watch: CopyStream(OutStream, InStream) puts the destination first and the source second. It’s not the typical source-then-destination order you might expect.
The Source Code
Here’s Erik’s final working example, which opens the camera as soon as the Customer List page is opened and stores the photo on the last customer record:
namespace DefaultPublisher.userSelection;
using Microsoft.Sales.Customer;
using System.Device;
pageextension 50100 CustomerListExt extends "Customer List"
{
trigger OnOpenPage()
var
Camera: Codeunit Camera;
InS: InStream;
PictureName: Text;
begin
if Camera.IsAvailable() then begin
if Camera.GetPicture(InS, PictureName) then begin
Rec.FindLast();
Rec.Image.ImportStream(InS, PictureName);
Rec.Modify();
end;
end else
message('Boo, no camera!');
end;
}
Note how clean this is: check availability, get the picture, import the stream into a field, and modify the record. The GetPicture method returns a Boolean, so you can handle the case where the user cancels the camera dialog.
The Second Approach: Page Camera
Beyond the Codeunit, there’s also a Page called Camera. It offers a slightly different workflow:
- You run the Camera page (which opens the camera UI).
- After the user takes a photo, you call
HasPictureto check if an image was captured. - Then call
GetPicture, which can return the data as an InStream or a TempBlob.
The Page also exposes some additional methods that the Codeunit does not:
- SetAllowEdit(Boolean) — Supposedly allows simple editing before the picture is stored.
- SetEncodingType(ImageEncoding) — Lets you choose between JPEG and PNG.
- SetQuality(Integer) — Accepts a value between 0 and 100, where 100 is the highest resolution.
However, in Erik’s testing, none of these settings appeared to have any visible effect. The quality parameter, the encoding type, and the allow-edit flag all seemed to be ignored by the modern web client. These options may have worked at some point in the past (or on specific client types), but they don’t seem functional today.
What Microsoft Uses Internally
Looking at Microsoft’s own code — specifically Page 346 (the Item Picture page) and its TakeNewPicture action — they use the Codeunit approach. This confirms that the Codeunit is the recommended, cleaner method. The Page-based approach gives you the option of passing around a TempBlob if that fits your architecture better, but the Codeunit is essentially a wrapper around the same underlying functionality.
Docker Tip: Camera Access Over HTTP
If you’re developing against a local Docker container using unencrypted HTTP, your browser will likely block camera access for security reasons. Modern browsers require HTTPS for accessing device hardware like cameras and microphones.
To work around this during development:
- Open your browser’s flags page (e.g.,
edge://flagsin Microsoft Edge orchrome://flagsin Chrome). - Search for “Insecure origins treated as secure”.
- Add your Docker container’s URL (e.g.,
http://bc20) to the list. - Enable the flag and restart the browser.
This will save you from pulling your hair out wondering why IsAvailable() keeps returning false.
Summary
Taking selfies (or any photos) in Business Central with AL is surprisingly straightforward:
- Use Codeunit Camera from
System.Devicefor a clean, cloud-compatible approach — no .NET interop needed. - The workflow is simple: check
IsAvailable(), callGetPicture(), then pipe the InStream data to your destination usingCopyStreamorImportStream. - A Page Camera alternative exists with extra settings (quality, encoding, editing), but these don’t appear to have any effect in current versions.
- Microsoft themselves use the Codeunit approach in the base application.
- If developing locally with Docker over HTTP, configure your browser to treat your container URL as a secure origin.