Flowscope
Re-understand Okta Workflows. Drop in an export and get a plain-English account of what each flow does, what it changes, what depends on it, and how two versions differ. Everything runs in your browser.
- JavaScript
- Vite
- Playwright
- Okta Workflows
Why I built it
Okta is part of my day job. The problem Flowscope solves is a familiar one: you build a flow in Okta Workflows, come back six months later, and have to work out what it does by clicking through every card. The export doesn’t help. It’s dense, deeply nested JSON.
So I built a tool that reads the export and tells you in plain English.
What it does
Open a .flow, .folder or .flopack export and you get:
- A summary. A headline naming the systems it touches (“deactivates user in Salesforce, posts to Slack”), every read and write grouped by system, the tables it uses, hardcoded values, and warnings. When the engineer left comment cards, the walkthrough is built from their own notes.
- Impact analysis. Who calls this flow, directly or through a chain, and which flows are tied to it through a shared Workflows Table with no call between them. The Okta console doesn’t show that last kind of dependency.
- A semantic diff. It compares meaning, not JSON: cards added or removed, values before and after, and above all, changes to what the flow does to external systems.
- A portability spec. Ordered steps, every branch condition, inputs, tables, API calls and error handling, plus an explicit list of what a human still has to decide. Nothing is guessed. An endpoint it can’t verify becomes a decision, not an invention.
- A graph of the flow, with branch arms and error handlers drawn as labelled groups.
Why it runs only in your browser
Okta exports aren’t scrubbed. Email addresses, group names and other hardcoded values stay in them, and they describe production identity infrastructure. So Flowscope never uploads anything. The whole tool is one self-contained 169 KB file with no runtime dependencies, and the hosted page ships a security policy (connect-src 'none') that stops the browser from making any outbound call.
The hard part
Okta stores each If/Else arm as a complete sub-flow inside the branch card. A parser that reads only the top level misses all of it. In the largest flow I tested, a shallow read sees 10 cards. The real count is 116.
Tested against real exports
I test every change against 61 sample exports collected from the Okta developer forum: 223 flows and 2,884 cards, 494 of them hidden inside branch arms. The corpus check runs 5,205 assertions in about a second. Among them: a flow diffed against itself must come out identical, and no flow can be its own caller. A browser test then drives the built file over every export.
When I moved the engine into its own modules, I rendered all 1,088 screens before and after and compared them byte for byte to prove nothing a user sees had changed. That move also exposed real bugs, including one where cards inside branch arms showed no incoming data at all.
These are sample flows, not customer data, so a green run means nothing broke on known inputs. It isn’t proof of completeness.
What the exports revealed
- Error handling is rare. Of the 113 sample flows that write to an external system, 107 have no error handling at all.
- Hidden coupling is common. Of 39 flows that use Workflows Tables, 27 are tied to another flow only through a shared table.
- Migration takes human judgement. Across all 223 flows, the portability spec flagged 321 decisions for a person to make, and invented zero endpoints.