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¶
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¶
- wavexis parses the YAML file and validates its structure.
- A single browser instance is launched.
- Each action is dispatched to the corresponding action class (
ScreenshotAction,EvalAction, etc.). - Actions execute sequentially — each one completes before the next starts.
- Results are collected and printed. Binary results (screenshots, PDFs) show byte counts; text results show a preview.
- 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:
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:
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 |
Take a screenshot |
pdf |
url, paper, landscape |
Generate a PDF |
eval |
url, expression, await_promise |
Evaluate JavaScript |
dom |
url, action, selector |
DOM operations |
navigate |
url |
Navigate to a URL |
scrape |
urls, expression |
Batch scrape multiple URLs |
click |
url, selector |
Click an element |
type |
url, selector, text |
Type text into an element |
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 |
emulation |
action, device, width, height, timezone, dark_mode, ... |
Device/viewport/timezone/geolocation/dark mode emulation |
Cookies in multi¶
The cookies action supports four operations: get, set, delete, clear.
Get cookies¶
Set a cookie¶
actions:
- cookies:
url: https://example.com
action: set
cookie:
name: session_token
value: abc123
domain: .example.com
path: /
Delete a cookie¶
actions:
- cookies:
url: https://example.com
action: delete
name: session_token
domain: .example.com
Clear all cookies¶
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¶
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:
url: "{{target_url}}/login"
selector: "#username"
text: "{{username}}"
- type:
url: "{{target_url}}/login"
selector: "#password"
text: "{{password}}"
- click:
url: "{{target_url}}/login"
selector: "#submit"
- screenshot:
url: "{{target_url}}/dashboard"
full_page: true
Environment variables¶
Access environment variables with {{env.KEY}}:
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:
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¶
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.
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
multiinvocation — no persistent storage. - Use
--cache-ttl 0to disable caching (default).
Example: iterative development¶
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
actionskey actionsis 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
Output: