Browser Provider
The Browser Provider allows you to automate web browser interactions for testing and scraping purposes.
This provider uses Playwright to control a headless Chrome browser, enabling you to navigate web pages, interact with elements, and extract data.
Prerequisites​
Playwright is a peer dependency of promptfoo, so you will need to install it separately:
npm install playwright @playwright/browser-chromium playwright-extra puppeteer-extra-plugin-stealth
Configuration​
To use the Headless Browser Provider, set the provider id
to browser
and provide a configuration object with a series of steps to execute.
providers:
- id: browser
config:
steps:
- action: navigate
args:
url: 'https://example.com'
- action: type
args:
selector: '#search-input'
text: '{{prompt}}'
- action: click
args:
selector: '#search-button'
- action: extract
args:
selector: '#results'
name: searchResults
transformResponse: 'data.searchResults'
Supported Actions​
The Headless Browser Provider supports the following actions:
navigate
: Go to a specified URLclick
: Click on an elementtype
: Enter text into an input fieldscreenshot
: Take a screenshot of the pageextract
: Extract text content from an elementwait
: Wait for a specified amount of timewaitForNewChildren
: Wait for new children of an element
Action Details​
navigate​
url
: The URL to navigate to
click​
selector
: The CSS selector of the element to clickoptional
: If true, then don't throw an error if the selector doesn't exist
extract​
selector
: The CSS selector of the element to extract text from
screenshot​
filename
: The filename to save the screenshot to
type​
selector
: The CSS selector of the input elementtext
: The text to type into the input
Special characters can be sent using the following placeholders:
<enter>
<tab>
<escape>
wait​
ms
: The number of milliseconds to wait
waitForNewChildren​
parentSelector
: The CSS selector of the parent element to wait for new children ofdelay
: The number of milliseconds to wait before checking for new childrentimeout
: The maximum number of milliseconds to wait for new children
Response Parsing​
Use the transformResponse
config option to extract specific data from the results. The parser receives an object with two properties:
extracted
: An object containing named results fromextract
actionsfinalHtml
: The final HTML content of the page after all actions are completed
Variables and Templating​
You can use Nunjucks templating in your configuration, including the {{prompt}}
variable and any other variables passed in the test context.
providers:
- id: browser
config:
steps:
- action: navigate
args:
url: 'https://example.com/search?q={{prompt}}'
- action: extract
args:
selector: '#first-result'
name: topResult
transformResponse: 'extracted.topResult'
tests:
- vars:
prompt: 'What is the capital of France?'
Using as a Library​
If you are using promptfoo as a node library, you can provide the equivalent provider config:
{
// ...
providers: [{
id: 'browser',
config: {
steps: [
{ action: 'navigate', args: { url: 'https://example.com' } },
{ action: 'type', args: { selector: '#search', text: '{{prompt}}' } },
{ action: 'click', args: { selector: '#submit' } },
{ action: 'extract', args: { selector: '#results' }, name: 'searchResults' }
],
transformResponse: (extracted, finalHtml) => extracted.searchResults,
}
}],
}
Reference​
Supported config options:
Option | Type | Description |
---|---|---|
headless | boolean | Whether to run the browser in headless mode. Defaults to true . |
cookies | string | { name: string; value: string; domain?: string; path?: string; }[] | A string or array of cookies to set on the browser |
transformResponse | string | Function | A function or string representation of a function to parse the response. Receives an object with extracted and finalHtml parameters and should return a ProviderResponse |
steps | BrowserAction[] | An array of actions to perform in the browser |
timeoutMs | number | The maximum time in milliseconds to wait for the browser operations to complete |
Note: All string values in the config support Nunjucks templating. This means you can use the {{prompt}}
variable or any other variables passed in the test context.
Supported Browser Actions​
The steps
array in the configuration can include the following actions:
Action | Description | Required Args | Optional Args |
---|---|---|---|
navigate | Navigate to a specified URL | url : string | |
click | Click on an element | selector : string | |
extract | Extract text content from an element | selector : string, name : string | |
screenshot | Take a screenshot of the page | path : string | fullPage : boolean |
type | Type text into an input field | selector : string, text : string | |
wait | Wait for a specified amount of time | ms : number | |
waitForNewChildren | Wait for new child elements to appear under a parent | parentSelector : string | delay : number, timeout : number |
Each action in the steps
array should be an object with the following structure:
{
action: string;
args: {
[key: string]: any;
};
name?: string;
}
Each step in the steps
array should have the following structure:
action
: Specifies the type of action to perform (e.g., 'navigate', 'click', 'type').args
: Contains the required and optional arguments for the action.name
(optional): Used to name extracted content in the 'extract' action.
Steps are executed sequentially, enabling complex web interactions.
All string values in args
support Nunjucks templating, allowing use of variables like {{prompt}}
.
Testing Streamlit applications​
Streamlit applications follow a common pattern where data-testid
attributes are used to identify elements.
Here's an example configuration:
providers:
- id: browser
config:
headless: true # set to false to see the browser
steps:
# Load the page - make sure you get the full URL if it's in an iframe!
- action: navigate
args:
url: 'https://doc-chat-llm.streamlit.app/~/+/'
# Enter the message and press enter
- action: type
args:
selector: 'textarea'
text: '{{prompt}} <enter>'
# Wait for the response
- action: wait
args:
ms: 5000
# Read the response
- action: extract
args:
selector: 'div.stChatMessage:last-of-type'
name: response
transformResponse: 'extracted.response'
Troubleshooting​
Iframes​
If you are using a selector to interact with the page and it keeps timing out, it could be because the element is inside an iframe.
If this is the case, try loading the iframe contents directly using the navigate
action.
Viewing the browser​
If you want to view the browser as it runs, you can set the headless
option to false
in the config.
providers:
- id: browser
config:
headless: false
Debugging​
If you are having trouble getting your tests to run, set headless
to false
and the browser will open. You can then see what is happening in the browser console.
Additionally, setting the LOG_LEVEL=debug
environment variable will print debug information to the console during your evaluation.