
Picture this: your warehouse team is doing daily inventory checks using paper forms and a separate barcode scanner device. Someone counts the stock, writes it down, hands the paper to a data entry clerk, who then types everything into a spreadsheet. Errors creep in. Things get lost. The whole process is slower than it needs to be. Now imagine instead that every team member has a phone, opens a Power Apps canvas app, scans a barcode, snaps a photo of any damage, and submits everything — all in one tap. That's not a futuristic scenario. That's what you can build today, and it's exactly what this lesson teaches you to do.
Power Apps canvas apps give you a set of media controls — built-in components for interacting with a device's camera, microphone, barcode scanner, and file system. These controls are what bridge the gap between a static form and a genuinely useful field tool. Whether you're building an inspection app, an asset management system, a receipt uploader, or a delivery confirmation tool, you'll almost certainly need at least one of these capabilities. Understanding how they work under the hood — not just how to drag them onto a screen — is what separates apps that frustrate users from apps that people actually want to use.
By the end of this lesson, you'll be able to add a camera capture to a canvas app, use the barcode scanner control to read product codes, and let users upload files or images from their device. You'll understand how the data flows from the control through formulas and into storage, and you'll know the common pitfalls that trip up beginners.
What you'll learn:
Before diving in, you should be comfortable with:
Set(), Patch(), and understanding control properties like OnSelectYou don't need to be a formula expert — we'll walk through every expression used.
Before you start dropping controls onto screens, it helps to understand the mental model. In Power Apps, a media control is just a special kind of input control. Like a text input captures text, a Camera control captures an image. The key insight is that the control holds the data temporarily in memory — it doesn't automatically save anything anywhere. Your job as the app maker is to write a formula that takes that captured data and does something useful with it: store it in a variable, patch it to SharePoint, attach it to a record, etc.
Think of it like a clipboard on your computer. When you copy something, it's on the clipboard — but it won't survive a restart unless you paste it into a document. Media controls work the same way. The capture lives in the control until your formula moves it somewhere permanent.
This also means the order of operations matters. You typically need three things: a control to capture the media, a button (or trigger) that runs a formula to process the captured data, and a destination where that data ends up.
In Power Apps Studio, go to the Insert tab on the left panel and search for "Camera." Select the Camera control to add it to your screen. You'll immediately see a live camera preview in the studio — or a placeholder if you're on a desktop without a webcam.
The Camera control has a critical property you need to understand first: StreamRate. This controls how frequently (in milliseconds) the camera updates its preview. The default is 100ms, which gives you a smooth live preview. Lower values use more processing power; higher values look choppier. For most apps, the default is fine.
The most important property for capturing a photo is Photo. This property holds the current frame as a base64-encoded image string. Think of base64 encoding as a way of representing a binary file (the photo) as a long string of text characters — it's how images get transmitted in many web and mobile contexts.
Here's where beginners get confused: the Photo property is constantly updating with the live preview. To "freeze" a moment in time — to actually take a photo — you need to copy that value somewhere when the user taps a button. You do this with the Set() function:
// OnSelect of a "Take Photo" button:
Set(varCapturedPhoto, Camera1.Photo)
This stores the current frame in a variable called varCapturedPhoto. From that point on, you can display the captured photo in an Image control by setting its Image property to varCapturedPhoto.
Add an Image control to your screen. Set its Image property to:
varCapturedPhoto
Now when the user taps "Take Photo," the variable gets set, and the Image control instantly shows the captured frame. This gives users visual confirmation that the right photo was taken before they submit.
Tip: Add a second button labeled "Retake" that simply runs
Set(varCapturedPhoto, "")to clear the variable. This lets users discard a bad photo and try again without restarting the whole form.
This is where things get a little more involved, and it's also where most tutorials leave you stranded. A SharePoint list doesn't store raw images as column values — instead, it stores them as attachments on list items. Power Apps handles this through the Patch() function with a special attachment syntax.
Here's a realistic scenario: you're building an inspection app. Each inspection record has a text field for notes and an image field for a photo. Your SharePoint list is called "Inspections" and has a column called "Notes."
When the user taps the "Submit" button, you want to create a new record and attach the photo. The formula looks like this:
// OnSelect of a "Submit" button:
Patch(
Inspections,
Defaults(Inspections),
{
Notes: TextInput_Notes.Text,
Attachments: [
{
Name: "inspection_photo.jpg",
Value: Camera1.Photo
}
]
}
)
A few things to unpack here:
Defaults(Inspections) tells Patch to create a new record rather than update an existing oneAttachments column takes a table of attachment objects — even if you're only attaching one file, it needs to be inside square bracketsName (a filename string you define) and a Value (the base64 image data from the camera)For this to work, your SharePoint list must have the Attachments feature enabled (it is by default for new lists). You also need to make sure Power Apps has the SharePoint data source connected.
Warning: The
Camera1.Photovalue is only the current preview frame at the moment the formula runs. If you've already stored it invarCapturedPhoto, use that variable in your Patch formula instead ofCamera1.Photo— otherwise you might capture a slightly different frame than the one the user approved.
The Barcode Reader control is one of the most practically useful things in Power Apps for any kind of inventory, logistics, or retail scenario. It uses the device's camera to continuously analyze frames and detect barcode patterns. When it finds a barcode, it decodes it and exposes the value through the Value property.
The control supports a wide range of barcode formats: QR codes, Code 128, Code 39, EAN-13, EAN-8, UPC-A, UPC-E, PDF417, and more. You don't need to configure the format — the control auto-detects it.
Add the Barcode Reader from the Insert panel (search for "Barcode Reader"). It will appear as a camera-like rectangle on your screen.
The Value property of the Barcode Reader holds the decoded string from the last successfully detected barcode. Unlike the Camera control, there's no "take a photo" moment — the Barcode Reader fires its OnScan event automatically whenever it successfully reads a code.
The OnScan event is where you put your logic. Here's a simple example: when a barcode is scanned, look up the corresponding product in a SharePoint list called "Products" and store the result in a variable.
// OnScan of BarcodeReader1:
Set(
varScannedProduct,
LookUp(Products, SKU = BarcodeReader1.Value)
)
Now you can display the product name on screen:
// Text property of a Label:
If(
IsBlank(varScannedProduct),
"No product found — scan again",
varScannedProduct.ProductName
)
This gives the user immediate feedback: they scan, the app looks up the product, and the name appears. If the barcode doesn't match anything in your list, they see a helpful message instead of nothing.
Let's extend this. Say your warehouse app needs to record that a quantity was received. After scanning the barcode, the user types a quantity into a text input, then taps "Confirm Receipt." The button formula updates the matching record in the Products list:
// OnSelect of "Confirm Receipt" button:
Patch(
Products,
LookUp(Products, SKU = BarcodeReader1.Value),
{
StockLevel: Value(TextInput_Quantity.Text) + varScannedProduct.StockLevel
}
);
Notify("Stock updated for " & varScannedProduct.ProductName, NotificationType.Success);
Set(varScannedProduct, Blank())
Breaking this down:
Patch finds the existing record using LookUp and updates only the StockLevel fieldValue() converts the text input string to a number so you can do arithmeticNotify() pops a success message at the top of the screenSet() clears the variable, resetting the screen for the next scanTip: The Barcode Reader control has a property called
Barcodesthat lets you restrict which barcode formats it accepts. If you know your app only uses QR codes, restricting to[BarcodeType.QRCode]can improve scan speed and reduce false positives.
Not every scenario involves capturing something new. Sometimes users already have a receipt photo in their gallery, a PDF on their device, or a document they need to attach to a record. That's where the Add Picture control comes in. It opens the device's native file picker, lets the user choose a file, and makes it available in the app.
Add the Add Picture control from the Insert panel (search for "Add picture"). It appears as a button on your screen — users tap it to launch their device's file browser.
Once a user selects a file, the control's Media property holds the file data. For image files, this behaves similarly to the Camera control's Photo property — it's the image data ready to be displayed or saved.
To display the selected image, add an Image control and set its Image property to:
AddMediaButton1.Media
The Add Picture control also exposes a FileName property, which gives you the original filename as a string. This is useful when saving to SharePoint so the attachment has a meaningful name rather than a generic one:
// Example: FileName property might return "receipt_march.jpg"
AddMediaButton1.FileName
The Patch syntax for uploading a file from Add Picture is nearly identical to what we used for the Camera control. Here's a receipt submission example for an expense tracking app:
// OnSelect of "Submit Expense" button:
Patch(
Expenses,
Defaults(Expenses),
{
EmployeeName: TextInput_EmployeeName.Text,
Amount: Value(TextInput_Amount.Text),
Category: Dropdown_Category.Selected.Value,
Attachments: [
{
Name: AddMediaButton1.FileName,
Value: AddMediaButton1.Media
}
]
}
);
Notify("Expense submitted successfully!", NotificationType.Success);
Reset(AddMediaButton1);
Reset(TextInput_EmployeeName);
Reset(TextInput_Amount)
The Reset() function at the end clears each control back to its default state, which is good UX — users shouldn't have to manually clear old data before submitting a second expense.
Warning: The Add Picture control has a maximum file size limit that depends on the browser or app player. For Power Apps mobile, very large files (over ~10MB) can cause the submission to fail silently. If your use case involves large files, add a check before patching. You can use
Len(AddMediaButton1.Media)to get an approximate size, though note this measures the base64 string length, not the raw file size.
What if you need to allow multiple files? The AddMediaButton1.Media property only holds the most recently selected file. To build a multi-file upload experience, you need to collect each selection into a collection as the user adds them.
Use the OnChange property of the Add Picture control (this fires every time a new file is selected):
// OnChange of AddMediaButton1:
Collect(
colAttachments,
{
Name: AddMediaButton1.FileName,
Value: AddMediaButton1.Media
}
)
Then in your Patch formula, reference the collection directly:
// OnSelect of "Submit" button:
Patch(
Inspections,
Defaults(Inspections),
{
Notes: TextInput_Notes.Text,
Attachments: colAttachments
}
);
Clear(colAttachments)
Clear(colAttachments) empties the collection after submission so it doesn't carry over to the next record.
Let's put all three controls together in a single screen. You're building a Delivery Confirmation App for a logistics company. When a driver makes a delivery, they need to scan the package barcode, take a photo of the delivered package, and submit both to a SharePoint list called "Deliveries."
Your SharePoint list should have these columns:
Step 1: Set up your screen
Open a blank canvas app (phone layout). From the Insert panel, add:
Step 2: Configure the Barcode Reader
Set one Label's Text property to:
If(IsBlank(BarcodeReader1.Value), "Scan package barcode...", "Scanned: " & BarcodeReader1.Value)
Step 3: Configure the Camera button
Set the "Capture Photo" button's OnSelect to:
Set(varDeliveryPhoto, Camera1.Photo)
Set the Image control's Image property to varDeliveryPhoto.
Step 4: Configure the Submit button
// OnSelect of "Submit Delivery":
If(
IsBlank(BarcodeReader1.Value) || IsBlank(varDeliveryPhoto),
Notify("Please scan barcode and capture photo before submitting.", NotificationType.Warning),
Patch(
Deliveries,
Defaults(Deliveries),
{
Title: BarcodeReader1.Value,
TrackingNumber: BarcodeReader1.Value,
DeliveryNotes: TextInput_Notes.Text,
Attachments: [{Name: "delivery_photo.jpg", Value: varDeliveryPhoto}]
}
);
Notify("Delivery confirmed!", NotificationType.Success);
Set(varDeliveryPhoto, "")
)
Step 5: Test it
Run the app in preview mode (press the play button in the top right). Point your device's camera at a QR code or product barcode — it should read and display the value. Tap "Capture Photo" to freeze a frame, then tap "Submit Delivery" and check your SharePoint list for the new record and attachment.
"The camera works in preview but not on mobile"
This almost always comes down to device permissions. When users first open the app on their phone, iOS and Android both prompt for camera permission. If they tap "Deny," the camera control will appear blank. Remind users to allow camera access, and consider adding a Label with instructions the first time they open the app.
"The photo patches but the attachment doesn't show up in SharePoint"
Double-check that your list has attachments enabled. In the SharePoint list settings, go to Advanced Settings and make sure "Attachments" is set to "Enabled." Also verify your formula uses the correct column name — it must be exactly Attachments (capital A).
"The Barcode Reader scans but the value disappears immediately"
The Value property resets between scans. If you're using BarcodeReader1.Value directly in your Patch formula rather than storing it in a variable, a slight timing issue can result in an empty value being submitted. Always use OnScan to store the value in a variable first: Set(varTrackingNumber, BarcodeReader1.Value).
"Add Picture shows the file selected but Patch fails"
Check whether you're patching to a SharePoint list vs. a Dataverse table. The attachment syntax is slightly different for Dataverse. For SharePoint, the syntax shown above works. For Dataverse, you use the Notes (attachment) functionality differently. Confirm your data source type.
"The app is very slow when the Camera control is on screen" The Camera control streams video continuously, which is CPU-intensive. If your screen has many other controls and formulas running, this can create performance issues. Consider putting the Camera on its own dedicated screen that users navigate to only when they need to take a photo. Navigate back to the main form screen afterward, passing the photo value as a parameter.
You've just built the foundation of any serious field tool in Power Apps. The Camera control, Barcode Reader, and Add Picture control each solve a different capture problem — live camera frames, automated code detection, and user-selected files — and all three funnel their data through the same general pattern: capture into a variable or collection, then patch to a data source with the attachment syntax.
The key mental model to carry forward is that media controls are temporary holders. They don't save anything on their own. Your formulas are the bridge between what the user captures and where that data lives permanently.
To deepen your skills from here:
Every field app you'll ever build for inspection, delivery, inventory, or compliance will draw on exactly what you learned here. The controls change, the data sources change, but the pattern stays the same.
Learning Path: Canvas Apps 101