A published custom flow doesn't run until you embed it in a system flow. This page shows you how to do that, explains what happens when the flow runs, and covers how the time budget is shared between the parent and the nested flow.
- You have a custom flow in Published state. If not, see Author a custom flow first.
- You know which system flow you want to embed it in (Login, Registration, Password Reset, etc.) and roughly which stage.
- You have tenant Admin access to the admin console.
Step 1 — Open the system flow in the builder
Section titled “Step 1 — Open the system flow in the builder”Navigate to Flows in the left sidebar. Click the System flows tab and open the flow you want to modify — Login, Registration, or whichever is right for your use case.
/screenshots/tenant_admin.custom_flows.embedding/system-flow-builder-open.png Step 2 — Choose the right stage
Section titled “Step 2 — Choose the right stage”Think about when in the authentication sequence your custom flow's logic should run. A few common placements:
- Post-Auth — after the user's credentials are verified but before the session is issued. Good for fraud screening, risk-based step-up, or enrichment that depends on knowing who the user is.
- Post-Login — after the session is issued. Useful for logging, notifications, or CRM sync where the session being created is a prerequisite.
- Pre-Create (in Registration) — before the user account is saved. Use this for reject-before-create logic (disposable email blocks, domain allowlists).
- Post-Create (in Registration) — immediately after the account is created. Good for enrichment fan-out to CRMs, webhooks, or tagging.
If you're uncertain, Post-Auth in the Login flow is the most common starting point.
Step 3 — Add the Run custom flow block
Section titled “Step 3 — Add the Run custom flow block”Inside the stage you chose, click + Add block. In the block catalogue, find Run custom flow (in the Control flow family) and click or drag it into the stage.
/screenshots/tenant_admin.custom_flows.embedding/run-custom-flow-block-in-palette.png The block appears in the stage with a warning that no custom flow has been selected yet.
Step 4 — Pick which custom flow to invoke
Section titled “Step 4 — Pick which custom flow to invoke”Click the block's settings icon (gear). A picker opens listing every published custom flow in your tenant.
/screenshots/tenant_admin.custom_flows.embedding/run-custom-flow-picker.png Select the custom flow you want to invoke. The block label updates to show the flow's name. You can also configure:
- On error — what to do if the custom flow fails unexpectedly. Options are Halt (stop the parent flow, same as Deny) or Continue (let the parent flow proceed as if Allow was returned). The default is Halt; choose Continue only if the custom flow is optional enrichment you don't want to block sign-in for.
Click Save.
Step 5 — Save and test the system flow
Section titled “Step 5 — Save and test the system flow”Save the system flow with the Save button. The change takes effect immediately for new sign-in attempts.
Before relying on it with real users, test it. Use the Test button in the builder to simulate a sign-in — supply a test user email and request context, then run. The trace panel shows each block's execution, including the steps inside the nested custom flow, so you can confirm it ran and returned the outcome you expected.
The Test pane runs the flow for real — it doesn't have a dry-run mode. If the run reaches a session-issuing block, a real session is created. Test against a scratch account on a non-production tenant, not against a live user. See Test and publish a flow for the full test guidance.
What happens at run time
Section titled “What happens at run time”When a user's sign-in reaches the Run custom flow block in the parent system flow:
- The platform suspends the parent flow at that block.
- It starts the custom flow as a nested run. The custom flow inherits the in-flight user's identity, device context, risk signals, and everything in the shared state up to that point.
- The custom flow executes stage by stage, block by block, writing to its own state namespace (
custom.<slug>.*). - When the custom flow reaches a terminal block (Allow or Deny), it returns its outcome to the parent.
- The parent resumes from the Run custom flow block, with the custom flow's outputs now available in state under
custom.<slug>.*.
If the custom flow returns Allow, the parent continues. If it returns Deny, the parent halts — the user's sign-in does not complete.
Reading the custom flow's outputs
Section titled “Reading the custom flow's outputs”Any data the custom flow writes to state is available to subsequent blocks in the parent flow. Reference it in block configurations and conditions using the {} picker — look under custom.<slug>.* where <slug> is the slug of your custom flow.
For example, if your fraud-screening custom flow is slugged fraud-gate and it writes a risk_verdict key in one of its blocks, a Decision block later in the parent flow can read custom.fraud-gate.risk_verdict to branch on the result.
Allow and Deny — what they mean for the parent
Section titled “Allow and Deny — what they mean for the parent”Allow from a custom flow means the parent flow continues running from the block after the Run custom flow block. The parent flow's subsequent blocks have access to the custom flow's state outputs.
Deny from a custom flow means the parent flow halts immediately. The user's authentication attempt fails. The reason the custom flow gave for denying is surfaced to the user (if you configured one) and recorded in the audit log.
If your custom flow uses a condition to branch between Allow and Deny, both paths must end with a terminal block. A custom flow that can reach a code path with no terminal block will not publish.
Budget arithmetic — the shared 10-second ceiling
Section titled “Budget arithmetic — the shared 10-second ceiling”Every authentication flow has a hard ceiling of 10 seconds from start to finish. This ceiling is shared between the parent system flow and any custom flows it invokes.
If your custom flow takes 4 seconds to run, the parent system flow has 6 seconds left for everything before it and after it. If the custom flow takes 9 seconds, the parent has 1 second — and if the parent's remaining blocks take longer, the whole flow times out and the user sees an error.
Design your custom flows to be fast. A few practical rules:
- Webhook calls to external services should respond in under 2 seconds. Anything slower is better handled asynchronously via an event subscription.
- IP reputation and risk-evaluate blocks are fast (milliseconds). Use them freely.
- If a custom-action block in your custom flow makes multiple serial external calls, consider whether they can run in parallel using the Parallel webhook block instead.
If a run times out, the audit log records the timeout and which block was executing when the budget was exhausted. Use that to identify the slow block and either optimise the call or move it off the authentication path.
The 10-second ceiling restarts for each new sign-in. It is not a per-user-per-day or per-day limit — it is a wall-clock limit per individual authentication event.
Removing or swapping the custom flow
Section titled “Removing or swapping the custom flow”To remove the Run custom flow block: open the system flow in the builder, click the block's remove icon (X), and save. The system flow reverts to running without the custom flow. Users signing in after the save do not encounter it.
To swap one custom flow for another: open the block's settings, change the selection in the picker, and save. The old flow stops running; the new one runs from the next sign-in onward.
What can go wrong
Section titled “What can go wrong”The custom flow doesn't appear in the picker. The flow must be in Published state. Drafts are not available for embedding. Go to Flows → Custom flows, open the flow, and publish it.
"Custom flow timed out." The nested flow — plus everything in the parent before it — exceeded 10 seconds. Check the audit log for the block that was running when the timeout hit. Optimise that block or remove it from the authentication path.
"Custom flow returned an unexpected error." The custom flow hit an unhandled error in one of its blocks. The behaviour depends on the On error setting on the Run custom flow block: Halt stops the parent; Continue lets it proceed. Check the flow's recent-run trace in Flows → Custom flows → [your flow] → Recent runs for details.
The parent flow continues even after I expected a Deny. Confirm the On error setting on the Run custom flow block. If it's set to Continue, an error in the custom flow is treated as implicit Allow. Also confirm your custom flow's terminal block is actually reachable from every code path — use the Test pane to step through the branching logic.
Where to go next
Section titled “Where to go next”With a custom flow embedded and tested, you're running your own business logic as part of IntelliAuth's authentication sequence. A few things to do from here:
- Watch it run — check Flows → Custom flows → [your flow] → Recent runs after real users sign in. The trace shows every block's execution and state output.
- Check the audit log — every custom flow invocation writes an entry. Open Settings → Audit log and filter for events on your flow's slug.
- Try a template — if you're just getting started with the kinds of logic custom flows can carry, the Recipes section has a set of finished patterns (fraud screening, CRM sync, enrichment fan-out) you can instantiate and adapt.