prompt
cy.prompt is a Cypress command that uses AI to convert natural language test steps into executable Cypress tests. You can view the generated Cypress code at any time using the Code button in the Command Log, giving you full visibility into what commands were created from your prompts.
cy.prompt supports two flexible workflows:
- Generate and export - Use AI to quickly create tests, review the generated code, and save it to your test files for predictable, version-controlled tests
- Continuous self-healing - Keep
cy.promptrunning in your tests to automatically adapt when your app changes
You can choose the workflow that fits your project's needs.
cy.prompt- How it works — understand the AI-powered process behind
cy.prompt - Choosing your workflow — decide between one-time generation or continuous self-healing
- How to write effective prompts — craft clear, reliable natural language steps
- What you can do — explore supported actions and capabilities
- Viewing and exporting generated code — see the Cypress code generated from your prompts and save it to your files
- Setup — enable the command and configure authentication
The demo above shows cy.prompt in action with Cypress Studio.
Syntax
interface PromptCommand {
(
steps: string[], // array of steps to execute
options?: {
placeholders?: { [key: string]: string } // redacted dynamic inputs that are ignored for cache identity
}
): void
}
Arguments
steps (String[])
An array of steps to execute.
options (Object)
Pass in an options object to cy.prompt().
| Option | Default | Description |
|---|---|---|
placeholders | {} | Dynamic or sensitive values that enable high performance caching. See placeholders for more details. |
Yields
cy.prompt() yields the value yielded by the last Cypress command executed in the prompt. In most cases, this will be an element, but it depends on the last command executed in the prompt.
cy.prompt([
// Executes cy.visit('/user-management')
'visit https://cloud.cypress.io/login',
// Executes cy.get('#login-button').click()
'click the login button',
]) // yields <button> since .click() yields the same subject it was originally given.
.closest('form')
.submit()
In the example below, the last command executed in the prompt is .visit(), so the yielded value is the window object.
cy.prompt([
// Executes cy.visit('/user-management')
'visit https://cloud.cypress.io/login',
]) // yields window object since .visit() yields window object
.its('navigator.language')
.should('equal', 'en-US')
How it works
When you call cy.prompt, Cypress performs a multi-step process:
-
Interpret prompt: Each string in your
steps[]array is parsed using an AI model. Cypress maps the intent (e.g. 'click the login button') to Cypress commands (cy.get(...).click()) and target elements. -
Generate selectors: Cypress evaluates your app's DOM and picks a selector based on priority rules (unique identifiers that are likely to be stable).
-
Generate Cypress code: Commands are generated and executed in sequence. The Command Log shows both your natural language step and the commands Cypress ran. You can view the complete generated code at any time using the Code button in the Command Log.
-
Cache for speed: Generated code is cached. Re-running the same test does not re-call the AI model unless the prompt or DOM changes in a way that invalidates the cached code.
-
Self-heal if needed: If cached selectors fail (element renamed, attributes changed, etc.), Cypress regenerates code for that step. This 'self-healing' happens automatically on future attempts.
-
Choose your workflow:
cy.promptsupports two flexible workflows depending on your project needs.- Export the code - Save generated code to your test file for predictable, version-controlled tests
- Keep it running - Let
cy.promptcontinue to self-heal and adapt to changes
Choose your workflow
cy.prompt supports two flexible workflows depending on your project needs. Both workflows give you full visibility into what code was generated, so you can always inspect and modify the results.
Workflow 1: Generate once, commit to source control
Use cy.prompt to generate tests, then export and commit the code.
Why choose this workflow?
- Predictable execution - You know exactly what code runs every time
- Fast test generation - Use AI to quickly create test skeletons
- No AI dependency - Tests run without calling the AI service
- PR review friendly - Generated code fits into existing review processes
- Stable selectors - Your app has stable, predictable elements
Example
// Generate the test
cy.prompt(
[
'visit https://cloud.cypress.io/login',
'type "[email protected]" in the email field',
'type {{password}} in the password field',
'click the login button',
'verify we are redirected to the dashboard',
],
{
placeholders: { password: 'secret123' },
}
)
After the test runs, click the Code button in the Command Log to view the generated Cypress code. This opens a dialog showing the complete Cypress commands that were generated from your natural language steps. From there, you can:
- Save to file - Replace your
cy.promptcall with the generated code directly in your test file - Copy to clipboard - Copy the code for use elsewhere
- Review and modify - Inspect the generated selectors and commands before committing
This workflow lets you use AI to quickly generate test code, then commit the exact generated code to your repository for predictable, version-controlled tests.
Workflow 2: Continuous AI-powered testing
Keep cy.prompt in your tests and let it self-heal and adapt to changes.
Why choose this workflow?
- Self-healing selectors - Tests adapt when your app changes
- Less maintenance - No need to update tests for every UI change
- Dynamic content friendly - Works well with changing data
- Smart regeneration - AI handles selector failures automatically
- Rapid iteration - Perfect for apps in active development
Example
// Let cy.prompt run on every test execution
cy.prompt([
'visit the product catalog',
'filter by category "Electronics"',
'sort by price high to low',
'verify the product count is 25',
])
Even when using cy.prompt for continuous testing, you can still view the generated code at any time. Click the Code button in the Command Log to see what Cypress generated, which is especially useful for:
- Debugging - Understanding why a test behaved a certain way
- Learning - Seeing how natural language maps to Cypress commands
- Exporting later - If you decide to switch to Workflow 1, you can export the code at any point
How to write effective prompts
Language Support: cy.prompt is optimized for English prompts and provides the most reliable results when prompts are written in English. We cannot guarantee accuracy or provide support for non-English prompts.
Prompt clarity determines reliability. Follow these rules:
- Imperative voice: Start with an action (click, type, verify).
- Use absolute URLs: Use the full URL of the page you want to visit.
- One action per step: Avoid chaining multiple actions in one string.
- Avoid ambiguity: Specify the action or element explicitly. Wrap specific text, values, or identifiers in quotes to help the AI identify them as exact matches. For example,
click the "Submit" buttonis clearer thanclick the Submit button. - Include context:
click the login button in the headeris better thanclick login button.
Example: Good vs. poor steps
// ✅ Good - clear and descriptive
cy.prompt([
'visit https://cloud.cypress.io/users/settings',
'click the "Edit Profile" button',
'type "John Doe" in the name field',
'type "[email protected]" in the email field',
'click the "Save Changes" button',
'verify the success message "Profile updated successfully" appears',
])
// ❌ Poor - vague and error-prone
cy.prompt([
'go to profile',
'click button',
'type name',
'type email',
'save',
'check success',
])
If Cypress cannot interpret a step
If Cypress cannot interpret a step, you'll see a dialog prompting you to refine your prompt. Fill out each step that needs information with a more specific prompt and click Save to update the cy.prompt code within your test file. The test will then run with the new prompt.
What you can do
Navigate to pages
'visit https://example.cypress.io'
'navigate to /login' // with baseUrl set
Interact with elements
'click the login button'
'hit the "x" button'
'expand the FAQ section'
'close the Technical Information section'
'switch to the Settings tab'
'dismiss the modal'
'double click the product image'
'right click the file item'
'type "[email protected]" in the email field'
'type {enter} in the email field'
'write "42" in the number field'
'put "No comment" in the textarea'
'fill the search input with "cypress"'
'clear the username field'
'focus on the search input'
'blur the filter input'
'select "Canada" from the country dropdown'
'pick "United States" from the list'
'choose "Newest" from the suggestions'
'check "I agree"'
'uncheck "Send me updates"'
'toggle the "Dark Mode" switch'
'submit the contact form'
'scroll the sales section into view'
'scroll to todays date in the calendar'
Verify results
'make sure the confirmation button is visible'
'verify an alert exists'
'expect the notification to contain the text "Email sent"'
'confirm that the [data-cy="result"] element has the text "Success"'
'the toast should not contain the text "Failed"'
'the current URL should be "https://cloud.cypress.io/login"'
'I expect the email field to have the value "[email protected]"'
'verify the "Remember me" input is disabled'
'the "Login" button should be enabled'
'now the product should have the class "loading"'
'assert the "I agree" checkbox is checked'
'validate that the #error-message is empty'
'the "Profile" tab should be active'
'the modal ought to be displayed'
'verify both checkboxes are checked'
'the search input should have focus'
'and "United States" is selected'
'ensure that the counter shows 5'
'verify the counter has the id "reset"'
'confirm that the code frame includes HTML "<span class="token">'
Change the viewport
'set the viewport to 400x600'
Wait
'wait 2 seconds'
'wait 500 milliseconds'
Placeholders
The caching problem
cy.prompt works by caching your prompt steps so it doesn't need to reach out to the AI every time. This makes tests run faster, but there's a challenge: any change to your prompt steps invalidates the cache, forcing a new AI call.
This becomes problematic when you have dynamic values that change each time cy.prompt is run (like timestamps, user IDs, or randomly generated data)
Without placeholders, the cache would always be invalidated because these dynamic values would be hardcoded directly in your steps.
The placeholder solution
Placeholders let you use dynamic and sensitive values while maintaining cache efficiency:
- Cache-friendly: Changes to placeholder values don't invalidate the cache
- Runtime substitution:
{{placeholder}}syntax gets replaced with actual values at execution time - Privacy-protected: Placeholder values are never sent to AI services, keeping sensitive data secure
Example usage
describe('Campaign Management', () => {
it('creates multiple campaigns with different discount percentages', () => {
const adminPassword = Cypress.env('ADMIN_PASSWORD')
const campaigns = [
{ name: 'Fall Sale', discountPct: 10 },
{ name: 'Spring Sale', discountPct: 15 },
]
// This loop demonstrates the caching benefit:
// - First iteration: AI generates and caches the code
// - Subsequent iterations: Reuse cached code with different placeholder values
campaigns.forEach((campaign) => {
const campaignName = campaign.name
const campaignDiscountPct = campaign.discountPct
cy.prompt(
[
`Visit ${Cypress.env('ADMIN_URL')}/admin/login`,
// Using {{adminPassword}} prevents this sensitive value from being sent to AI
'Type {{adminPassword}} into the password field',
'Click Sign In',
'Open the Promotions tab',
'Click to create a new campaign',
// Using {{campaignName}} and {{campaignDiscountPct}}
// allows for high performance caching with different values
'Type {{campaignName}} into the name field',
'Set discount to {{campaignDiscountPct}}% for all products',
'Save the campaign',
'Verify the campaign "{{campaignName}}" appears in the list',
],
{
placeholders: {
adminPassword,
campaignName,
campaignDiscountPct,
},
}
)
})
})
})
Viewing and exporting generated code
At any time during or after a test run, you can view the exact Cypress code that cy.prompt generated from your natural language steps. This transparency is built into every cy.prompt execution.
How to view generated code
- Run your test with
cy.promptin Cypress App - Click the "Code" button - This button appears next to each
cy.promptcommand in the Command Log

- Review the generated code - A dialog displays the complete Cypress code with all of the generated commands (e.g.,
cy.get(),cy.click(),cy.type()) and comments showing which prompt step generated each command.

What you can do with the generated code
Once you have the generated code, you can:
- Save code to your test file - Replace the
cy.promptcall with the generated Cypress commands for predictable, version-controlled tests. - Copy code to your clipboard - Use the code in other files or share it with your team.
This helps you review and modify the generated code as needed or just use it as a reference to understand what cy.prompt is doing behind the scenes.
Customizing selectors in generated code
You can customize which selectors cy.prompt uses when generating Cypress code by configuring the ElementSelector API. This lets you control which attributes Cypress prioritizes (like data-*, id, aria-label, etc.) when creating selectors, ensuring the generated code matches your project's selector strategy.
Configure the selector priority in your support file or test file:
// cypress/support/e2e.js or in your test file
Cypress.ElementSelector.defaults({
selectorPriority: [
'data-cy', // Prefer data-cy attributes
'attribute:role', // Then ARIA roles
'attribute:aria-label', // Then ARIA labels
'id', // Then IDs
'class', // Finally classes
],
})
For more examples and details, see the ElementSelector API documentation.
Setup
Enable the command
cy.prompt is experimental and may change in future releases. Enable the command in your config file:
- cypress.config.js
- cypress.config.ts
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
experimentalPromptCommand: true,
},
})
import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
experimentalPromptCommand: true,
},
})
Authentication & usage
Because cy.prompt uses AI under the hood, it needs to communicate securely with large language models to interpret your prompts. Cypress Cloud helps manage those requests, apply organization-level controls, and track usage in a way that's non-invasive. We never use your prompts to train AI models, and you can turn AI features off at any time. cy.prompt is currently available on any of our Cypress Cloud plan types.
To use cy.prompt, you must either:
- Log into Cypress Cloud
- Or run with
--recordand a valid--key. See instructions.
If you don't have a Cloud account, create a free account and gain access to a 2-week trial of all paid features.
Sign up ➜ See a demo Explore an example projectExamples
Gherkin-style tests
cy.prompt can execute Gherkin-style tests, making test automation accessible to a broader audience including product managers, QA engineers, and stakeholders who are familiar with behavior-driven development (BDD) patterns. This expands the pool of people who can write and maintain tests without requiring deep technical knowledge of Cypress APIs. This is also a great way to get started with test automation and get buy-in from stakeholders who are familiar with BDD patterns.
Benefits for Cucumber users:
- Familiar syntax: If you're already using Cucumber/Gherkin,
cy.promptaccepts the same Given/When/Then/And structure - No step definitions: Unlike traditional Cucumber, you don't need to write step definition files -
cy.promptinterprets the steps directly - Improved performance: Tests run without the overhead of Cucumber's step definition mapping
- Simplified maintenance: No need to maintain separate step definition files that can become out of sync with your tests
Gherkin example 1: Successful user registration with valid data
describe('Feature: User Registration', () => {
it('Scenario: Successful user registration with valid data', () => {
cy.prompt(
[
'Given the user is on the "/register" page',
'When the user enters "Avery Lopez" in the name field',
'And the user enters "[email protected]" in the email field',
'And the user enters {{password}} in the password field',
'And the user enters {{password}} in the confirm password field',
'And the user selects "admin" from the role dropdown',
'And the user checks the terms and conditions checkbox',
'And the user clicks the "Register User" button',
'Then the user should see a success notification',
'And the user should be added to the user list',
],
{
placeholders: {
password: Cypress.env('PASSWORD'),
},
}
)
})
})
The generated code may look like:
describe('Feature: User Registration', () => {
it('Scenario: Successful user registration with valid data', () => {
// Prompt step 1: Given the user is on the "/register" page
cy.visit('/register')
// Prompt step 2: When the user enters "Avery Lopez" in the name field
cy.get('#full-name').type('Avery Lopez')
// Prompt step 3: And the user enters "[email protected]" in the email field
cy.get('#email').type('[email protected]')
// Prompt step 4: And the user enters "password123" in the password field
cy.get('#password').type('password123')
// Prompt step 5: And the user enters "password123" in the confirm password field
cy.get('#confirm-password').type('password123')
// Prompt step 6: And the user selects "admin" from the role dropdown
cy.get('#role').select('admin')
// Prompt step 7: And the user checks the terms and conditions checkbox
cy.get('#terms').check()
// Prompt step 8: And the user clicks the "Register User" button
cy.get('#registration-form .btn-success').click()
// Prompt step 9: Then the user should see a success notification
cy.get('.success').should('be.visible')
// Prompt step 10: And the user should be added to the user list
cy.get('#user-list').should('contain', 'Avery')
})
})
Gherkin example 2: User cannot be deactivated if already inactive
describe('Feature: User Status Management', () => {
it('Scenario: User cannot be deactivated if already inactive', () => {
cy.visit('/user-management')
cy.prompt([
'Given there is an inactive user on the page',
'When the admin tries to deactivate the already inactive user',
'But the user is already in inactive status',
'Then the system should show a message that user is already inactive',
'But the user status should remain unchanged',
])
})
})
The generated code may look like:
describe('Feature: User Status Management', () => {
it('Scenario: User cannot be deactivated if already inactive', () => {
cy.visit('/user-management')
// Prompt step 1: Given there is an inactive user on the page
cy.get('#user-list .status-inactive').should('be.visible')
// Prompt step 2: When the admin tries to deactivate the already inactive user
cy.get('#user-list div:nth-child(3) > .user-actions > .btn-danger').click()
// Prompt step 3: But the user is already in inactive status
cy.get('#user-list .status-inactive').should('contain', 'inactive')
// Prompt step 4: Then the system should show a warning message
cy.get('.warning-notification').should('be.visible')
// Prompt step 5: But the user status should remain unchanged
cy.get('#user-list .status-inactive').should('contain', 'inactive')
})
})
Gherkin example 3: Admin manages user status
it('Scenario Outline: Admin manages user status', () => {
cy.visit('/users')
const Examples = [
{ status: 'pending', action: 'activates', new_status: 'active' },
{ status: 'active', action: 'deactivates', new_status: 'inactive' },
{ status: 'inactive', action: 'activates', new_status: 'active' },
]
Examples.forEach((example) => {
cy.prompt([
`Given there is a(n) ${example.status} user on the page`,
`When the admin ${example.action} the user`,
`Then the user status should change to ${example.new_status}`,
])
})
})
The commands in the generated code may look like:

Login flow
const password = Cypress.env('adminPassword')
cy.prompt(
[
'visit the login page',
'type "[email protected]" in the email field',
'type {{password}} in the password field',
'click the login button',
'verify we are redirected to the dashboard',
],
{
placeholders: { password },
}
)
E-commerce checkout
cy.prompt([
'visit https://example.com/products',
'search for "wireless headphones"',
'click on the first search result',
'click the "Add to Cart" button',
'verify the cart icon shows 1 item',
'click the cart icon',
'click the "Proceed to Checkout" button',
'fill in shipping information',
'select standard shipping',
'enter credit card details',
'click the "Place Order" button',
'verify the order confirmation page loads',
])
Search functionality
cy.prompt([
'search for "united states"',
'pick "United States" from the list',
'clear the search field',
'look for "canada"',
'choose "Canada" from the suggestions',
])
Settings configuration
cy.prompt([
'toggle on the "Enable Notifications" switch',
'verify the notification shows "Enable Notifications enabled"',
'verify the notifications toggle is enabled',
'verify the toggle switch is in the on position',
])
Dynamic testing with loops
If you need to test a loop of steps, you can use the placeholders option to pass in the dynamic values. This optimizes caching so that the prompt does not need to be called out to AI for each iteration of the loop.
const matchingSearchTerms = ['cypress', 'testing', 'automation']
const nonMatchingSearchTerms = ['cyprus', 'fuzzy', 'wrong']
matchingSearchTerms.forEach((term) => {
cy.prompt(
[
`type "{{term}}" in the search input`,
`verify the search results contain "{{term}}"`,
],
{
placeholders: {
term,
},
}
)
})
nonMatchingSearchTerms.forEach((term) => {
cy.prompt(
[
`type "{{term}}" in the search input`,
`verify the search results does not contain "{{term}}"`,
],
{
placeholders: {
term,
},
}
)
})
Cross-origin testing
cy.origin('https://cloud.cypress.io/login', () => {
cy.prompt(
[
'type "[email protected]" in the email field',
'type {{password}} in the password field',
'click the login button',
],
{
placeholders: {
password: Cypress.env('PASSWORD'),
},
}
)
})
Mixed with traditional Cypress
const electronicsCount = Cypress.env('staging') === true ? 5 : 25
// Confirm the UI works in staging environment
cy.task('seedStagingDB')
cy.visit(`${Cypress.env('stagingUrl')}/products`)
cy.prompt(
[
'filter by category "Electronics"',
'sort by price high to low',
`verify the product count is {{electronicsCount}}`,
'verify the sort indicator is "Price: High to Low"',
],
{
placeholders: {
electronicsCount,
},
}
)
// Confirm the UI works in production environment
cy.task('seedProductionDB')
cy.visit(`${Cypress.env('productionUrl')}/products`)
cy.prompt(
[
'filter by category "Electronics"',
'sort by price high to low',
`verify the product count is {{electronicsCount}}`,
'verify the sort indicator is "Price: High to Low"',
],
{
placeholders: {
electronicsCount,
},
}
)
Or to further clean up the cy.prompt call:
const electronicsCount = Cypress.env('staging') === true ? 5 : 25
const electronicsFilterPrompt = [
'filter by category "Electronics"',
'sort by price high to low',
`verify the product count is {{electronicsCount}}`,
'verify the sort indicator is "Price: High to Low"',
]
// Confirm the UI works in staging environment
cy.task('seedStagingDB')
cy.visit(`${Cypress.env('stagingUrl')}/products`)
cy.prompt(electronicsFilterPrompt, {
placeholders: {
electronicsCount,
},
})
// Confirm the UI works in production environment
cy.task('seedProductionDB')
cy.visit(`${Cypress.env('stagingUrl')}/products`)
cy.prompt(electronicsFilterPrompt, {
placeholders: {
electronicsCount,
},
})
Limitations
These apply to all cy.prompt usage unless noted otherwise.
General limitations
| Limitation | Details |
|---|---|
| Authentication | Requires Cypress Cloud account and/or valid record key |
| Test Type | E2E tests only (component testing not yet supported) |
| Browser Support | Chromium-based browsers only (Chrome, Edge, Electron) |
| Language Support | Optimized for English prompts; other languages are not guaranteed |
| Command Coverage | Not all Cypress APIs supported - see What you can do |
Experimental release limitations
The cy.prompt command is currently in experimental release. During the experimental release, there are some limitations that we intend to address in the future.
| Limitation | Details |
|---|---|
| Assertions | 'not.exist' assertions are not supported See issue |
| Multi-Element | Assertions on multiple elements are not currently supported See issue |
| Cookies/Sessions | Clearing cookies or sessions is not supported See issue |
| Scrolling | Scrolling to elements is not supported See issue |
| API Testing | API requests (e.g., cy.request() or cy.intercept()) are not supported See issue |
| DOM Support | Canvas and iframe elements are not supported. See canvas issue and iframe issue |
Pricing & usage limits
During the experimental release, access will be provided at no additional charge. Users are limited by the number of cy.prompt definitions and steps they can run per hour. This limit is higher for paid accounts and lower for free accounts. Our intention is to not limit normal usage of the feature.
Please note that pricing and usage limitations are subject to future adjustments. We commit to keeping you informed of any such changes.
There are two sets of limits: per-user hourly limits and per-prompt limits.
Per-user hourly limits
Usage limits only apply to runs that are not recording to Cypress Cloud.
User limits on projects with free accounts:
- 100 prompts per hour
- 500 prompt steps per hour
User limits on projects with paid accounts (or on free trial):
- 600 prompts per hour
- 3,000 prompt steps per hour
Per-prompt limits
- Up to 50 steps per
cy.promptcall to maintain context fidelity and produce reliable, executable commands. - During the experimental release, system-wide limits apply to the total input length processed by
cy.prompt. Very long prompts may be rejected or require splitting.
To improve reliability and performance, consider the following:
- Keep one action or assertion per step.
- Split long flows into multiple
cy.promptcalls.
Privacy & security
For detailed information about how Cypress protects your data and manages AI model security, see our Security & Compliance page.
Disabling AI features
AI capabilities, including cy.prompt, are enabled by default for all users on any Cloud plan. Organization admins and owners can enable and disable the AI capabilities for their entire organization from their organization settings. For more information, see our FAQ.
History
| Version | Changes |
|---|---|
| 15.4.0 | Introduced experimental cy.prompt command |