Skip to main content

Configuration

Prowl configuration lives at .prowl/config.yml. All options with their defaults:

{{VAR}} interpolation

String values in config.yml support {{VAR}} placeholders. As of 0.1.8 they are resolved before the config is validated — from process.env, with the config-directory .env filling in any missing keys (without overriding what is already in the environment). See Variables → Variables in config.yml.

# Execution target. Defaults to the web target; existing web configs work unchanged.
target:
type: "web" # "web" (default) | "macos" | "android" | "ios" (native ones experimental)
url: "http://localhost:3000" # Required for the web target
# Native targets set `app` instead of `url` (see the notes below the table):
# app: "com.example.App" # macos: bundle id or .app path
# # android: package name or .apk path
# # ios: bundle id or built .app path
# deviceSerial: "emulator-5554" # android only; required with several devices attached
# udid: "ABCD-1234" # ios only; required with several simulators booted
# coldStart: false # android (`pm clear`) / ios (uninstall+reinstall) only

# Browser settings
browser:
headless: true # false = show the browser window
slowMo: 0 # ms delay between actions (debugging)
timeout: 30000 # default page operation timeout
engine: "chromium" # chromium | firefox | webkit
channel: null # chrome, msedge, etc.
viewport: # or preset: "mobile" | "tablet" | "desktop"
width: 1280
height: 720

# What gets saved per run
artifacts:
screenshots: "on-failure" # "on-failure" or "all"
networkHar: false # save network activity as HAR
console: true # save browser console output
junit: false # generate JUnit XML report

# Hunt-level assertions (applied to every hunt)
assertions:
noConsoleErrors: true # fail on console.error
noNetworkErrors: true # fail on HTTP >= 400
maxTotalTimeMs: 30000 # max total time for all steps
networkIgnorePatterns: [] # URL substrings to ignore

# Safety guardrails
guardrails:
maxSteps: 50 # max steps per hunt
allowedDomains: # only navigate to these domains
- "localhost"
- "127.0.0.1"
- "0.0.0.0"
forbiddenSelectors: # selectors that steps cannot use
- "[data-danger]"
- ".delete-btn"
allowedApps: [] # native targets only: which app(s) a hunt may drive;
# empty = allow the target app (analog of allowedDomains)

# Auth state from `prowl login`
auth:
storageStatePath: ".prowl/auth-state.json"

# Run history retention
history:
maxRuns: 100 # keep the last N runs per hunt

Section Reference

target

The target block carries a discriminant, type, that selects the execution target. It is optional and defaults to "web", so existing target: { url } configs are unchanged.

OptionTypeDefaultDescription
type"web" | "macos" | "android" | "ios""web"Execution target. "web" drives a browser; the native targets (macos, android, ios) are experimental
urlstring(required for web)Base URL for all relative navigation. Web target only — not accepted on native targets
appstring(required for native)The target app. macos: bundle id or absolute .app path. android: package name or .apk path. ios: bundle id or built .app path. Not accepted on web
deviceSerialstringandroid only. The adb serial (e.g. emulator-5554); required only when several devices are attached
udidstringios only. The simulator UDID; required only when several simulators are booted
coldStartbooleanfalseandroid/ios only. A deterministic fresh start — Android runs pm clear; iOS does uninstall+reinstall (needs the .app path)
note

The native targets are experimental (shipped in Prowl 0.1.5). Each has its own selector dialect, step-compatibility matrix, and setup:

  • Android Targetadb, the on-device appium-uiautomator2-server agent, deviceSerial / coldStart.
  • iOS Simulator Target — Xcode, the WebDriverAgent build, udid / coldStart (simulators only).
  • macOS Target — the Accessibility API and permission setup.

browser

OptionTypeDefaultDescription
headlessbooleantrueRun browser in headless mode
slowMonumber0Milliseconds to wait between each action
timeoutnumber30000Default timeout for page operations
engine"chromium" | "firefox" | "webkit""chromium"Browser engine to use
channelstring | nullnullBrowser channel (e.g. "chrome", "msedge")
viewportobject | string{ width: 1280, height: 720 }Viewport size or preset ("mobile", "tablet", "desktop")

artifacts

OptionTypeDefaultDescription
screenshots"on-failure" | "all""on-failure"When to capture screenshots
networkHarbooleanfalseSave network activity as HAR file
consolebooleantrueSave browser console output
junitbooleanfalseGenerate JUnit XML report

assertions

OptionTypeDefaultDescription
noConsoleErrorsbooleantrueFail hunts on console.error
noNetworkErrorsbooleantrueFail hunts on HTTP >= 400
maxTotalTimeMsnumber30000Max total execution time in ms
networkIgnorePatternsstring[][]URL substrings to ignore for network error checks

guardrails

OptionTypeDefaultDescription
maxStepsnumber50Maximum steps per hunt
allowedDomainsstring[]["localhost", "127.0.0.1", "0.0.0.0"]Domains the browser can navigate to (web target)
allowedAppsstring[][]Which app(s) a native target (macOS, Android, iOS) may drive; empty allows the target app. Entries are bundle ids, package IDs, or .app/.apk paths. Native analog of allowedDomains
forbiddenSelectorsstring[]["[data-danger]", ".delete-btn"]Selectors that steps cannot target
warning

forbiddenSelectors and assertions.networkIgnorePatterns use case-sensitive substring matching (includes()). A pattern of "Delete" matches "Delete History", but "delete" does not — and ".delete-btn" also matches ".undelete-btn" because the substring is present. Prefer exact-enough patterns over broad fragments.

allowedDomains is enforced only for http: and https: navigations. The about: and data: protocols (for example about:blank) bypass the allowlist by design, so hunts can interact with browser-internal pages.

auth

OptionTypeDefaultDescription
storageStatePathstring".prowl/auth-state.json"Path to saved auth state from prowl login

history

Every prowl run and prowl ci appends an entry to .prowl/history.json (hunt name, status, start time, duration, and run directory). Retention is capped per hunt — once a hunt exceeds the cap, its oldest entries are dropped on the next write; other hunts are unaffected.

OptionTypeDefaultDescription
maxRunsnumber100Number of runs to keep per hunt

Inspect history with prowl history <hunt-name> (add --json for machine-readable output, --limit <n> to change the slice — default 20):

prowl history smoke-test
prowl history smoke-test --limit 50 --json

CLI Overrides

Several config options can be overridden from the command line:

prowl run <hunt> --headed          # Override headless: false
prowl run <hunt> --trace # Capture Playwright trace
prowl run <hunt> --slow-mo 500 # Override slowMo
prowl run <hunt> --url <override> # Override target.url
prowl run <hunt> --config <path> # Use different config file
prowl run <hunt> --browser chromium # Override browser engine
prowl run <hunt> --channel chrome # Override browser channel
prowl run <hunt> --viewport 1920x1080 # Override viewport size
prowl run <hunt> --include-tags smoke # Only run hunts with tag
prowl run <hunt> --exclude-tags slow # Skip hunts with tag
prowl run <hunt> --json # Machine-readable JSON output
prowl run <hunt> --junit # Generate JUnit XML report

Was this page helpful?