· 8 min read
Which Canvas checks a machine should own, and which it shouldn't
Most Canvas QA fails in one of two directions. Either nobody runs it and a mis-bound template goes to the whole audience, or somebody runs it as a ritual — a list of ticks applied at the end of a long week by a person who has stopped reading. The way out is not a longer checklist. It is sorting the existing one by whether the check has a right answer a machine can establish, or a judgement that needs a person who knows what the program is for.

By Justin Williames
Founder, Orbit · 10+ years in lifecycle marketing
The pre-launch hour, and why the checklist stops working
Picture the hour before a Canvas goes live. The build has been signed off, the copy is approved, someone has already told the wider team it launches this afternoon. Now a person opens a forty-item checklist and starts ticking. By item twelve they are pattern-matching rather than verifying. By item thirty they are ticking things they have not looked at, because everything so far was fine and the meeting is in ten minutes.
That is not carelessness. It is what a flat list does to a tired person — exactly the failure mode automation is good at removing. But automating the whole list is the wrong correction, because a meaningful fraction of the items are not verification at all. They are judgement wearing a checkbox.
The useful cut is decidability. If a check has one correct answer that can be established by reading something, hand it to a machine and stop spending human attention on it. If the check is really asking whether this is the correct call, no amount of tooling substitutes for someone who knows what the program is for. Sorting the list this way usually shrinks the human half to a size a person can actually hold at 4pm on a Thursday.
The checks a machine should own outright
These have right answers. Every one of them compares what is configured against what was specified. A person reading them off a screen is strictly worse at it than a script.
Template binding, by content fingerprint. The single highest-value automated check, because it catches the mistake that costs the most. The Braze API's message-step title field is usually null, so you cannot verify a binding by name. You verify it by content: fetch the bound template, then fingerprint on subject line plus preheader plus one distinctive block that only exists in that variant — an upsell card, a tier-specific paragraph. That is how you catch the free-tier email bound to the paid branch, which looks completely normal in the flow diagram.
Liquid fallbacks on every variable. Every personalisation token needs a default. A missing fallback does not fail loudly at build time; it fails on the subset of users with a null value, which is always larger than anyone estimates. Scanning a body for unguarded variables is trivially mechanical and nobody does it reliably by eye.
Links, UTMs and the staging-domain check. Every CTA resolving, no test or staging hosts, tracking parameters consistent. Also worth automating: CTA parity, meaning two buttons with the same visible label cannot point at different destinations.
Compliance furniture. Unsubscribe link present, physical address present, sender and subscription group correct. These are pass or fail. They are legally load-bearing. They also vanish first when a template is rebuilt from a module that never had them.
Size after link-wrapping, and dark mode. The byte budget has to be measured after the ESP wraps every link for click tracking, because that is what actually gets delivered and it is meaningfully larger than what you built. Gmail clips past its limit. A clipped email loses its unsubscribe link — which turns a rendering nuisance into a compliance one. Dark-mode inversion is likewise a render fact, judged on a delivered seed send rather than a preview pane.
Conversion-event count and delay values, read back as configured.Braze caps conversion events at four per Canvas. Counting them is machine work. Reading each delay's actual duration back from the configuration — rather than from the build spec that says what it was supposed to be — is machine work too. That is where accidental zero-delay back-to-back sends get caught.
The checks that still need a person
Now the half that does not automate, and will not, because the input a machine would need is intent — which lives in a person's head or a PRD, and if it lives in the PRD you are back to a human reading it.
| The check | Why it resists automation |
|---|---|
| Is this the right conversion event? | A machine confirms four events are defined and valid. Whether they measure the outcome this journey exists to produce is a question about strategy. Wrong-but-valid is the common failure. It locks at launch. |
| Does the audience-path group ranking encode the intent? | A user follows the highest-ranked group they match, so order is logic. Any ordering is syntactically fine; only one reflects what you meant when overlapping groups were designed. |
| Should the 'Everyone Else' catch-all exit or advance? | Exit versus advance is a deliberate choice about unknown data. Both are legal. Choosing wrong silently absorbs users who needed handling. |
| Should this delay be three days? | Reading the value is mechanical. Judging it against how the behaviour actually decays needs someone who knows the product and has seen the curve. |
| Does the copy tell the truth about what the user just did? | Grammar and rendering are checkable. Whether the email claims something the product does not do is not checkable. Neither is whether it lands as helpful or as nagging. |
| Will these names mean anything in a year? | A machine flags 'Group 1' and blank names. It cannot tell you that 'Paid' should have been 'Paid – Has Not Added Services', because that requires knowing what the filter underneath is for. A vague group name usually hides a vague filter. |
The pattern across all six: the machine establishes what is true, the human decides whether it is right. Confusing those two is how a QA pass produces a confident green tick over a journey that is internally consistent and strategically wrong.
The trap in the middle: checkable is not the same as API-checkable
Most attempts at automating this break on a detail nobody writes down. Several of the machine-ownable checks cannot be done through the Braze API at all, because the API does not expose the configuration they inspect.
So "a machine can own this check" sometimes means a script hitting an endpoint, and sometimes means a model driving the Canvas Flow editor in a browser: opening each gate, clicking each step, reading the configuration off the screen. Both are automation. Only one of them works for delays and filters. Assuming the wrong one is how a QA report ends up asserting things nobody verified.
That gives a blunt rule for reading anyone's Canvas QA output, including your own tooling's: every quantitative claim — a segment size, a step count, a delay value — has to come from a live read performed during that pass. Not from memory, not from the build spec, not from an estimate that sounds plausible. A number in a QA report with no read behind it is the report's weakest point. It is usually the number someone acts on.
The three rules that keep a QA pass from becoming an incident
Whoever or whatever runs the pass, these hold. They are constraints on the QA process itself rather than checks on the Canvas.
Never launch during QA. Use plain Save. Do not click through toward a launch state to see what happens, because on a live Canvas what happens is that it launches. QA is not a licence to ship. A tool given QA scope should not be given launch scope in the same session.
Keep entry on a test audience for the whole pass. Restore it if you change it. The single most expensive mistake available here is leaving the real audience attached to a Canvas you are poking at. If you swap the audience to test, the pass is not finished until it is swapped back and confirmed.
Verify the settings that lock before anything else. Conversion events cannot be added or removed after launch. Re-entry settings are fixed once live. Those items belong at the top of the pass, not buried at item thirty-one, because a wrong conversion event discovered post-launch means rebuilding the Canvas to measure the thing you were always trying to measure.
Test sends deserve one specific trick: embed the step name or the user ID in the test body via Liquid. Six test emails in an inbox all look alike. Without a marker you cannot tell which step produced which, so the test send verified that mail arrives rather than that the right mail arrives from the right step.
What to do with this on Monday
Take your current Canvas checklist and mark each line M or H. Machine-decidable or human-judgement. Most teams discover the list is roughly two-thirds M, which means two-thirds of the attention currently spent on ticking boxes is being spent on the part a tool does better and never gets bored doing.
Then hand the M items over and protect the H items. Give them the front of the pass, while whoever is running it is still reading properly. The point of automating the mechanical two-thirds is not speed — it is that the conversion event, the group ranking and the catch-all routing finally get looked at by someone with attention left.
One structural note worth taking seriously: if the specification the Canvas is being checked against lives only in the head of the person doing the checking, this exercise has a ceiling regardless of tooling. A checklist compares configuration to intent, and intent needs a written home. That is the source-of-truth argument. It is upstream of everything here. If you are still deciding what access the QA tooling should have, start read-only — QA needs to see everything and change nothing.
The full severity-rated version, with the go / no-go call at the end, is in the Canvas QA skill.
Read next
The Braze Canvas QA skill — the full severity-rated checklist
Frequently asked questions
- Can a model run the whole Canvas QA on its own?
- It can run the decidable two-thirds and produce a findings table with severities. It cannot tell you whether the conversion event matches the KPI or whether a delay suits the behaviour, because both need the program's intent. The output to expect is a pass with a shortlist of judgement calls escalated to you, not a verdict.
- Why fingerprint templates by content instead of checking the name?
- Because the Braze API's message-step title field is usually null, so there is often no name to check. Fetching the bound template and matching on subject, preheader and one distinctive block is the only reliable way to confirm which variant is actually attached to a step.
- Which items should sit at the very top of the pass?
- Anything that locks at launch. Conversion events cap at four and cannot be changed afterwards. Re-entry settings are fixed once live. Everything else is fixable after go-live; those are not, which makes them blockers rather than findings.
- Will a Braze test send verify the emails on its own?
- Only if you can tell which send came from which step, so embed the step name or user ID via Liquid in the test body. And judge rendering on the delivered message rather than the design tool's preview — link-wrapping and client-side rewriting happen after the preview and are exactly what causes clipping and dark-mode surprises.
- How does this differ from a general pre-launch review?
- A pre-launch review covers any campaign or significant change and asks whether it should go out. This one is narrower. It verifies a Braze Canvas is built the way it was specified — step by step — and returns a go or no-go on that basis. Run the Canvas pass first — a strategy review of a mis-bound journey reviews the wrong thing.
This post is backed by an Orbit skill
More in Point it at your stack
What a read-only Braze key already buys you — and where its ceiling actually is
Read-only access to a live Braze workspace covers most of the work worth handing a model: inventory, Canvas and template review, segment analysis, naming enforcement, data-model validation. The ceiling is real, but it is not the permission checkboxes. It is the API surface itself.
The handoff packet: seven parts, and the build question each one kills
A lifecycle handoff is measured in the questions asked after it lands, not the pages in it. Here are the seven parts of a packet a builder can ship from without you, the two everyone skips and why the packet now has a second reader who forgets everything between sessions.
Stop writing the email design system. Derive it from what you already send.
A written design system describes the emails you meant to build. Your sent HTML describes the ones you actually built. Machine ingestion reads the second — here is what it can genuinely recover from a Figma file or a shipped template, what it cannot and the line where a module catalogue becomes a system.
Found this useful? Share it with your team.
You finished the playbook. Get the next.
New guides and product updates land in your inbox when they ship. One list, real lifecycle work, unsubscribe the second it stops being useful.
Guides and Orbit updates only. No sequences, no selling your address.
Use this in Claude
Claude can run this playbook for you.
Orbit is a free extension for Claude Desktop — no licence key, no card — that runs the lifecycle work you just read about. You've read how it works; Orbit hands Claude the same playbook as a skill it can execute: discovery, build, QA, push, on your own ESP.
Download Orbit — free