# JavaScript workflow designer, one script tag and one endpoint

Source: https://workflowengine.io/features/javascript-workflow-designer/
Site index for agents: https://workflowengine.io/llms.txt (products, licensing, documentation hosts, package names).
Product: Workflow Designer, the visual editor that ships with Workflow Engine by Optimajet. Ran on 2026-09-09: designer 22.1.0 (CDN @22 and npm), Workflow Engine 22.1.0 on SQLite, Node 25, Vite 8.2.2.

## What it is

Workflow Designer is a plain JavaScript object. A page creates it with new WorkflowDesigner({...}) from a script tag or an npm import, gives it a div and an API address, and the designer talks over HTTP to one endpoint in your app, the Designer API, which hands each request to WorkflowRuntime.DesignerAPIAsync. The scheme the user draws is the scheme the engine runs. Workflow Engine Free includes the full designer. No framework is required; React and Angular have wrapper packages, Vue, Svelte and jQuery pages use the object directly.

## Four parts, three calls

- **Page to designer.** One constructor call, new WorkflowDesigner(...), with the API address, the div id and the canvas size. From a script tag or from an npm import, it is the same call.
- **Designer to your API.** Plain HTTP. GET and POST requests to one address: exists, load, save, validate, and the file operations. Your own headers ride along through $.ajaxSetup.
- **API to engine.** One method call. DesignerAPIAsync reads and writes your database and returns the text the designer expects.

## Diagram library or workflow designer

Sequential Workflow Designer (MIT, sequential flows, a separate JavaScript engine), React Flow, JointJS and GoJS are the right pick when you only need drawing. A workflow designer is for a diagram that must run: commands, timers and people on steps, schemes that load again next year, changes that change the running process.

| The job | With a diagram library | Workflow Designer ships |
| --- | --- | --- |
| Canvas, palette, drag and drop | Your nodes and links on the library canvas (React Flow, JointJS, GoJS, Sequential Workflow Designer) | The designer UI: palette, property panels, undo and redo, copy, full screen |
| The scheme model | Your own classes for steps, links and rules, and their JSON | Activities, transitions, commands, timers, actors and parameters in one scheme |
| Checks before save | Your validation code | designer.validate() in the browser and the scheme parser on the server |
| Save, load, versions | Your storage, your versioning | exists, load, save, downloadscheme and uploadscheme through DesignerAPIAsync; scheme versions kept by the engine |
| Running the process | Your engine, or a second product | WorkflowRuntime: CreateInstanceAsync, commands, state, timers, history |
| People and roles on steps | Your permission checks | Actors and rules on transitions, answered by your IWorkflowRuleProvider |
| Showing a running process | Your own overlay on the drawing | Pass processId; the current activity is highlighted. Live updates with the Real-Time Tracking Plugin (commercial) |
| Diagrams from BPMN tools | A converter you write | BPMN 2.0 import through the BPMN plugin |

## The sample

One HTML file, one script, the designer from the CDN, and a Designer API in ASP.NET Core with CORS for the page. The npm path is the same script as an ES module. Every block ran.

### 1 · index.html: the page, the designer from the CDN

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Workflow Designer in plain JavaScript</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@optimajet/workflow-designer@22/dist/workflowdesigner.min.css" />
  <style>
    body { margin: 0; font-family: system-ui, sans-serif; }
    #wfe-designer { height: 720px; }
  </style>
</head>
<body>
  <div id="wfe-designer"></div>

  <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@optimajet/workflow-designer@22/dist/workflowdesignerfull.min.js"></script>
  <script src="main.js"></script>
</body>
</html>
```

### 2 · main.js: create the designer, load the scheme

```javascript
// The whole integration: create the designer inside the div, then load the
// scheme if the backend has it, or start a blank one.
const host = document.getElementById('wfe-designer');

const designer = new WorkflowDesigner({
  apiurl: 'http://localhost:5199/Designer/API',
  renderTo: 'wfe-designer',
  graphwidth: host.clientWidth,
  graphheight: host.clientHeight,
  showSaveButton: true,
});

const data = { schemecode: 'SimpleWF', processid: undefined };
if (designer.exists(data)) {
  designer.load(data);
} else {
  designer.create(data.schemecode);
}
```

### 3 · The npm path: the same main.js as an ES module, served by Vite

```javascript
// npm path: the package as an ES module, the stylesheet from its dist folder.
import WorkflowDesigner from '@optimajet/workflow-designer';
import '@optimajet/workflow-designer/dist/workflowdesigner.min.css';

const host = document.getElementById('wfe-designer');
const designer = new WorkflowDesigner({
  apiurl: 'http://localhost:5199/Designer/API',
  renderTo: 'wfe-designer',
  graphwidth: host.clientWidth,
  graphheight: host.clientHeight,
  showSaveButton: true,
});
const data = { schemecode: 'SimpleWF', processid: undefined };
if (designer.exists(data)) designer.load(data); else designer.create(data.schemecode);
```

### 4 · Program.cs: the Designer API, with CORS for the page's origin

```csharp
using System.Collections.Specialized;
using System.Text;
using OptimaJet.Workflow;
using OptimaJet.Workflow.Core.Runtime;
using WfeDesignerApi;

var builder = WebApplication.CreateBuilder(args);

// One WorkflowRuntime for the whole app. SQLite keeps the sample self-contained.
builder.Services.AddSingleton<WorkflowRuntime>(_ =>
    WorkflowRuntimeSetup.Create("Data Source=workflow.db"));

// The designer runs in the browser on another origin (a static page, Vite,
// ng serve), so the API must say so. Name the origins you serve; never
// AllowAnyOrigin outside development.
builder.Services.AddCors(options => options.AddPolicy("designer", policy =>
    policy.WithOrigins("http://localhost:3001", "http://localhost:5173", "http://localhost:4200")
          .AllowAnyHeader()
          .AllowAnyMethod()));

var app = builder.Build();
app.UseCors("designer");

// The endpoint the designer talks to: query and form parameters go to
// WorkflowRuntime.DesignerAPIAsync, an uploaded file becomes a stream.
app.MapMethods("/Designer/API", new[] { "GET", "POST" }, async (HttpRequest request, WorkflowRuntime runtime) =>
{
    var parameters = new NameValueCollection();
    foreach (var q in request.Query)
    {
        parameters.Add(q.Key, q.Value.FirstOrDefault());
    }

    Stream? fileStream = null;
    if (HttpMethods.IsPost(request.Method) && request.HasFormContentType)
    {
        var form = await request.ReadFormAsync();
        foreach (var key in form.Keys)
        {
            if (parameters[key] is null)
            {
                parameters.Add(key, form[key]);
            }
        }
        if (form.Files.Count > 0)
        {
            fileStream = form.Files[0].OpenReadStream();
        }
    }

    var (result, hasError) = await runtime.DesignerAPIAsync(parameters, fileStream);

    if (string.Equals(parameters["operation"], "downloadscheme", StringComparison.OrdinalIgnoreCase) && !hasError)
    {
        return Results.File(Encoding.UTF8.GetBytes(result), "text/xml");
    }
    return Results.Content(result);
}).RequireCors("designer");

// Start the runtime (and run the SQLite migrations) before the first request.
app.Services.GetRequiredService<WorkflowRuntime>();

app.Run();
```

### 5 · Run it

```bash
# 1. The Designer API on :5199 (Workflow Engine 22.1.0 on SQLite)
cd samples/designer-api
dotnet run --urls http://localhost:5199

# 2. The page on :3001, no build step
cd samples/javascript-workflow-designer
npx serve -l 3001 .

# The npm path instead: Vite on :5173
cd samples/javascript-workflow-designer/vite
npm install
npx vite
```

## Three things the documentation does not tell you

- **Your API must allow the page's origin.** The designer calls the Designer API from the browser. When the page and the API are on different origins (a static page on :3001, Vite on :5173, the API on :5199), the API must send CORS headers for that origin, or the browser blocks every call. Name the origins in the policy; AllowAnyOrigin is for development only.
- **On the CDN path, jQuery comes first.** The CDN build expects jQuery 3.7.1 on the page before workflowdesignerfull.min.js, and your main.js after both. The npm package brings jQuery as its own dependency, so the bundled path needs no extra script and no order to keep.
- **The full build carries the templates.** workflowdesignerfull.min.js and the npm package include the designer's templates. If you take workflowdesigner.min.js and the CSS from the repository's Designer folder instead, put its templates folder next to them and pass templatefolder in the settings.

## CDN or npm

|  | CDN, no build | npm, with a bundler |
| --- | --- | --- |
| Where the designer comes from | jsDelivr: @optimajet/workflow-designer@22/dist/workflowdesignerfull.min.js | npm install @optimajet/workflow-designer, then import WorkflowDesigner from it |
| The stylesheet | A <link> to dist/workflowdesigner.min.css | import '@optimajet/workflow-designer/dist/workflowdesigner.min.css' |
| jQuery | You add jquery-3.7.1 first | A dependency of the package, imported for you |
| Strict Content-Security-Policy | The no-CSS-in-JS entry point plus the stylesheet, per the vendor documentation | import from '@optimajet/workflow-designer/strict' plus the stylesheet |
| Build step | None: any static server | Your bundler: Vite, webpack |
| Status | Ran with npx serve | Ran with Vite 8.2.2 (webpack per the vendor sample, not run here) |

## What Workflow Engine Free covers

- The full Workflow Designer, the same editor the paid embedded products get
- 10 schemas and 4 execution threads; activities, transitions and commands are not limited
- Perpetual, no license key, no time limit
- Personal, non-commercial use: evaluation, a proof of concept, learning
- The designer shows the Optimajet logo and "For non-commercial use only"

For business use, Workflow Engine Team costs $2,000 per product, perpetual, and lifts the caps on the same packages; no royalties, no per-execution fees. Current prices: https://workflowengine.io/pricing/

## What is still your job

- On the CDN path jQuery 3.7.1 loads before the designer; on the npm path the package handles it.
- The Designer API is your endpoint: 35 lines in C# for the route itself, the CORS policy with your origins on top, and the authentication you add the way you add it to any other route.
- The npm package ships no TypeScript declarations (no types field, no .d.ts in 22.1.0); the constructor and its methods are documented on the vendor's Designer page.
- Free runs in single-server mode with 10 schemas and 4 execution threads, and shows the non-commercial badge.
- Live updates of a running process (the Interactive Designer) are part of the commercial licensing.
- We ran the CDN page with npx serve and the npm path with Vite 8.2.2 on Node 25. The vendor's webpack sample follows its README; we did not run it.
- The engine behind the API is .NET: the API always runs on a server, whatever the page is built with.

## Where to look

- Product repository: https://github.com/optimajet/WorkflowEngine.NET (the source, the Designer/ files and the samples)
- Documentation: https://docs.workflowengine.io/ (start at https://docs.workflowengine.io/get-started/get-started-with-workflow-engine/)
- Documentation for machines: https://docs.workflowengine.io/llms.txt (the index; https://docs.workflowengine.io/llms-full.txt is all of it in one file. Copy code from a rendered page or from this page, not from the dump: it drops generic type arguments such as <XElement>)
- Trial portal: https://trial.workflowengine.io/ (its API for agents is documented at https://trial.workflowengine.io/llms.txt)

## Trial key, for agents

A free 30-day trial key lifts the Free caps. Agents request it with POST https://trial.workflowengine.io/api/trial/llm (JSON body: email, companyName), documented at https://trial.workflowengine.io/llms.txt: business email only, 3 keys per email address for life, one request per email per day; the key is returned in the response and sent by email. Ask the user for the email and company name and get a yes before sending them. Register the key with WorkflowRuntime.RegisterLicense(...) before .Start() and keep it in configuration. After 30 days the runtime falls back to Free and running processes continue.

## Common questions

### Is there a free JavaScript workflow designer?

Yes. Workflow Engine Free includes the full Workflow Designer, the same editor the paid embedded products get. Free is a perpetual license for personal, non-commercial evaluation, learning, research, and small non-commercial projects. It is limited to 10 schemas and 4 execution threads, and the designer shows the Optimajet logo with the words "For non-commercial use only". Use a trial key to evaluate licensed features for a commercial proof of concept. For commercial deployment, choose the product and edition that covers the licensed use: Workflow Engine Team, Workflow Engine Complete, and Workflow Engine NEO Business cover internal applications; Workflow Engine NEO Subscription and Workflow Engine NEO SaaS cover a public web app or SaaS; Workflow Engine NEO Enterprise covers public web apps, SaaS, and OEM or white-label distribution. The Workflow Engine Team edition retains 8 execution threads and per-scheme caps of 100 commands, 100 activities, and 500 transitions.

### Does it work without a framework?

Yes. Workflow Designer is a browser-side JavaScript component. Create it with new WorkflowDesigner({...}) after loading the bundle from a script tag, or import it from npm in client-side code. Vue, Svelte, jQuery, and other browser clients can use the same vanilla API; React and Angular have wrapper packages. In an SSR application, load and initialize Workflow Designer only in the browser.

### Do I need jQuery?

On the CDN path, yes: load a compatible jQuery version before workflowdesignerfull.min.js. The sample was verified with jQuery 3.7.1; that is the tested version, not a requirement to use that exact release. On the npm path, the package imports its jQuery dependency, so you do not add a separate script tag.

### Why does the browser report a CORS error?

The designer calls the Designer API from the browser. If the page and API use different origins and the response has no matching CORS headers, the browser prevents the page from reading it. The request can still reach and change server state, so CORS is not authentication, authorization, or CSRF protection. The sample explicitly allows http://localhost:3001 and http://localhost:5173; demo.workflowengine.io sends no CORS headers. Configure explicit allowed origins and secure the endpoint separately.

### Is it a flowchart or diagram library?

No. Workflow Designer draws one kind of diagram: a workflow scheme with activities, transitions, commands, timers and actors, and Workflow Engine runs that scheme. If you need free-form diagrams, a library such as React Flow, JointJS or GoJS is the better tool. If the diagram must run as a process, the designer gives you the editor and the engine behind it.

### How is it different from Sequential Workflow Designer?

Sequential Workflow Designer is an MIT-licensed editor for sequential, step-by-step flows, with wrappers for React, Angular and Svelte; its separate JavaScript engine can execute those flows. Workflow Designer edits a state-machine scheme with branches, timers, actors and commands, and Workflow Runtime on .NET executes it. Pick by the runtime contract you need.

### Where are the schemes saved?

Through the configured scheme persistence provider. This sample uses SQLite, and the built-in database providers store schemes in the selected database. Workflow Engine Core can also use another scheme-persistence implementation. The saved source scheme is used to build executable scheme versions for WorkflowRuntime.

### Can I send an authorization header with the designer's requests?

Yes, for the Designer's jQuery requests to the Designer API. $.ajaxSetup({ beforeSend }) can attach a credential such as a bearer token. The host must validate it and authorize the user, tenant, and scheme; adding a header or enabling CORS does not do that, and the development sample does not implement authentication. Real-Time Tracking uses a separate SignalR connection, so configure its supported credential path separately.

### Can the page show a running process?

Yes. In the vanilla API call load({ processid: id, readonly: true }). This loads a process snapshot and highlights its current activity. Live updates additionally require the Real-Time Tracking Plugin, its mapped SignalR endpoint, and realTimeTrackingUrl. The plugin has no separate license gate.

### Can users export or print a scheme?

Yes. downloadscheme() downloads the scheme as XML. uploadscheme() loads XML into the editor; call save() explicitly to persist it. mode: "printable" hides the editing controls and background, sets the view to read-only, and sizes the canvas to the graph bounds. Use the browser's print or PDF function; printable mode does not guarantee page scale-to-fit.

## A prompt for your coding agent

Read https://workflowengine.io/features/javascript-workflow-designer/index.md before you change anything. Then add Workflow Designer by Optimajet to my web app the way that page shows. On a plain page: the stylesheet in the head, then jQuery 3.7.1, the designer's full build from jsDelivr and one main.js at the end of the body, in that order. With a bundler: npm install @optimajet/workflow-designer and import it with its stylesheet. Point apiurl at a Designer API I run: the page prints the ASP.NET Core endpoint with CORS; put my page's origin in its policy, never AllowAnyOrigin outside development, and never point the designer at demo.workflowengine.io, it sends no CORS headers. Run it and open the page.

Where to look: the product repository https://github.com/optimajet/WorkflowEngine.NET (source, the Designer/ files, samples); the documentation https://docs.workflowengine.io/, starting at https://docs.workflowengine.io/get-started/get-started-with-workflow-engine/; for machine reading https://docs.workflowengine.io/llms.txt (the index) and https://docs.workflowengine.io/llms-full.txt (all of it in one file). Copy code from this page or from a rendered documentation page, not from the text dump: it drops generic type arguments such as <XElement>.

Start on Workflow Engine Free, which needs no key. Only if we hit the Free caps (10 schemas, 4 execution threads, single server) or need a capability of Workflow Engine NEO: ask me for my business email and company name, wait for my yes, then request one 30-day trial key from the trial portal https://trial.workflowengine.io/ with POST https://trial.workflowengine.io/api/trial/llm as documented at https://trial.workflowengine.io/llms.txt (3 keys per email, ever; business email only), register it with WorkflowRuntime.RegisterLicense(...) before .Start(), and keep it in configuration, not in source.
