A working guide, in applied mode, to PingOne DaVinci. It starts with the vocabulary of flows, nodes, connectors, connections, and capabilities, then covers building on the canvas and why the logic lives on the connecting line rather than in the node. It explains the four variable contexts with their exact {{...}} syntax, subflow input and output schemas, and deployment through applications and flow policies with versions and A/B weights. It also covers the six launch methods, among them the widget, redirect, API, and SDK, and a debugging ladder built from Validate Flow, Flow Analytics, log levels, correlation IDs, and the documented flow limits. Nine traps, six checks, a production-readiness checklist, and cited documentation links round it out.
Subject: Identity & Access Management · 120 slides · applied lesson
Open the interactive version of this deck · Homework for this lesson
Title
Identity Orchestration · Working Guide
The vocabulary, the canvas, the variable syntax, the deployment layer, and the debugging ladder — everything you need to build a flow that survives contact with production.
Objectives
DaVinci looks like a flowchart tool, which is why people underestimate it. The canvas is the easy part; the parts that bite are variables, versions, and limits.
{{...}} syntax.This deck pairs with the PingOne Protect deck — Protect decides how risky a sign-on is, DaVinci decides what to do about it. You can take either one first.
Warm-up
Discussion prompt
Before we open PingOne DaVinci - Orchestrating Identity Flows: without looking back, what was the main idea of Building a PingOne Protect Demo for Your Company, and what could you do by the end of it that you could not do before?
Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.
Answer:
An end-to-end guide, in applied mode, to building a credible PingOne Protect demo. It starts with what Protect is and is not, then lays out the three-beat demo arc, the licence tiers, and the eight Risk-tier predictors as against the six Protect-tier ones. From there it walks through standing up the environment and the worker app, building a targeted risk policy with scores, thresholds, overrides, and mitigation, wiring it up through the riskEvaluations API and a DaVinci flow, adding the PingOne Signals SDK, triggering each predictor live, and proving the result on the Threat Protection dashboard and in the audit log. The deck includes nine traps, six checks, a full run of show, and two closing slides of cited documentation links.
Section
Part 1
Concept
Picture the login logic at a company that's been running five years. Sign-on lives in a Java filter. The MFA rule lives in a different service. Registration has its own copy of the email-verification code, slightly out of date.
Now the fraud team asks for one change: step up to MFA when risk is high, but only for customers, not employees.
That's a two-week ticket across three teams, and nobody can draw the current behavior on a whiteboard without arguing.
DaVinci's proposition is that this logic should be one diagram that executes, owned by the identity team, changed without a deployment.
Counterexample
Discussion prompt
DaVinci's proposition is that this logic should be one diagram that executes, owned by the identity team, changed without a deployment.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Intuition
Every company already has these diagrams. They're in Confluence, they're six months stale, and the code drifted away from them.
The single idea worth taking from this deck: in DaVinci the diagram is not documentation of the system — the diagram is the system.
There is no separate implementation that can drift, because the canvas is what executes at runtime.
That's also the trade. When the diagram is the system, sloppy diagrams become production incidents — which is exactly why Ping's own best-practice guidance is mostly about layout, naming, and annotation, things that would be cosmetic in any other tool.
Analogy
Discussion prompt
Explain A flowchart that actually runs by analogy to something with no Identity & Access Management in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
Every company already has these diagrams. They're in Confluence, they're six months stale, and the code drifted away from them.
Concept
PingOne DaVinci — "An orchestration platform that lets you create flows to guide users through IAM activities."
Unpack that. Orchestration means it coordinates other systems rather than being the system of record. IAM activities means sign-on, registration, password reset, step-up, consent, recovery.
DaVinci rarely stores your users or checks your passwords. It calls the things that do, in an order you drew, with branching you control.
Say this early when explaining it to a colleague, because the most common misconception is that DaVinci replaces the directory. It doesn't. It conducts.
Explain it
Discussion prompt
Explain What DaVinci is, in Ping's own words to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
Unpack that. Orchestration means it coordinates other systems rather than being the system of record. IAM activities means sign-on, registration, password reset, step-up, consent, recovery.
Concept
Almost every confused DaVinci conversation is two people using one of these four words to mean different things.
The relationship reads in one sentence: a flow is made of nodes; each node is a connector plus one of its capabilities.
Concept
This is the distinction that trips up every newcomer, and the docs use all three words on the same page.
| Term | What it is | Analogy |
|---|---|---|
| Connector | The integration type — the thing that knows how to talk to PingOne, or HTTP, or Twilio | The class |
| Connection | A configured instance of a connector, with its own environment, keys, and settings | The instance |
| Capability | One action that connector exposes, chosen per node | The method you call |
You can configure multiple instances of the same connector with different environments or settings — that's how one flow reaches a dev PingOne tenant and another reaches production.
So a node reads as: this connection, doing this capability. Once that clicks, the canvas stops being mysterious.
Trade off
Comparison matrix
From Connector vs connection vs capability: every row here is a choice with a cost. Fill the Analogy column, then say which row you would actually pick and what you give up for it.
| Term | What it is | Analogy |
|---|---|---|
| Connector | The integration type — the thing that knows how to talk to PingOne, or HTTP, or Twilio | The class |
| Connection | A configured instance of a connector, with its own environment, keys, and settings | The instance |
| Capability | One action that connector exposes, chosen per node | The method you call |
Ranking
Put in order
Put the moves of Reading a flow left to right into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. User-facing nodes pause the flow and wait for input; backend nodes don't.
Worked example
Here's a minimal sign-on flow. Practise narrating one out loud — it's how you'll onboard a teammate.
Node 1: an HTTP connector with a Custom HTML Template capability shows the username and password form.
Why: User-facing nodes pause the flow and wait for input; backend nodes don't.
Node 2: a PingOne connector capability checks those credentials against the directory.
Why: DaVinci didn't validate the password itself — it asked the system whose job that is. That's orchestration.
A logical operator on the connection between node 2 and node 3 decides the branch.
Why: The operator lives on the line, not on the node — this is the single most surprising thing about the canvas for people coming from code.
Node 3a on success: create a session and return. Node 3b on failure: an Error Message connector node.
Why: Both branches must terminate; a branch that dangles is exactly what Validate Flow will flag later.
Verify by walking the diagram and asking, at every line, "what makes this path get taken?"
Why: If you can't answer for a given line, that line is a future incident.
Reverse engineer
Discussion prompt
Work backwards. The example finished here:
Verify by walking the diagram and asking, at every line, "what makes this path get taken?"
What was it asked to do, and what must it have been given? Reconstruct the problem from its answer.
Hint: Every quantity in the result had to enter somewhere. Account for each one.
Answer:
Here's a minimal sign-on flow. Practise narrating one out loud — it's how you'll onboard a teammate.
Concept
Building a flow does not make it reachable. There's a second layer, and skipping past it is why a new user's first flow "doesn't do anything."
Ping's sequence: after you create a flow, you "add it to an application and create a flow policy to control how and when the flow gets used."
The useful way to hold it: the flow is the program, the application is the entry point, and the flow policy is which build of the program runs today.
Anomaly
Predict first
A student writes this, and it looks reasonable:
The assumption: the canvas is live, so saving a flow updates what users get.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: The flow policy is pinned to a specific saved version, so your edit is sitting in a newer version nobody is routed to.
The model: editing a flow creates a version; the flow policy chooses which version runs.
Why: The flow policy is pinned to a specific saved version, so your edit is sitting in a newer version nobody is routed to.
Trap
The assumption: the canvas is live, so saving a flow updates what users get.
You edit the flow, save, and test through the application.
Why: The flow policy is pinned to a specific saved version, so your edit is sitting in a newer version nobody is routed to.
You conclude DaVinci is caching and start clearing things at random.
Why: The real cause is a deployment layer you didn't know was between you and the user.
The model: editing a flow creates a version; the flow policy chooses which version runs.
Check the flow policy's Flows section and see which version it points at.
Why: The policy can name specific versions, or use the Latest Version option to always follow the newest.
For a dev environment, point the policy at Latest Version so edits take effect immediately.
Why: For production, pin an explicit version — that's the whole reason the indirection exists.
Pattern
Photograph this. Getting these seven words right is most of what fluency in DaVinci means.
| Word | One-line definition |
|---|---|
| Flow | The executable diagram of one IAM journey |
| Node | One task in that diagram |
| Connector | The integration type a node uses |
| Connection | A configured instance of a connector |
| Capability | The specific action the node performs |
| Application | The entry point that lets outside systems run flows |
| Flow policy | Which flow and which version an application actually runs |
If you can fill this table from memory, you can read any DaVinci screenshot and any DaVinci support thread.
Comparison
Comparison matrix
From The vocabulary card: refill the One-line definition column from what you know. The rest of the table is as it appeared.
| Word | One-line definition |
|---|---|
| Flow | The executable diagram of one IAM journey |
| Node | One task in that diagram |
| Connector | The integration type a node uses |
| Connection | A configured instance of a connector |
| Capability | The specific action the node performs |
| Application | The entry point that lets outside systems run flows |
| Flow policy | Which flow and which version an application actually runs |
Elimination
Eliminate the wrong options
You built and saved a flow, but calling your application still runs the old behavior. What is the most likely cause?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: An application reaches a flow through a flow policy, and that policy names specific flows and versions — with Latest Version as an option. If the policy is pinned to an earlier version, new edits live in a version nothing routes to. This indirection is deliberate: it is what lets you edit safely while production keeps running a known-good build.
Check
One of these confusions accounts for most first-week frustration.
Check your understanding
You built and saved a flow, but calling your application still runs the old behavior. What is the most likely cause?
Answer: A
Why: An application reaches a flow through a flow policy, and that policy names specific flows and versions — with Latest Version as an option. If the policy is pinned to an earlier version, new edits live in a version nothing routes to. This indirection is deliberate: it is what lets you edit safely while production keeps running a known-good build.
Section
Part 2
Concept
Open the connector catalog and it's overwhelming. It's much smaller once you know it sorts into four groups.
| Category | What lives there |
|---|---|
| Core connectors | Foundational flow mechanics — HTTP, Functions, Variables, Error Message, Flow Conductor |
| Ping connectors | Integration with other Ping products — PingOne, PingOne MFA, PingOne Protect, PingFederate |
| Service connectors | Third-party integrations — messaging, fraud, verification, CRM |
| Use case connectors | Pre-orchestrated solutions for common scenarios |
You will spend 80% of your time in Core. Learn those five properly and the rest are just APIs with a nice form in front of them.
Concept
These are the ones worth memorizing, because they appear in essentially every flow you'll ever open.
| Connector | What it does |
|---|---|
| HTTP | "Display custom HTML pages, make REST API calls, and more" — the workhorse |
| Functions | Branching through logical conditions or custom code |
| Flow Conductor | Initiates asynchronous external events and supports subflows |
| Variable | Stores and retrieves flow attributes |
| Error Message | Customizes error messaging within flows |
Notice how much of the canvas is not identity-specific. HTTP, Functions, and Variables are general programming primitives wearing a flowchart costume — which is a useful thing to tell a developer who's skeptical of no-code tools.
Concept
If you only learn one connector, learn this one. Three of its capabilities carry most flows:
Make REST API Call is the escape hatch that makes DaVinci viable in a real company: whatever bespoke internal service you must consult, you call it from the canvas rather than filing a ticket against the identity codebase.
Matching
Match the pairs
From The HTTP connector earns its own slide — match each one to what it actually does. The descriptions have been shuffled.
Why: Custom HTML Template, Custom HTML Message, Make REST API Call are easy to tell apart while they are sitting next to their descriptions and much harder afterwards, which is what this checks.
Concept
These are how DaVinci reaches the rest of the platform. Each wraps a product's API behind capabilities.
| Connector | What it brings into a flow |
|---|---|
| PingOne | Core PingOne functionality — users, sessions, directory operations |
| PingOne Authentication | User authentication and session management |
| PingOne MFA | Cloud-based multifactor authentication |
| PingOne Protect | Risk evaluation — reduces MFA fatigue while still challenging in high-risk situations |
| PingFederate | Leverages existing PingFederate authentication policies |
The PingFederate row is the one that unblocks migrations: a company can orchestrate in DaVinci while its authentication policies still live on-premises, rather than having to move everything at once.
Intuition
It seems like bureaucracy at first: why configure a connection when you already chose a connector?
Because the connector describes how to talk to a system, while the connection describes which instance of that system, with which credentials.
You can configure multiple instances of one connector with different environments or settings. One PingOne connector; a dev connection and a prod connection.
That separation is what makes a flow portable. Move the flow between environments and you re-point the connection — the diagram itself doesn't change.
Trap
The shortcut: a single PingOne connection, pointed at production, used by every flow.
You test a registration flow on the canvas.
Why: It creates real users in the production directory, because the connection never distinguished environments.
Cleaning up means deleting real records, and you can't be certain which ones were yours.
Why: The blast radius of a test is now the size of production.
The discipline: one connection per environment, named for the environment.
Create separate connections — e.g. PingOne - Dev and PingOne - Prod — even though they use the same connector.
Why: Naming them by environment makes the wrong choice visible on the canvas instead of buried in a settings panel.
Promote a flow between environments by re-pointing its nodes at the other connection.
Why: The diagram is unchanged, which is exactly the property that makes the flow reviewable.
Ranking
Put in order
These are the steps of Choosing a connector, scrambled. Put them back in order before the next slide shows you.
Why: This is the order the recipe itself gives. Recalling the sequence without the slide in front of you is the difference between recognising the method and being able to run it — most of what goes wrong in practice is a step done out of turn.
Pattern
Work down this list and stop at the first match. It resolves almost every "which node do I use?" question.
Reaching for raw HTTP when a purpose-built connector exists is the most common form of DaVinci technical debt.
Prediction
Predict first
Your flow must run against a development PingOne tenant in dev and a production tenant in prod, without redrawing the flow. What do you create?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: Two connections from the same PingOne connector, one per environment, and re-point the nodes
Why: A connector is the integration type; a connection is a configured instance of it with its own environment and settings. You can configure multiple instances of the same connector, which is precisely the mechanism for having dev and prod tenants without duplicating the flow. The diagram stays identical and only the connection binding changes.
Check
This distinction shows up in every DaVinci support thread.
Check your understanding
Your flow must run against a development PingOne tenant in dev and a production tenant in prod, without redrawing the flow. What do you create?
Answer: A
Why: A connector is the integration type; a connection is a configured instance of it with its own environment and settings. You can configure multiple instances of the same connector, which is precisely the mechanism for having dev and prod tenants without duplicating the flow. The diagram stays identical and only the connection binding changes.
Section
Part 3
Step zero
Discussion prompt
Creating your first flow — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: On the Flows tab, click Add Flow.
Answer:
Worked example
Concretely: you've been asked to build a sign-on journey. Here's the opening sequence.
On the Flows tab, click Add Flow.
Why: Everything starts here; flows are the top-level object you'll spend your time in.
Choose one of the three starting options.
Why: The choice matters more than it looks — see the next beat.
| Option | Ping's description | When to pick it |
|---|---|---|
| Template Flow | "Create a flow starting with a template created by Ping." | Learning, or a standard journey |
| Import Flow | "Import a flow that was exported in JSON format." | Promoting between environments |
| Blank Flow | "Create a flow starting from a blank canvas." | A journey genuinely unlike the templates |
For your first build, start from a Template Flow even if you intend to replace most of it.
Why: Templates come pre-wired with the error handling and node titling conventions you'd otherwise learn by breaking things.
Verify you can run the template unchanged before editing anything.
Why: A known-good starting point means every later break is attributable to a change you made.
Blank canvas
Draw it
Draw what Creating your first flow just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.
Concept
When you place a node, you choose what kind of thing it is:
| Node type | What it's for |
|---|---|
| Connector | A task performed by a connector capability — the overwhelming majority of nodes |
| User Interface | A screen presented to the user |
| Subflow | Runs another flow as a step inside this one |
Subflow is the one to notice early. It's the only reuse mechanism DaVinci has, and it's the difference between one 200-node monster and eight readable flows.
Estimation
Predict first
Four ways to add a node, and they are not interchangeable — pick by what you want the canvas to look like afterwards.
Commit before you compute: what does Adding and wiring nodes come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: Verify each new node has a meaningful Node Title on its Settings tab before moving on.
Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Ping's guidance is explicit about this, and an untitled node is a warning in Validate Flow.
Worked example
Four ways to add a node, and they are not interchangeable — pick by what you want the canvas to look like afterwards.
Click the plus icon in the lower left of the canvas to create an unconnected node.
Why: Useful when you're sketching, but an unconnected node is something Validate Flow will complain about, so connect it before you save.
Drag from the start or stop icons on an existing node to create a connected node.
Why: This is the default move — it wires the connection as it creates the node, so you never forget the line.
Right-click an existing node and select Clone to duplicate it with its configuration.
Why: Fastest way to make a second, similar node — but see the node-ID trap later, because clones carry variable references with them.
Select nodes, right-click, choose Copy, then right-click the canvas and select Paste Nodes.
Why: This is how you lift a working sub-sequence into another part of the flow.
Connect two nodes by clicking and dragging a line between them.
Why: The line is a real object with its own configuration, which is the key idea on the next slide.
Verify each new node has a meaningful Node Title on its Settings tab before moving on.
Why: Ping's guidance is explicit about this, and an untitled node is a warning in Validate Flow.
Sorting
Sort into buckets
These are the pieces of PingOne DaVinci - Orchestrating Identity Flows, out of order. Put each one back under the part of the lesson it belongs to.
Concept
This is the single biggest adjustment for anyone coming from code. In a program, the if is a statement. On this canvas, the condition lives on the connection between two nodes.
Right-click a connecting line to change its operator type — for example If All True or If Any False.
So a node with three outgoing lines is a three-way branch, and each line carries its own condition. There is no separate "if node" holding it together.
Practical consequence: when a flow takes the wrong path, inspect the line, not the node. Newcomers lose hours re-reading node configuration for a decision that was never stored there.
Ranking
Put in order
Put the moves of A risk-based sign-on, node by node into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. Give every input element a unique ID; Ping's best practices call for this so you can reference the values later in the flow.
Worked example
The concrete build: sign the user in, but step up to MFA when PingOne Protect says the attempt is risky. This is the flow the Protect deck's demo runs on.
Node 1 — HTTP connector, Custom HTML Template: collect username and password.
Why: Give every input element a unique ID; Ping's best practices call for this so you can reference the values later in the flow.
Node 2 — PingOne Protect connector, Create Risk Evaluation.
Why: Evaluate before the access decision, so the result can still change what happens next.
Node 3 — PingOne connector: validate the credentials.
Why: Order is a genuine design choice; evaluating risk first lets you deny obvious automation without spending a directory lookup on it.
Wire three lines out of the risk node, branching on the returned risk level.
Why: Low goes straight through, medium routes to MFA, high routes to denial — the branching is yours, not a Ping default.
Node 4 — PingOne MFA connector on the medium branch.
Why: This is the payoff of orchestration: the step-up rule is a line on a diagram, not a deployment.
Node 5 — PingOne Protect connector, Update Risk Evaluation, on every terminating branch.
Why: Including the deny path. The completion status is what lets the risk models learn from outcomes.
Verify by running the flow once per branch and confirming each path terminates cleanly.
Why: Three runs, three outcomes — anything that dangles will show up in Validate Flow anyway, so find it now.
Concept
In most tools, tidy diagrams are a nicety. Here the diagram is the source code, so Ping's best practices read like a style guide — and they're worth following literally.
Treat these as you'd treat a linter in a codebase: not opinions, but the accumulated cost of other people's incidents.
Concept
Past a certain size, lines crossing the canvas make a flow unreadable. Teleport nodes jump execution to another point without drawing a line across everything.
Ping recommends them to improve readability and enable section reuse in large flows, with two specific cautions:
The second caution is the subtle one: several teleports converging on one node makes the flow's actual execution order genuinely ambiguous to a human reader, which defeats the point of using them.
Anomaly
Predict first
A student writes this, and it looks reasonable:
The design: after a failed password, draw a line back to the first node to "try again."
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Each pass re-executes those nodes, and each node can only run a limited number of times per invocation.
The design: one clear start, and retries as an explicit loop that does not re-enter it.
Why: Each pass re-executes those nodes, and each node can only run a limited number of times per invocation.
Trap
The design: after a failed password, draw a line back to the first node to "try again."
The retry path re-enters the flow's starting point.
Why: Each pass re-executes those nodes, and each node can only run a limited number of times per invocation.
A user who fumbles their password several times hits the execution ceiling and the flow dies oddly.
Why: The error surfaces nowhere near the actual cause, so it gets debugged as a connector problem.
The design: one clear start, and retries as an explicit loop that does not re-enter it.
Follow Ping's guidance: begin with a single starting point and avoid looping back to it.
Why: Retry by routing back to the form node, not to the flow's entry node.
Budget the loop against the documented limit of 20 executions per node per invocation.
Why: Three password attempts is fine; an unbounded retry loop is a time bomb with a documented fuse.
Pattern
The order that avoids rework. Steps 1 and 2 feel skippable and are the ones that cost most when skipped.
Ping's own summary of when this matters most: complex flows — parallel branches, data processing, loops, API normalization — require extensive planning and testing.
Check
This catches people who learned flowcharts from writing code.
Check your understanding
A flow keeps taking the failure branch even though the credential check succeeds. Where should you look first?
Answer: A
Why: In DaVinci the branching condition lives on the connection between nodes, not inside the node. You right-click a connecting line to set its operator type, such as If All True or If Any False. When a flow takes an unexpected path, the line is where the decision was actually configured.
Section
Part 4
Concept
Concretely: you capture an email at registration and need it three nodes later, or a support flag set last month that should change today's journey. Those are different problems, and DaVinci solves them with different variable contexts.
Variable context — What determines how widely a variable's value is shared — across one flow run, across a user's lifetime, or across the whole company.
Every variable has a context. Picking the wrong one is the source of both classic bugs: a value that mysteriously vanishes, and a value that mysteriously persists.
Concept
Learn the syntax literally. These are the strings you type into node fields, and a typo fails quietly as an empty value.
| Context | Reference syntax | Lives as long as |
|---|---|---|
| Company | {{global.company.variables.variableName}} | The whole tenant — shared configuration |
| User | {{global.userInfo.variables.variableName}} | The user — persists across sessions |
| Flow | {{global.flow.variables.variableName}} | The flow definition |
| Flow instance | {{global.variables.variableName}} | This single execution |
Notice the odd one: flow instance variables have the shortest path, {{global.variables.name}}, with no qualifier. The most-used context got the shortest name.
That's also the one that bites — {{global.variables.x}} and {{global.flow.variables.x}} look nearly identical and mean very different lifetimes.
Step zero
Discussion prompt
Reaching into a nested value — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Write the variable reference in full braces first.
Answer:
Worked example
Variables aren't always flat. When a company variable holds an object, you append the path outside the braces.
{{global.company.variables.variablename}}.level1.level2Write the variable reference in full braces first.
Why: The braces delimit the variable lookup; anything after them is path navigation on the result.
Append the object path after the closing braces, dot-separated.
Why: This is the part people get wrong — putting the path inside the braces makes the whole reference fail to resolve.
Verify by echoing the value into a debug message before you depend on it.
Why: An unresolved reference yields an empty value rather than an error, so it will not announce itself.
Concept
There's an asymmetry here that costs people an afternoon, and it's worth stating flatly.
Per the docs: "The variables connector can be used to update User variables and Flow Instance variables. It can also be used to create flow instance variables, but user variables must be created in the variables tab."
| Operation | Variables connector | Variables tab |
|---|---|---|
| Create flow instance variable | Yes | Yes |
| Update flow instance variable | Yes | — |
| Create user variable | No | Yes — required |
| Update user variable | Yes | — |
So a flow can set a user variable at runtime but cannot invent one. Declare user variables in the Variables tab first, then write to them from the canvas.
Discrimination
Sort into buckets
Sort these by Variables connector, from memory, without looking back at Who can create and update what. Telling them apart on the spot is the skill; the table is only where the answer happens to be written down.
Trap
The code: a Functions node comparing a variable straight into an expression.
You write the variable reference bare, the way you would a number.
Why: The docs warn that the variable's exact value is substituted into the code, so a string arrives without quotation marks and the expression is malformed.
The node fails or silently evaluates wrong, and the branch goes the wrong way.
Why: Because substitution is textual, the symptom is a syntax-shaped failure a long way from the variable's definition.
The rule: quote by type, because substitution is literal.
Surround a string variable in quotation marks; leave boolean and number variables bare.
Why: This is Ping's stated guidance — take the variable type into account when writing the code.
Confirm the declared Data Type of the variable before writing the expression.
Why: The type is declared where the variable was created, and it is the thing that decides whether quotes are required.
Break the constraint
Discussion prompt
The rule this trap just fixed:
The type is declared where the variable was created, and it is the thing that decides whether quotes are required.
Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?
Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.
Answer:
The docs warn that the variable's exact value is substituted into the code, so a string arrives without quotation marks and the expression is malformed.
Intuition
Once a flow passes about forty nodes, nobody reads it. Subflows are how you get back to something a colleague can review.
The analogy is exact: a subflow is a function. It has parameters going in, a return value coming out, and it exists so the same logic isn't written twice.
A good candidate is any sequence you'd describe with a single verb — "verify the email", "send the OTP", "check the risk". If it needs a paragraph, it isn't one subflow.
The payoff is the same as with functions: fixing a bug in email verification means fixing it once, not in the six flows that happen to verify email.
Ranking
Put in order
Put the moves of Passing data into a subflow into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. This declares what the subflow expects, which is also what makes it self-documenting to whoever calls it.
Worked example
Data crosses the boundary through input and output schemas — the parameter list and the return type.
Open the subflow and click Input Schema.
Why: This declares what the subflow expects, which is also what makes it self-documenting to whoever calls it.
Use the variable name as the Parameter Name.
Why: Keeping the names identical on both sides removes an entire category of mapping mistake.
Select the Data Type matching the variable's type.
Why: Same reason quoting matters in Functions nodes — type is load-bearing, not decorative.
Enable Required if the flow cannot function without it.
Why: A required parameter fails loudly at the boundary rather than as an empty value deep inside the subflow.
Define the output schema the same way for values the parent flow needs back.
Why: Without an output schema the subflow can do work but cannot report anything, which is a surprisingly easy mistake to ship.
Verify by calling the subflow with a deliberately missing required parameter.
Why: You want to see it fail at the boundary — that confirms the contract is real and not just documentation.
Anomaly
Predict first
A student writes this, and it looks reasonable:
The shortcut: clone a working node to make a similar one, then edit its settings.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Those references point at the original node's ID, so the new node reads output produced somewhere else entirely.
The habit: after any clone or copy, verify the node IDs.
Why: Those references point at the original node's ID, so the new node reads output produced somewhere else entirely.
Trap
The shortcut: clone a working node to make a similar one, then edit its settings.
The clone carries its variable references with it.
Why: Those references point at the original node's ID, so the new node reads output produced somewhere else entirely.
The flow runs without error and produces subtly wrong data.
Why: Nothing fails, which makes this among the hardest DaVinci bugs to spot by reading the canvas.
The habit: after any clone or copy, verify the node IDs.
Turn on Show Node ID from the More Options menu.
Why: The docs recommend exactly this to verify variables point at the expected node ID after copying or cloning.
Walk each variable reference in the new node and confirm the source ID is the one you intend.
Why: Ten seconds per cloned node, against an afternoon of debugging data that is wrong but plausible.
Ranking
Put in order
These are the steps of Variable hygiene, scrambled. Put them back in order before the next slide shows you.
Why: This is the order the recipe itself gives. Recalling the sequence without the slide in front of you is the difference between recognising the method and being able to run it — most of what goes wrong in practice is a step done out of turn.
Pattern
Six rules that prevent nearly every variable bug in DaVinci.
The last one is the highest-value habit in this deck. Unresolved references produce empty values rather than errors, so the only way to know a reference works is to look at it.
Commit first
Predict first
What is the difference between {{global.variables.orderId}} and {{global.flow.variables.orderId}}?
Commit to an answer, then rate it — certain, fairly sure, or guessing — and write the rating down before you turn the page.
Correct: The first is a flow instance variable scoped to a single execution; the second is a flow variable tied to the flow definition
Why: Flow instance variables are referenced as {{global.variables.variableName}} and hold values for one execution of the flow. Flow variables use {{global.flow.variables.variableName}} and belong to the flow definition rather than a single run. The near-identical syntax for very different lifetimes is exactly why this pair causes confusion.
The rating matters as much as the answer: confident-and-wrong is the combination that survives revision, because nothing about it feels like it needs revisiting.
Check
Read the two references carefully before answering.
Check your understanding
What is the difference between {{global.variables.orderId}} and {{global.flow.variables.orderId}}?
Answer: A
Why: Flow instance variables are referenced as {{global.variables.variableName}} and hold values for one execution of the flow. Flow variables use {{global.flow.variables.variableName}} and belong to the flow definition rather than a single run. The near-identical syntax for very different lifetimes is exactly why this pair causes confusion.
Section
Part 5
Concept
A flow with no application is a program with no main. The application is what lets the outside world start it.
Applications enable you to run flows using a widget, API calls, OpenID Connect (OIDC) calls, or SAML 2.0 calls — and to A/B test across different flows.
So the application answers two questions at once: by what protocol does something reach this journey, and which journey does it get.
Step zero
Discussion prompt
Creating an application and flow policy — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: On the Applications tab, click Add Application, then Edit…
Answer:
Worked example
The click path, in order. The two easy-to-miss steps are flagged.
On the Applications tab, click Add Application, then Edit the one you created.
Why: The application is the container; the routing lives on its Flow Policy tab.
Open the Flow Policy tab and click + Add Flow Policy.
Why: One application can carry several policies, which is how one front door serves several journeys.
Enter a name in the Policy Name field.
Why: Name it for the journey and the audience, e.g. 'Customer sign-on', because this name is what you'll pick from later.
Decide whether to enable PingOne Flow Policy — this cannot be changed later.
Why: Enable it if you plan to launch the flow through a redirect. Getting this wrong means deleting the policy and starting again.
If using PingOne flows, choose bypass options for existing sessions — Password Based Authentication and/or MFA Based Authentication — with time ranges.
Why: This is how you avoid re-challenging a user who authenticated two minutes ago.
Click Next, then in the Flows section select the flows and their versions.
Why: The Latest Version option follows the newest version automatically; anything else pins.
Click Next to reach the weight distribution modal and set weights from 1 to 100.
Why: Weights are percent chance of selection when multiple flows are listed — this is the A/B testing mechanism.
Optionally add IP whitelists to bypass weights, then choose Analytics - Select Success Nodes.
Why: Success nodes are what let DaVinci compute a success rate for the flow, so pick the genuine terminal-success nodes.
Click Create Flow Policy, then apply the changes on the General tab.
Why: Verify by invoking the application and confirming the expected flow version runs — the apply step is the one people forget.
Blank canvas
Draw it
Draw what Creating an application and flow policy just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.
Concept
The flow policy is quietly the most powerful screen in DaVinci, because it turns a risky change into a measured one.
Each flow can have multiple versions specified, and distribution weights act as percent chance of selection across them.
Ship a new registration flow to 10% of traffic by weighting old at 90 and new at 10.
Why: Nobody redeploys anything; you're changing the routing, not the software.
Watch the success rates via the analytics success nodes you selected.
Why: This is why choosing genuine terminal-success nodes matters — the comparison is only as good as the definition of success.
Move the weights as confidence grows, and pin to the new version when done.
Why: The rollback is equally instant, which is the actual reason this is valuable.
IP whitelists bypass the weights — that's how your QA team always lands on the new version while customers are still being split.
Concept
Choosing wrong here means rebuilding the user-facing half of your flow, so decide before you draw screens.
| Method | Ping's description | Pick it when |
|---|---|---|
| Redirect through PingOne | "Launches flow in new browser tab" | You want a full-page journey with OIDC or SAML |
| Redirect via DaVinci as external IdP | Similar, but "not recommended unless you have already configured your environment for it" | Legacy setups only |
| Widget | "Launches flow within current browser tab" | You don't want to send the user to a new URL |
| API call | "Launches flow without UI components using API call" | The flow has no screens at all |
| SDK | "Launches flow from native or web apps using the Ping SDKs" | You want fine-grained control of a mobile experience |
| PingFederate integration | Uses the widget to launch flows from a PingFederate deployment | PingFederate is already the front door |
OIDC and SAML are not separate methods — they're the protocols the redirect methods use. That distinction saves an argument in design review.
Comparison
Comparison matrix
From Six ways to launch a flow: refill the Pick it when column from what you know. The rest of the table is as it appeared.
| Method | Ping's description | Pick it when |
|---|---|---|
| Redirect through PingOne | "Launches flow in new browser tab" | You want a full-page journey with OIDC or SAML |
| Redirect via DaVinci as external IdP | Similar, but "not recommended unless you have already configured your environment for it" | Legacy setups only |
| Widget | "Launches flow within current browser tab" | You don't want to send the user to a new URL |
| API call | "Launches flow without UI components using API call" | The flow has no screens at all |
| SDK | "Launches flow from native or web apps using the Ping SDKs" | You want fine-grained control of a mobile experience |
| PingFederate integration | Uses the widget to launch flows from a PingFederate deployment | PingFederate is already the front door |
Hypothesis
Predict first
Launching with the widget is about to be worked. State your hypothesis first: which rule or definition decides this one, and what is the first move it forces? Then watch whether the example agrees with you.
Correct: Your frontend asks your own backend for a DaVinci SDK token, which posts to /dvtoken.
Why: The token request is server-side precisely so the next point holds.
A hypothesis you wrote down is falsifiable; a vague sense of how it will go is not. If the example opens somewhere else, that gap is the thing worth chasing.
Worked example
The widget is the common choice for a web app that doesn't want to navigate away. It's a two-step dance, and the split matters for security.
Your frontend asks your own backend for a DaVinci SDK token, which posts to /dvtoken.
Why: The token request is server-side precisely so the next point holds.
Understand why: "The /sdktoken call must be executed on the server side, not in client-side code, to protect the application's API key from exposure on a public web page."
Why: Doing this in the browser publishes your API key to anyone who opens devtools. This is the one security rule of widget integration.
The frontend then renders the flow with the SDK token, company ID, policy ID, and API root URL.
Why: The policy ID is the flow policy you configured — that's the link between the page and the journey.
davinci.skRenderScreen(
document.querySelector(".dvWidget"),
props
);Verify by confirming no API key appears in the browser's network tab or page source.
Why: If it does, the token call is running in the wrong place, and the fix is architectural rather than a config toggle.
Error analysis
Annotate
Walk the callouts on Launching with the widget. Each one is a place this is easy to get subtly wrong.
Concept
For native mobile or a JS app wanting full control of the UI, the Ping SDKs run the flow behind the scenes and render native screens.
Flows launched this way must use compatible connectors: HTTP Connector with Custom HTML Template, or Form Connector with Show Form.
Submit buttons need specific attributes so the SDK can recognize them:
type=submit
data-skbuttonvalue="Continue"|"Submit"|"Proceed"|"Next"Three global parameters are available inside the flow, which is how a flow can adapt to the platform it's running on:
| Parameter | Meaning |
|---|---|
| p1UserId | The user's PingOne identifier, after authentication |
| isSdk | Boolean — was this flow invoked from an SDK? |
| platformType | String — js, android, or ios |
Anomaly
Predict first
A student writes this, and it looks reasonable:
The order: design the journey, build every screen with Custom HTML Templates, then decide how the app calls it.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: SDK-launched flows accept only specific connector capabilities and need data-skbuttonvalue attributes on submit buttons.
The order: choose the launch method first, then build screens against its constraints.
Why: SDK-launched flows accept only specific connector capabilities and need data-skbuttonvalue attributes on submit buttons.
Trap
The order: design the journey, build every screen with Custom HTML Templates, then decide how the app calls it.
The mobile team says they need native screens via the SDK.
Why: SDK-launched flows accept only specific connector capabilities and need data-skbuttonvalue attributes on submit buttons.
Every user-facing node needs revisiting.
Why: The orchestration logic was fine; the entire presentation layer was built against the wrong contract.
The order: choose the launch method first, then build screens against its constraints.
Ask up front whether the caller is a web page, a native app, or a headless service.
Why: Headless means the API method and no screens at all — which changes the flow's shape completely, not just its styling.
If SDK is even possible, build user-facing nodes to its contract from day one.
Why: Custom HTML Template plus the required button attributes works for both widget and SDK; the reverse is not true.
Constraint
Discussion prompt
Run Deployment recipe with this step confiscated:
Set weights if you're A/B testing, and whitelist QA's IPs.
Is it still possible? If it is, say what takes its place and what it costs you. If it is not, say exactly what that step was providing that nothing else does.
Hint: A step you can drop for free was never load-bearing. If you cannot drop it, name the thing that goes wrong the moment it is gone.
Answer:
Pattern
From finished canvas to serving traffic.
Steps 3 and 7 are the two that produce "it doesn't work and I can't see why."
Edge cases
Discussion prompt
Deployment recipe works on the cases you have just seen. Push it to the edge: what is the most degenerate input it still handles — empty, zero, one item, everything equal — and what is the first case where it stops being true? Name the case, not just "it breaks".
Hint: Try the smallest legal input, then the largest, then the one where two things collide. Methods are specified at their edges; the middle takes care of itself.
Answer:
Steps 3 and 7 are the two that produce "it doesn't work and I can't see why."
Prediction
Predict first
While creating a flow policy, which setting cannot be changed later and therefore needs a deliberate decision up front?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: The PingOne Flow Policy option, which must be enabled if you plan to launch the flow through a redirect
Why: The flow policy creation flow offers a PingOne Flow Policy option and the documentation notes it cannot be changed later. It is the setting that matters if you intend to launch the flow through a redirect, so getting it wrong means deleting the policy and creating it again.
Check
One of these choices is permanent. That's the hint.
Check your understanding
While creating a flow policy, which setting cannot be changed later and therefore needs a deliberate decision up front?
Answer: A
Why: The flow policy creation flow offers a PingOne Flow Policy option and the documentation notes it cannot be changed later. It is the setting that matters if you intend to launch the flow through a redirect, so getting it wrong means deleting the policy and creating it again.
Section
Part 6
Concept
Before you debug behavior, let the tool find the structural problems. Open a flow on the Flows tab and click Validate Flow.
It sorts findings into two buckets, and the distinction is meaningful:
| Category | Meaning | Examples |
|---|---|---|
| Errors | Must be resolved before deployment | Empty flows, disabled nodes, missing form selections, circular subflow dependencies |
| Warnings | Won't block execution but hurt clarity or function | Missing node titles, debug-level logging, unmapped outcomes |
The UI shows "View X Error(s)", or "View X Warning(s)" when there are no errors. The Error Validation pane opens, where Show Warnings includes warnings, and View Error / View Warning highlights the offending node.
Circular subflow dependencies is the one to notice — a subflow calling something that calls back into it is invisible on any single canvas.
Trade off
Comparison matrix
From Validate Flow — do this before anything else: every row here is a choice with a cost. Fill the Meaning column, then say which row you would actually pick and what you give up for it.
| Category | Meaning | Examples |
|---|---|---|
| Errors | Must be resolved before deployment | Empty flows, disabled nodes, missing form selections, circular subflow dependencies |
| Warnings | Won't block execution but hurt clarity or function | Missing node titles, debug-level logging, unmapped outcomes |
Step zero
Discussion prompt
Reading Flow Analytics — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Open the flow and click Analytics in the lower left to open the…
Answer:
Worked example
A user reports a failure at 14:20. Here's how you find that exact execution.
Open the flow and click Analytics in the lower left to open the Flow Analytics window.
Why: The window shows a graph of flow runs across a date range plus an Events Logs section for individual executions.
Search by Flow Execution ID, User ID, User Name, Correlation ID, or Transaction ID.
Why: If your support process captures any one of these, you go straight to the run instead of hunting by timestamp.
Select the execution to see Flow Duration and, per node, the Node Title, Connector, and Capability.
Why: This is where meaningful node titles stop being a style preference and start saving you time.
Expand an event to read the JSON request and response between nodes.
Why: This is the ground truth for what a connector actually sent and received, as opposed to what you assumed.
Note how nodes are highlighted: at Info or Debug all executed nodes highlight; at Error only the initial node and error nodes do.
Why: So the path you can see depends on the log level that was active at execution time — you cannot retroactively raise it.
Verify against the two documented constraints before concluding data is missing.
Why: Analytics may be delayed up to 30 minutes at high volume, and run details are retained for 30 days.
Reverse engineer
Discussion prompt
Work backwards. The example finished here:
Verify against the two documented constraints before concluding data is missing.
What was it asked to do, and what must it have been given? Reconstruct the problem from its answer.
Hint: Every quantity in the result had to enter somewhere. Account for each one.
Answer:
A user reports a failure at 14:20. Here's how you find that exact execution.
Concept
When analytics doesn't show enough, raise the log level — deliberately and temporarily.
Go to Flow Settings and open the Logging tab, then set Log Level to Debug.
Why: Debug gives "additional insight into the properties, parameters, and connector inputs between nodes" — the between-node data that Info omits.
Use the Scrub Sensitive Information options when the flow handles anything private.
Why: Debug logs may contain sensitive data; this is the control that keeps a debugging session from becoming a data incident.
Reset to Info when you're done.
Why: The docs call this out for performance, and Validate Flow raises debug-level logging as a warning precisely because it gets left on.
Remember the interaction with analytics: log level determines which nodes highlight in a past execution, so raising it only helps for runs after you changed it.
Trap
The situation: you set Debug to chase a bug on Friday and ship the fix.
The flow stays on Debug in production.
Why: Every execution now writes verbose logs including properties and connector inputs between nodes.
Log volume and sensitive-data exposure both grow quietly.
Why: Nothing breaks, so nothing prompts anyone to look — the cost is invisible until an audit or a bill finds it.
The habit: Debug is a tool you pick up and put down.
Set Debug, reproduce once, capture the execution, then set Info back immediately.
Why: Ping's guidance is explicit about resetting the level afterward for performance.
Let Validate Flow be your backstop — it reports debug-level logging as a warning.
Why: Running validation before each deploy turns a habit you might forget into a check that catches it.
Concept
A flow that fails silently is worse than one that fails loudly. Two mechanisms, and the docs are clear about which belongs where.
| Mechanism | Use | How |
|---|---|---|
| HTTP connector, Custom HTML Message | Debugging and test flows | Click {} in the Message field, select skerrormessage from the SK-Component source |
| HTTP connector, Custom HTML Template | Debugging with full page control | Use HTML with data-skcomponent="skerrormessage" |
| Error Message connector | Production | Purpose-built for consistent, customized error messaging |
The rule of thumb: skerrormessage is for you; the Error Message connector is for your users. Raw DaVinci error text is diagnostic, not something a customer should ever read.
Concept
Real incidents cross products. A user failed sign-on; the trace has to survive the hop from DaVinci into PingOne and out to PingFederate.
| Identifier | What it traces |
|---|---|
| correlationId | An HTTP request within PingOne microservices |
| transactionId | A complete flow execution across all services |
| externalTransactionId | The bridge between PingOne and external systems such as PingFederate |
| sessionId / externalSessionId | A user's session across executions |
transactionId is the one to put in your support ticket template. It spans the whole execution, which is the unit a user is actually complaining about.
You can also ship flow data to an external aggregator using the HTTP connector's Make REST API Call, adding a header with x-log-key as the key and your API key as the value.
Concept
These are documented numbers, not folklore. Several of them shape architecture, so read them before you draw a big flow rather than after.
| Limit | Value |
|---|---|
| Node executions per invocation | 20 per node (excluding polling nodes) |
| Saved versions per flow | 100 |
| Max payload for an API call in a flow | 10 MB |
| Max payload per node | 1 MB |
| Flow timeout | Default 5 minutes, maximum 2 days |
| HTTP response timeout | Default 15 seconds, maximum 120 seconds |
| Entities per environment | 100 of each type (flows, connections) |
| Variables per environment | 200 total, each up to 1 MB |
The 20-execution ceiling is the one that surprises people, because it's per node per invocation and it's what turns an innocent-looking retry loop into an outage.
Comparison
Comparison matrix
From The limits you must design around: refill the Value column from what you know. The rest of the table is as it appeared.
| Limit | Value |
|---|---|
| Node executions per invocation | 20 per node (excluding polling nodes) |
| Saved versions per flow | 100 |
| Max payload for an API call in a flow | 10 MB |
| Max payload per node | 1 MB |
| Flow timeout | Default 5 minutes, maximum 2 days |
| HTTP response timeout | Default 15 seconds, maximum 120 seconds |
| Entities per environment | 100 of each type (flows, connections) |
| Variables per environment | 200 total, each up to 1 MB |
Concept
The flow timeout defaults to 5 minutes and can technically go to 2 days. Ping's practical advice is much narrower.
"Values between 300 (5 minutes) and 900 (15 minutes) are appropriate for most flows. Do not use a value greater than 7200 (2 hours)."
The reasoning is worth internalizing: a flow holds state while it waits. A long timeout means abandoned sessions accumulate rather than being cleaned up.
If a journey genuinely needs to pause for a day — waiting on a manual approval, say — that's a signal to use an asynchronous pattern via the Flow Conductor connector, not a longer timeout.
Explain it
Discussion prompt
Explain Timeouts: the recommended band to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
The flow timeout defaults to 5 minutes and can technically go to 2 days. Ping's practical advice is much narrower.
Anomaly
Predict first
A student writes this, and it looks reasonable:
The design: a polling loop that checks an external system until it returns ready.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Each node can run a maximum of 20 times per flow invocation, so the 21st pass fails.
The design: bound every loop, and use the right tool for waiting.
Why: Each node can run a maximum of 20 times per flow invocation, so the 21st pass fails.
Trap
The design: a polling loop that checks an external system until it returns ready.
The loop routes back through the same node repeatedly.
Why: Each node can run a maximum of 20 times per flow invocation, so the 21st pass fails.
It works in testing, where the external system responds on the second try.
Why: The ceiling is only reached when the external system is slow — which is exactly when you least want a second failure mode.
The design: bound every loop, and use the right tool for waiting.
Count the maximum passes your loop can take and confirm it's under 20.
Why: If you can't bound it, it isn't a loop — it's a wait, and it needs a different pattern.
Use the Flow Conductor connector for genuinely asynchronous waits.
Why: It initiates asynchronous external events, which is the supported way to wait without burning node executions.
Two truths and a lie
Sort into buckets
Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.
Pattern
Climb in order. Each rung is cheaper than the one above it, and most bugs fall off in the first three.
Rung 6 deserves emphasis: an unresolved variable reference yields an empty value rather than an error, so looking at the value is often the only way the bug ever reveals itself.
Elimination
Eliminate the wrong options
A node's output is consistently empty, but the flow runs with no errors and Validate Flow reports nothing. What is the most likely cause?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: An unresolved variable reference — a typo in the context path, or a reference pointing at the wrong node ID after a clone — produces an empty value instead of an error. Nothing fails, so neither the run nor Validate Flow flags it. This is why echoing a new reference into a debug message before building logic on it is such a high-value habit.
Check
The symptom here is deliberately quiet. That's the point.
Check your understanding
A node's output is consistently empty, but the flow runs with no errors and Validate Flow reports nothing. What is the most likely cause?
Answer: A
Why: An unresolved variable reference — a typo in the context path, or a reference pointing at the wrong node ID after a clone — produces an empty value instead of an error. Nothing fails, so neither the run nor Validate Flow flags it. This is why echoing a new reference into a debug message before building logic on it is such a high-value habit.
Section
Part 7
Concept
These two products are constantly confused because they appear in the same flow and are sold together.
Protect produces a verdict. DaVinci produces a consequence. Neither is useful alone: a risk score with no consequence is a dashboard, and a flow with no risk signal is a fixed decision tree.
In connector terms, that whole relationship is three nodes: Create Risk Evaluation, branch, Update Risk Evaluation.
Analogy
Discussion prompt
Explain DaVinci and Protect, in one sentence each by analogy to something with no Identity & Access Management in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
Protect produces a verdict. DaVinci produces a consequence. Neither is useful alone: a risk score with no consequence is a dashboard, and a flow with no risk signal is a fixed decision tree.
Pattern
Before a flow carries real users. Every line here maps to something earlier in this deck.
skerrormessage.If a colleague can read your canvas and predict what each line does without opening a single node, the flow is ready. That is the real test.
Real world
Discussion prompt
Outside this lesson: where does PingOne DaVinci - Orchestrating Identity Flows actually turn up? Name one concrete situation — a job, a piece of software someone ships, a decision somebody has to make — and say which part of Production readiness checklist is doing the work in it.
Hint: Vague is the failure mode here. "Engineering" is not a situation; "deciding whether this build is fast enough to ship" is.
Answer:
A working guide, in applied mode, to PingOne DaVinci. It starts with the vocabulary of flows, nodes, connectors, connections, and capabilities, then covers building on the canvas and why the logic lives on the connecting line rather than in the node. It explains the four variable contexts with their exact {{...}} syntax, subflow input and output schemas, and deployment through applications and flow policies with versions and A/B weights. It also covers the six launch methods, among them the widget, redirect, API, and SDK, and a debugging ladder built from Validate Flow, Flow Analytics, log levels, correlation IDs, and the documented flow limits. Nine traps, six checks, a production-readiness checklist, and cited documentation links round it out.
Section
Sources
Concept
Every product-behavior claim in this deck traces to a page below. All were fetched and confirmed to resolve.
These eight share one base: docs.pingidentity.com/davinci/
| What it backs up in this deck | Page (append to the base above) |
|---|---|
| Flows, nodes, connectors, capabilities, applications — the definitions | davinci_introduction.html |
| Add Flow, the three starting options, adding and connecting nodes | flows/davinci_how_to_create_a_flow.html |
| The four variable contexts and their exact syntax; nested values | variables/davinci_using_variables_in_flows.html |
| Flow policy click-path, versions, weights, success nodes | applications/davinci_configuring_a_flow_policy.html |
| Annotation, node titles, teleport cautions, timeout band | davinci_best_practices/davinci_best_practices_building_flows.html |
| Analytics, log levels, Show Node ID, skerrormessage, correlation IDs | davinci_best_practices/davinci_best_practices_debugging_and_analytics.html |
| Validate Flow: errors vs warnings and the UI labels | flows/davinci_validating_a_flow.html |
| Every documented limit and its number | flows/davinci_flow_limits.html |
The deck's JSON carries all entries with full URLs in its sources block.
Counterexample
Discussion prompt
The deck's JSON carries all entries with full URLs in its sources block.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Concept
The remaining pages, shown in full.
| What it backs up in this deck | URL |
|---|---|
| The six ways to integrate a flow into an application | docs.pingidentity.com/davinci/integrating_flows_into_applications/davinci_how_to_implement_a_flow.html |
| Widget launch, the /dvtoken server-side rule, skRenderScreen | docs.pingidentity.com/davinci/integrating_flows_into_applications/davinci_launching_a_flow_with_the_widget.html |
| SDK launch, p1UserId / isSdk / platformType, data-skbuttonvalue | docs.pingidentity.com/davinci/integrating_flows_into_applications/davinci_sdk_launching_a_flow_with_the_sdk.html |
| Flow Analytics window, search fields, retention and delay | docs.pingidentity.com/davinci/flows/davinci_viewing_flow_analytics.html |
| Connector categories and the core utility connectors | docs.pingidentity.com/connectors/index.html |
| PingOne Protect connector capabilities and branch options | docs.pingidentity.com/connectors/p1_protect_connector.html |
As with the Protect deck, the teaching craft here — the debugging ladder, the readiness checklist, the vocabulary card — is judgment layered on documented behavior, and it's labelled as such in sources.
Connect it up
Draw it
One page, no notation unless you need it: draw how these connect — The Mental Model · Connectors: the Building Blocks · Building a Flow · Variables and Subflows · Deploying a Flow · Debugging and Limits. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.
Recap
You can build, deploy, and debug a DaVinci flow — and explain to a skeptical developer why the diagram is trustworthy.
{{...}} syntax, quote by declared type.The three ideas that carry the most weight:
Pair this with the PingOne Protect deck for the full picture: Protect decides how risky the moment is, DaVinci decides what happens next.
Want this taught 1-on-1? Alexander tutors Identity & Access Management — $55/session, free consultation.