Canvas Apps: Design, Data, State and Error Handling
Building canvas apps that are accessible, responsive and debuggable β variables and collections, error handling, and testing with Monitor.
Canvas is the other half of the app story
Model-driven apps generate layout from metadata. Canvas apps do the opposite: you place every control, and you decide exactly what happens when it is touched.
Nadia reaches for canvas when Raviβs drivers need something on a phone, in a truck cab, with gloves on. That is a usability problem that no generated layout will solve well.
Variables and collections
State management is the part of canvas that most often goes wrong, and the exam knows it.
| Kind of state | Scope | Set with | Reach for it when |
|---|---|---|---|
| Global variable | The whole app | Set() | A value several screens need β the signed-in driver, the selected depot |
| Context variable | A single screen | UpdateContext() | Screen-local state β is this panel expanded? |
| Collection | The whole app | Collect() / ClearCollect() | A table of rows held in the app β a basket, a batch, cached reference data |
The habit that separates good canvas apps from bad ones
Use the narrowest scope that works.
A global variable is visible everywhere, which sounds convenient and becomes a debugging problem in an app of any size β anything can change it, from anywhere. If only one screen needs the value, a context variable makes that constraint explicit.
The same applies to collections. A collection is a whole table living in the appβs memory. Loading a large Dataverse table into a collection βso itβs fastβ is one of the most common performance mistakes in canvas apps β it moves the cost to app start-up and breaks delegation.
Delegation, briefly, because it underpins performance questions
When a canvas app queries a data source, Power Apps tries to push the filtering and sorting to the data source. That is delegation, and it is what allows an app to work against a table with a million rows.
When an expression cannot be delegated, Power Apps instead pulls a limited number of rows to the device and processes them locally. The app does not fail β it quietly gives you an answer based on a subset. That is why delegation warnings matter: the symptom is wrong results, not an error.
For the exam, the reasoning to hold onto is: if a scenario mentions a large data set and unexpected or incomplete results, think delegation before thinking bug.
Designing for accessibility, performance, responsiveness and usability
Microsoft lists these four together in a single objective, which is a hint that they expect design judgement rather than trivia.
| Quality | What good looks like | The common failure |
|---|---|---|
| Accessibility | Meaningful accessible labels on controls, sufficient colour contrast, a sensible tab order, and no meaning carried by colour alone | Using red text as the only indicator of a problem |
| Performance | Delegable queries, minimal work in OnStart, loading only what the screen needs | Pulling entire tables into collections at start-up |
| Responsiveness | Layout that adapts to screen size rather than assuming a fixed canvas | Designing at one size and discovering the phone view is unusable |
| Usability | Few taps to the common task, obvious next action, clear feedback after every action | A form that gives no confirmation, so users submit twice |
Accessibility is not optional polish
It is worth being blunt about this: accessible labels, contrast and keyboard order are what make an app usable for people with screen readers, low vision or motor impairments. They are listed as an exam objective because they are a professional expectation, not a nice-to-have.
The practical exam-facing version: if an option describes conveying status only through colour, it is the wrong answer.
Automating business processes from canvas apps
Canvas apps do not have to hold the logic themselves. A common and testable pattern is for the app to hand off to a Power Automate cloud flow β the app collects input and calls the flow, the flow does the multi-step work.
When to keep logic in the app, and when to hand it to a flow
- Keep it in the app when it is immediate, user-facing, and needs to update the screen β validation, calculations for display, navigation.
- Hand it to a flow when it involves other systems, approvals, waiting, retries, or work that should continue after the user closes the app.
The giveaway phrase in scenarios is anything involving waiting β for an approval, for a response, for a schedule. Canvas apps are not built to wait. Flows are.
Error handling
Things fail. The question is whether your user finds out in a useful way.
A save can fail because the network dropped, because someone else edited the record, or because a required field was empty. Without error handling, the app either shows a raw platform message or appears to succeed while nothing was saved.
Good error handling catches the failure, tells the user something they can act on, and leaves the app in a sensible state.
Testing and Monitor
The objective names Monitor explicitly, which means it is fair game.
What Monitor gives you
Monitor shows a live stream of the events happening inside a running canvas app β the data calls being made, how long each one took, and what came back.
That makes it the right tool for a specific class of problem:
- βThe app is slowβ β Monitor shows which calls are taking the time, and how many are being made.
- βThe data is wrongβ β Monitor shows the actual request and response, so you can see whether the app asked the wrong question or got the wrong answer.
- βIt works for me but not for themβ β Monitor can attach to a published app session, not just the studio.
What Live monitor is not: a step-through debugger that lets you set breakpoints and walk a formula line by line. It is a diagnostic stream, and its strength is showing you what actually happened rather than what you assumed would. It does surface formula context alongside events β Microsoft describes it as helping you understand βhow the events and formulas contained in your app workβ β so treat βshows traffic only, never formulasβ as too strong.
One naming note: the current product name is Live monitor. The objective wording still says Monitor, and they are the same tool.
Kite Freightβs driver app
Nadia builds Run Check as a canvas app for phones.
| Requirement | Decision |
|---|---|
| Drivers confirm arrival at a depot | Canvas app β phone form factor, gloves, one-handed use |
| Selected depot needed across three screens | Global variable via Set() |
| Whether the notes panel is open | Context variable β only one screen cares |
| Todayβs assigned runs | Filtered, delegable query β not a full-table ClearCollect() |
| Arrival triggers a notification to dispatch and waits for acknowledgement | Cloud flow β there is waiting involved, so it does not belong in the app |
| Save fails offline | IfError around the write, a clear message, and the driver stays on the screen to retry |
| Status shown by colour | Colour plus a text label β colour alone fails accessibility |
| App feels slow in the field | Monitor attached to a real session shows the depot list being re-queried on every screen change |
Quick recall
Check yourself
A canvas app shows only some of the expected records from a Dataverse table with 80,000 rows. No error is displayed. The same user can see all of the expected records through a model-driven view, and Power Apps Studio shows a delegation warning on the formula. What is the most likely cause?
Drivers confirm arrival in a canvas app. The confirmation must notify dispatch and then wait for dispatch to acknowledge before the run is marked complete. Where should this logic live?
Which design choice would fail an accessibility review?