Skip to content

Multi Config

The multi command lets you execute multiple actions from a single YAML config file. All actions run sequentially on a single browser session, avoiding the overhead of launching a browser for each action.

Usage

wavexis multi <config.yml>

Config format

The YAML file must have an actions key containing a list of action entries. Each entry is a dict with a single key (the action type) and a dict of parameters.

actions:
  - screenshot:
      url: https://example.com
      full_page: true
  - pdf:
      url: https://example.com
      paper: a4
  - eval:
      url: https://example.com
      expression: document.title
  - dom:
      url: https://example.com
      action: get
      selector: h1
  - navigate:
      url: https://example.org
  - scrape:
      urls:
        - https://example.com
        - https://example.org
      expression: document.title

How it works

  1. wavexis parses the YAML file and validates its structure.
  2. A single browser instance is launched.
  3. Each action is dispatched to the corresponding action class (ScreenshotAction, EvalAction, etc.).
  4. Actions execute sequentially — each one completes before the next starts.
  5. Results are collected and printed. Binary results (screenshots, PDFs) show byte counts; text results show a preview.
  6. The browser is closed after all actions complete.

Watch mode

Re-execute the config automatically when the file changes. This is designed for iterative config development — edit the YAML, save, and see results immediately:

wavexis multi config.yml --watch

Output:

Watching config.yml for changes (Ctrl+C to stop)...
[14:32:05] Completed 3 actions
  Waiting for changes...
  File changed, re-running...
[14:32:18] Completed 3 actions
  Waiting for changes...

Watch mode uses file polling (1-second interval) for cross-platform compatibility. Press Ctrl+C to stop.

Dry run

Validate the config and show the planned actions without launching a browser:

wavexis multi config.yml --dry-run

Output:

Plan: 3 action(s)
  1. screenshot: https://example.com (full_page=True)
  2. eval: https://example.com — document.title
  3. pdf: https://example.com (paper=a4)

Dry run is useful for:

  • Validating config syntax — catches structural errors before running.
  • Reviewing action sequences — verify the order and parameters of actions.
  • CI validation — ensure configs are valid in pull requests without executing them.

Supported actions

Action Parameters Description
screenshot url, full_page, format, quality, selector, device Take a screenshot
pdf url, paper, landscape, margin, no_header_footer, media Generate a PDF
eval url, expression, await_promise Evaluate JavaScript
dom url, action, selector, outer, all, attribute, value DOM operations
navigate url, wait Navigate to a URL
scrape urls, expression, output_format Batch scrape multiple URLs
visual_diff url, baseline_path, selector, threshold Compare a screenshot with a baseline image
click url, selector, button, click_count, delay Click an element
type url, selector, text, delay Type text into an element
fill url, selector, value Fill an input element
select url, selector, value Select an option
hover url, selector Hover over an element
keypress url, key Press a key
right_click url, selector Right-click an element
double_click url, selector Double-click an element
drag url, from_selector, to_selector Drag element to target
tap url, selector Tap an element (touch)
scroll url, selector, x, y Scroll the page or an element
upload url, selector, file Upload a file
cookies url, action, cookie, name, domain Cookie operations
headers url, action, headers, user_agent HTTP headers and user agent
wait strategy, selector, url_pattern, timeout Wait for a condition
har url, duration Capture network traffic as HAR
emulation action, device, width, height, timezone, dark_mode, ... Device/viewport/timezone/geolocation/dark mode emulation

Note: url is optional on interaction actions. When provided, the action navigates to that URL first (a fresh page load — any state typed or clicked before is lost). Omit url to run the action on the current page.

Cookies in multi

The cookies action supports four operations: get, set, delete, clear.

Get cookies

actions:
  - cookies:
      url: https://example.com
      action: get
actions:
  - cookies:
      url: https://example.com
      action: set
      cookie:
        name: session_token
        value: abc123
        domain: .example.com
        path: /
        secure: true
        http_only: true
        same_site: Strict

Optional cookie fields: secure (bool), http_only (bool), same_site (Strict, Lax, or None).

actions:
  - cookies:
      url: https://example.com
      action: delete
      name: session_token
      domain: .example.com

Clear all cookies

actions:
  - cookies:
      url: https://example.com
      action: clear

Headers in multi

The headers action supports two operations: set-headers (set extra HTTP headers) and set-user-agent (override the User-Agent string).

Set extra HTTP headers

actions:
  - headers:
      url: https://example.com
      action: set-headers
      headers:
        X-Custom-Header: my-value
        Authorization: Bearer token123
  - screenshot:
      url: https://example.com

Headers are applied before subsequent actions in the sequence, so the screenshot will be taken with the custom headers active.

Override User-Agent

actions:
  - headers:
      url: https://example.com
      action: set-user-agent
      user_agent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)"
  - screenshot:
      url: https://example.com

Wait in multi

The wait action pauses execution until a condition is met. This is essential for pages with dynamic content that loads after navigation.

Wait strategies

Strategy Description Required params
load Wait for page load event none
domcontentloaded Wait for DOM content loaded none
networkidle Wait until network is idle none
selector Wait for a CSS selector to appear selector
url Wait for URL to match a pattern url_pattern

Examples

actions:
  - navigate:
      url: https://app.example.com
  - wait:
      strategy: selector
      selector: "#dashboard-loaded"
      timeout: 10000
  - screenshot:
      url: https://app.example.com
      full_page: true
actions:
  - click:
      url: https://app.example.com
      selector: "#load-more"
  - wait:
      strategy: networkidle
      timeout: 5000
  - scrape:
      urls:
        - https://app.example.com
      expression: "document.querySelectorAll('.item').length"

Emulation in multi

The emulation action sets device, viewport, geolocation, timezone, or dark mode before subsequent actions. This is useful for testing how a page renders under different conditions.

Device emulation

actions:
  - emulation:
      action: device
      device: iphone-15
  - screenshot:
      url: https://example.com
      full_page: true

Viewport override

actions:
  - emulation:
      action: viewport
      width: 1920
      height: 1080
  - screenshot:
      url: https://example.com

Timezone

actions:
  - emulation:
      action: timezone
      timezone: America/New_York
  - eval:
      url: https://example.com
      expression: new Date().getTimezoneOffset()

Dark mode

actions:
  - emulation:
      action: dark_mode
      dark_mode: true
  - screenshot:
      url: https://example.com

Geolocation

actions:
  - emulation:
      action: geolocation
      latitude: 37.7749
      longitude: -122.4194
      accuracy: 100
  - eval:
      url: https://example.com
      expression: navigator.geolocation

Variables

Configs support variable substitution using {{var}} syntax. Define variables in a top-level vars section and reference them in any action parameter.

User-defined variables

vars:
  target_url: https://app.example.com
  username: admin@example.com
  password: secret123

actions:
  - navigate:
      url: "{{target_url}}/login"
  - type:
      selector: "#username"
      text: "{{username}}"
  - type:
      selector: "#password"
      text: "{{password}}"
  - click:
      selector: "#submit"
  - screenshot:
      url: "{{target_url}}/dashboard"
      full_page: true

type, click and other interaction actions only get url when you want them to navigate — repeating it re-loads the page and loses the state entered by previous actions.

Environment variables

Access environment variables with {{env.KEY}}:

actions:
  - eval:
      url: "{{env.TARGET_URL}}"
      expression: document.title

For security, only variables listed in WAVEXIS_ENV_ALLOWLIST are substituted — the placeholder stays literal otherwise:

export WAVEXIS_ENV_ALLOWLIST=TARGET_URL
TARGET_URL=https://staging.example.com wavexis multi config.yml

Substitution rules

  • Variables are substituted in string values only — dicts, lists, and scalars are left as-is.
  • Unknown variables are left unchanged (e.g. {{unknown}} stays literal).
  • Missing environment variables are left unchanged.
  • Substitution is recursive — variables in nested dicts and lists are all processed.

Parallel execution

By default, actions execute sequentially. Use --parallel to run all actions concurrently on the same backend:

wavexis multi config.yml --parallel

This is useful when actions are independent (e.g. scraping multiple URLs). Results are returned in the same order as the actions in the config.

When to use parallel

  • Independent actions — scraping different URLs, taking screenshots of different pages.
  • Performance — reduce total execution time when actions don't depend on each other.

When NOT to use parallel

  • Sequential dependencies — if action B depends on action A's side effects (e.g. login then screenshot).
  • State mutations — cookies, headers, or emulation that affect subsequent actions.

Parallel with watch

wavexis multi config.yml --parallel --watch

Action caching

Cache action results to avoid re-analyzing pages when running workflows repeatedly. Useful in watch mode or CI where the same config is executed multiple times.

wavexis multi config.yml --cache-ttl 60

Cacheable actions

Action Cached
screenshot Yes
dom Yes
scrape Yes
eval Yes
cookies Yes
headers Yes
navigate No
click No
type No
pdf No
wait No
emulation No

How caching works

  • Cache is keyed by URL, action type, and a hash of action parameters.
  • TTL (time-to-live) controls how long cached results are valid.
  • On cache hit, the action is skipped and the cached result is returned.
  • Cache is in-memory per multi invocation — no persistent storage.
  • Use --cache-ttl 0 to disable caching (default).

Example: iterative development

# Cache for 120 seconds while iterating on config
wavexis multi config.yml --watch --cache-ttl 120

Each time the config changes and re-runs, cacheable actions that haven't expired will return instantly.

Validation errors

Invalid config files raise MultiConfigError with exit code 2:

  • Missing actions key
  • actions is not a list
  • Action entry has multiple keys
  • Action parameters are not a dict
  • Unknown action type

Example: login flow

A complete login flow with cookie inspection:

actions:
  - navigate:
      url: https://app.example.com/login
  - type:
      url: https://app.example.com/login
      selector: "#username"
      text: admin@example.com
  - type:
      url: https://app.example.com/login
      selector: "#password"
      text: secret123
  - click:
      url: https://app.example.com/login
      selector: "#login-button"
  - eval:
      url: https://app.example.com/dashboard
      expression: document.title
  - cookies:
      url: https://app.example.com/dashboard
      action: get
  - screenshot:
      url: https://app.example.com/dashboard
      full_page: true
wavexis multi login-flow.yml

Output:

Completed 7 actions
  Action 1: None
  Action 2: None
  Action 3: None
  Action 4: None
  Action 5: Dashboard - Example App
  Action 6: [{"name": "session", "value": "abc123", ...}]
  Action 7: 45678 bytes