Skip to main content
Nodes are the fundamental building blocks of AutoMFlows workflows. Each node represents a discrete operation, from browser interactions to API calls to data manipulation.

Node Categories

AutoMFlows provides 70+ built-in node types organized into categories:

Browser

Start, Open Browser, Navigation, Context Manipulation

Interaction

Action (click, hover, drag), Type, Keyboard, Scroll

Data

Element Query, Data Extractor, Smart Extractor, Screenshot

Form

Form Input (select, check, upload), Storage, Dialog, Download, Iframe

Verification

Verify (browser, API, database)

Logic

JavaScript Code, Loop, Wait

Value

Int Value, String Value, Boolean Value, Input Value

API

API Request, API cURL

Config

Load Config File, Select Config File

Database

Connect, Disconnect, Query, Transactions

Notification

Email, Slack, Webhook

CSV

Read, Write, Append

Node Structure

Every node follows the same base structure:
// shared/src/types.ts:79
export interface BaseNode {
  id: string;                           // Unique identifier (auto-generated)
  type: NodeType | string;              // Node type (enum or plugin type)
  position: { x: number; y: number };   // Canvas coordinates
  data: NodeData | Record<string, any>; // Type-specific configuration
}

Node Handler Interface

Each node type has a handler that implements the execution logic:
// backend/src/nodes/base.ts:4
export interface NodeHandler {
  execute(node: BaseNode, context: ContextManager): Promise<void>;
}
Handlers receive:
  • node: The node configuration with all properties
  • context: The execution context containing page, browser, data, and variables

Browser Nodes

Start Node

Every workflow begins with a Start node. It configures global execution settings:
export interface StartNodeData {
  label?: string;
  recordSession?: boolean;           // Record video of browser session
  screenshotAllNodes?: boolean;      // Take screenshots on all nodes
  screenshotTiming?: 'pre' | 'post' | 'both';
  snapshotAllNodes?: boolean;        // Capture accessibility snapshots
  snapshotTiming?: 'pre' | 'post' | 'both';
  slowMo?: number;                   // Delay between nodes (ms)
  scrollThenAction?: boolean;        // Smooth scroll before UI interactions
}
The Start node is special—it doesn’t execute any action but configures the execution environment for all subsequent nodes.

Open Browser Node

Launches a browser instance using Playwright:
export interface OpenBrowserNodeData {
  headless?: boolean;                // Run without UI (default: false)
  viewportWidth?: number;            // Viewport width in pixels
  viewportHeight?: number;           // Viewport height in pixels
  maxWindow?: boolean;               // Maximize window (default: true)
  browser?: 'chromium' | 'firefox' | 'webkit';
  capabilities?: Record<string, any>;  // Playwright context options
  launchOptions?: Record<string, any>; // Playwright launch options
  stealthMode?: boolean;             // Enable stealth mode to avoid detection
  jsScript?: string;                 // JavaScript to inject on all pages
}
Implementation: backend/src/nodes/browser.ts:13
{
  "type": "openBrowser",
  "data": {
    "headless": false,
    "viewportWidth": 1920,
    "viewportHeight": 1080,
    "browser": "chromium",
    "stealthMode": true,
    "capabilities": {
      "locale": "en-US",
      "timezoneId": "America/New_York",
      "geolocation": { "latitude": 40.7128, "longitude": -74.0060 },
      "permissions": ["geolocation"]
    },
    "jsScript": "Object.defineProperty(navigator, 'webdriver', {get: () => false});"
  }
}
Handles page navigation and tab management:
export interface NavigationNodeData {
  action: 'navigate' | 'goBack' | 'goForward' | 'reload' | 'newTab' | 'switchTab' | 'closeTab';
  url?: string;                      // For navigate/newTab
  waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
  referer?: string;                  // Custom referer header
  tabIndex?: number;                 // For switchTab/closeTab
  urlPattern?: string;               // For switchTab by URL
  contextKey?: string;               // Store page reference
  timeout?: number;
  failSilently?: boolean;
  // Wait conditions and retry config...
}
Implementation: backend/src/nodes/browser.ts:63

Interaction Nodes

Action Node

Unified handler for mouse interactions:
export interface ActionNodeData {
  action: 'click' | 'doubleClick' | 'rightClick' | 'hover' | 'dragAndDrop';
  selector: string;
  selectorType?: SelectorType;
  selectorModifiers?: SelectorModifiers;
  // Action-specific
  button?: 'left' | 'right' | 'middle';
  delay?: number;                    // For hover/doubleClick
  targetSelector?: string;           // For dragAndDrop
  targetX?: number;                  // For dragAndDrop coordinates
  targetY?: number;
  timeout?: number;
  failSilently?: boolean;
  // Wait conditions and retry config...
}
Implementation: backend/src/nodes/handlers/action.ts:9
1

Click

Clicks on an element. Supports left, right, middle mouse buttons.
2

Double Click

Performs double-click. Optional delay between clicks.
3

Right Click

Opens context menu on element.
4

Hover

Moves mouse over element. Useful for dropdown menus.
5

Drag and Drop

Drags element to target selector or coordinates.

Type Node

Enters text into input fields:
export interface TypeNodeData {
  selector: string;
  selectorType?: SelectorType;
  text: string;                      // Supports ${data.key} interpolation
  inputMethod?: 'fill' | 'type' | 'pressSequentially' | 'append' | 'prepend' | 'direct';
  delay?: number;                    // Keystroke delay for type method
  clearFirst?: boolean;              // Clear field before typing
  timeout?: number;
  // Wait conditions and retry config...
}
Implementation: backend/src/nodes/handlers/type.ts
  • fill: Fast, sets value directly (bypasses events)
  • type: Simulates typing with keyboard events
  • pressSequentially: Types character by character with delay
  • append: Adds text to end of existing value
  • prepend: Adds text to beginning of existing value
  • direct: Sets value property directly (no events)

Form Input Node

Handles form-specific interactions:
export interface FormInputNodeData {
  action: 'select' | 'check' | 'uncheck' | 'upload';
  selector: string;
  // Select-specific
  values?: string | string[];        // Options to select
  selectBy?: 'value' | 'label' | 'index';
  multiple?: boolean;                // Multiple selection
  // Upload-specific
  filePaths?: string | string[];     // Files to upload
  // Check/uncheck-specific
  force?: boolean;                   // Force action even if disabled
  timeout?: number;
  // Wait conditions and retry config...
}
Implementation: backend/src/nodes/handlers/formInput.ts

Data Extraction Nodes

Element Query Node

Queries element properties:
export interface ElementQueryNodeData {
  action: 'getText' | 'getAttribute' | 'getCount' | 'isVisible' | 'isEnabled' | 'isChecked' | 'getBoundingBox' | 'getAllText';
  selector: string;
  selectorType?: SelectorType;
  attributeName?: string;            // For getAttribute
  outputVariable?: string;           // Store result (default varies by action)
  timeout?: number;
  // Wait conditions and retry config...
}
Implementation: backend/src/nodes/handlers/elementQuery.ts Output variables:
  • getText: Stores in data.elementText
  • getAttribute: Stores in data.attributeValue
  • getCount: Stores in data.elementCount
  • isVisible: Stores in data.isVisible
  • getAllText: Stores array in data.allElementText

Data Extractor Node

Extracts structured data from multiple elements:
export interface DataExtractorNodeData {
  containerSelector: string;         // Parent container
  containerSelectorType?: SelectorType;
  fields: DataExtractorFieldDefinition[];
  outputVariable?: string;           // Store results (default: 'extractedData')
  limit?: number;                    // Max items to extract
  timeout?: number;
  saveToCSV?: boolean;               // Save to CSV file
  csvFilePath?: string;
  csvDelimiter?: string;
}

export interface DataExtractorFieldDefinition {
  name: string;                      // Field name in output
  selector: string;                  // Relative to container
  selectorType?: SelectorType;
  extract: 'text' | 'attribute' | 'innerHTML';
  attribute?: string;                // If extract='attribute'
}
Implementation: backend/src/nodes/handlers/dataExtractor.ts
{
  "type": "dataExtractor",
  "data": {
    "containerSelector": ".product-card",
    "containerSelectorType": "css",
    "fields": [
      {
        "name": "title",
        "selector": "h3.product-title",
        "selectorType": "css",
        "extract": "text"
      },
      {
        "name": "price",
        "selector": ".price",
        "selectorType": "css",
        "extract": "text"
      },
      {
        "name": "url",
        "selector": "a",
        "selectorType": "css",
        "extract": "attribute",
        "attribute": "href"
      }
    ],
    "outputVariable": "products",
    "limit": 10,
    "saveToCSV": true,
    "csvFilePath": "./output/products.csv"
  }
}
Stores array in data.products:
[
  { "title": "Product 1", "price": "$19.99", "url": "/product/1" },
  { "title": "Product 2", "price": "$29.99", "url": "/product/2" }
]

Smart Extractor Node

Automatic extraction patterns:
export interface SmartExtractorNodeData {
  mode: 'allLinks' | 'allImages' | 'tables' | 'repeatedItems';
  tableIndex?: number;               // For 'tables' mode
  outputVariable?: string;           // Store results
  includeMetadata?: boolean;         // Include element metadata
  limit?: number;
  timeout?: number;
}
Implementation: backend/src/nodes/handlers/smartExtractor.ts

Logic Nodes

JavaScript Code Node

Executes arbitrary JavaScript in the browser or Node.js context:
export interface JavaScriptCodeNodeData {
  code: string;                      // JavaScript code to execute
  failSilently?: boolean;
}
Implementation: backend/src/nodes/logic.ts
JavaScript Code nodes execute server-side with full access to the execution context. Only use in trusted environments.
// Available in code execution scope:
// - context: ContextManager instance
// - page: Playwright Page instance
// - browser: Playwright Browser instance
// - data: context.getAllData()
// - variables: context.getAllVariables()

// Example: Custom data manipulation
const products = data.extractedData;
const totalPrice = products.reduce((sum, p) => {
  const price = parseFloat(p.price.replace('$', ''));
  return sum + price;
}, 0);

context.setData('totalPrice', totalPrice);

Loop Node

Iterates over arrays or conditions:
export interface LoopNodeData {
  mode: 'forEach' | 'doWhile';
  failSilently?: boolean;
  
  // forEach mode
  arrayVariable?: string;            // e.g., "products" for data.products
  
  // doWhile mode
  condition?: SwitchCondition;
  updateStep?: string;               // JavaScript code to run each iteration
  maxIterations?: number;            // Safety limit (default: 1000)
}
Implementation: backend/src/nodes/logic.ts
During loop execution, these variables are available:
// forEach mode
data.loopIteration      // Current iteration index (0-based)
data.loopItem          // Current array item
data.loopArray         // Full array being iterated

// doWhile mode
data.loopIteration     // Current iteration count

Wait Node

Pauses execution based on conditions:
export interface WaitNodeData {
  waitType: 'timeout' | 'selector' | 'url' | 'condition' | 'api-response';
  value: number | string;            // Timeout ms, selector, URL, JS condition
  selectorType?: SelectorType;
  timeout?: number;
  pause?: boolean;                   // Pause execution (for debugging)
  // API response wait config
  apiWaitConfig?: {
    contextKey: string;              // Which API response to check
    checkType: 'status' | 'header' | 'body-path' | 'body-value';
    path?: string;
    expectedValue?: any;
    matchType?: MatchType;
  };
  // Retry config...
}
Implementation: backend/src/nodes/handlers/wait.ts

API Nodes

API Request Node

Makes HTTP requests:
export interface ApiRequestNodeData {
  method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
  url: string;                       // Supports ${data.key} interpolation
  headers?: Record<string, string>;
  body?: string;
  bodyType?: 'json' | 'form-data' | 'raw' | 'url-encoded';
  formFields?: Array<{ key: string; value: string; type: 'text' }>;
  formFiles?: Array<{ key: string; filePath: string }>;
  timeout?: number;
  contextKey?: string;               // Store response (default: 'apiResponse')
  failSilently?: boolean;
  // Retry config with API-specific conditions...
}
Implementation: backend/src/nodes/api.ts Response structure:
data.apiResponse = {
  status: 200,
  statusText: 'OK',
  headers: { 'content-type': 'application/json' },
  body: { /* parsed JSON or raw text */ }
}

Verification Node

Asserts conditions across multiple domains:
export interface VerifyNodeData {
  domain: 'browser' | 'api' | 'database';
  verificationType: string;          // Domain-specific types
  
  // Browser verification
  urlPattern?: string;
  expectedText?: string;
  selector?: string;
  elementCheck?: 'visible' | 'hidden' | 'exists' | 'notExists' | 'count' | 'enabled' | 'disabled';
  
  // API verification
  statusCode?: number;
  jsonPath?: string;
  headerName?: string;
  apiContextKey?: string;
  
  // Database verification
  dbContextKey?: string;
  dbVerificationType?: 'rowCount' | 'columnValue' | 'rowExists' | 'queryResult';
  columnName?: string;
  rowIndex?: number;
  
  // Common
  matchType?: 'contains' | 'equals' | 'regex' | 'startsWith' | 'endsWith';
  comparisonOperator?: 'equals' | 'greaterThan' | 'lessThan' | 'greaterThanOrEqual' | 'lessThanOrEqual';
  expectedValue?: any;
  caseSensitive?: boolean;
  timeout?: number;
  failSilently?: boolean;
}
Implementation: backend/src/nodes/handlers/verify.ts

Value Nodes

Provide static or dynamic values:
export interface IntValueNodeData {
  value: number | string;            // Number or ${data.key}
  variableName?: string;             // Store in data[variableName]
}
Value nodes are typically used with property input connections to provide dynamic values to other nodes.

Node Handler Registry

Node handlers are registered in a central map:
// backend/src/nodes/index.ts:20
const handlers: NodeHandlerMap = {
  [NodeType.START]: new StartHandler(),
  [NodeType.OPEN_BROWSER]: new OpenBrowserHandler(),
  [NodeType.TYPE]: new TypeHandler(),
  [NodeType.ACTION]: new ActionHandler(),
  // ... 60+ more handlers
};

export function getNodeHandler(nodeType: NodeType | string): NodeHandler | undefined {
  // Check built-in handlers first
  if (Object.values(NodeType).includes(nodeType as NodeType)) {
    return handlers[nodeType as NodeType];
  }
  
  // Check plugin registry for custom types
  return pluginRegistry.getHandler(nodeType);
}

Property Input Resolution

Before node execution, property inputs are resolved:
// backend/src/engine/executor/resolvePropertyInputs.ts
export async function resolvePropertyInputs(
  node: BaseNode,
  context: ContextManager
): Promise<BaseNode> {
  const data = node.data as any;
  if (!data._inputConnections) return node;
  
  // Resolve each connected property
  for (const [propertyName, connection] of Object.entries(data._inputConnections)) {
    const sourceValue = context.getData(`${connection.sourceNodeId}_output`);
    if (sourceValue !== undefined) {
      data[propertyName] = sourceValue;
    }
  }
  
  return { ...node, data };
}
This allows nodes to receive dynamic values from upstream nodes’ outputs.

Build docs developers (and LLMs) love