Skip to content

Embed a custom flow in a system flow

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.

Before you begin
  • 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.

The system flow builder. You can add blocks to any of the editable stages.

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.

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.

Run custom flow lives in the Control flow family. It only appears in system-flow palettes, not in custom-flow palettes.

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.

The picker shows the name and slug of every published custom flow. Drafts do not appear here.

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.

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.

When a user's sign-in reaches the Run custom flow block in the parent system flow:

  1. The platform suspends the parent flow at that block.
  2. 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.
  3. The custom flow executes stage by stage, block by block, writing to its own state namespace (custom.<slug>.*).
  4. When the custom flow reaches a terminal block (Allow or Deny), it returns its outcome to the parent.
  5. 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.

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.

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.

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.

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.