For a same-origin iframe, wait for its document body, wrap that body with Cypress, find the input, and call .type():
cy.get('iframe')
.its('0.contentDocument.body')
.should('not.be.empty')
.then(cy.wrap)
.find('input')
.type('your text')
Replace 'iframe' and 'input' with selectors that uniquely identify the frame and the field. This pattern does not cross the browser’s same-origin boundary: a cross-origin embedded frame cannot normally be read this way.
Check the frame’s origin before writing the test
An origin is made up of the scheme, hostname, and port. Compare those parts for the page running Cypress and the document loaded inside the iframe. If they match, Cypress can use the frame’s contentDocument.body with ordinary Cypress queries and actions. If they differ, browser same-origin security prevents the parent page’s test code from reading the embedded document through this pattern.
This distinction is about the document embedded in the page, not just the URL visible in the address bar. A page can be on your application’s origin while containing a frame hosted elsewhere. In that case, the parent page’s origin does not give the test access to the frame’s document.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
- Same-origin embedded frame: use the body-wrapping pattern below, then query and type into the field.
- Cross-origin embedded frame: the ordinary
contentDocumentapproach is blocked. Consider whether the test can instead cover a top-level navigation, or whether the limited browser configuration option described below is appropriate for your test suite. - Top-level navigation to another origin: this is a different case from an embedded iframe;
cy.origin()is relevant to the former, not a way to enter the latter.
Type into a same-origin iframe
Use a selector for the intended frame and field
If the page contains multiple frames or inputs, broad selectors can pick the wrong one. Substitute selectors tied to your application’s stable markup—for example, an iframe selector that identifies the intended frame and a field selector based on a stable attribute. The example uses input only as a general target.
cy.get('iframe#contact-frame')
.its('0.contentDocument.body')
.should('not.be.empty')
.then(cy.wrap)
.find('input[name="message"]')
.type('Hello')
The query starts at the wrapped iframe body, so .find() searches within that document rather than the parent page. Keep the chain attached to the wrapped body when continuing with Cypress queries and actions inside the frame.
Reuse the access pattern with a helper
For a suite that needs the same frame repeatedly, put the body access in a helper and continue querying the returned Cypress chain:
Rank #2
const getIframeBody = () =>
cy.get('iframe#contact-frame')
.its('0.contentDocument.body')
.should('not.be.empty')
.then(cy.wrap)
getIframeBody()
.find('[name="message"]')
.type('Hello')
Keep the iframe selector specific if your page has more than one frame. The helper packages access to the body; it does not change which origins the browser permits Cypress to access.
Recommended Free Tools
Wait for the body and the field at the right times
The iframe document and the application content inside it may not be ready at the same moment. .its('0.contentDocument.body') with .should('not.be.empty') waits for the body to become available and populated; Cypress’s documented pattern relies on retrying while the iframe content becomes available.
A populated body does not guarantee that an asynchronously rendered input is already present. In that case, query the actual target field with a retrying Cypress query or assertion before typing. For example, the chained .find('input[name="message"]') identifies the desired field rather than treating the body’s existence as proof that the field is ready. Choose the field selector based on the application’s markup, not on a transient layout detail.
Rank #3
A useful diagnosis is to separate these two waits: first establish that the frame body is populated, then establish that the intended field can be found. If the body is available but the field is not, investigate the field’s selector and when the application renders it. If the body itself is unavailable, check frame selection and origin before changing the field query.
Cross-origin iframes: know the limits of each workaround
For an embedded frame on a different origin, the browser’s standard security boundary prevents the parent test from reading its document. The same-origin code cannot be made cross-origin merely by changing the selector or waiting longer.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
chromeWebSecurity: false is browser-limited
Cypress documents chromeWebSecurity: false as a workaround that permits access to cross-origin embedded frames in Chromium-family browsers. This is a browser-specific configuration choice, not a portable Cypress iframe API. The documented workaround is unsupported in Firefox and WebKit.
Rank #4
Use it only after weighing the security implications and the browsers your suite must cover. A test that depends on this setting is not equivalent across those unsupported browser engines. Check the current Cypress guidance for the version and browser configuration used by your project before relying on it; do not treat this option as a general fix for cross-origin access.
cy.origin() is for top-level navigation, not embedded frames
cy.origin() lets a test run commands against a second origin after top-level navigation. It does not let Cypress issue commands inside a cross-origin iframe. If a link or redirect takes the browser to another page origin, that is the situation where cy.origin() may apply. If that other-origin document remains embedded in an iframe, it does not solve the frame boundary.
There is also a version detail for tests that navigate between top-level origins: Cypress documents that, as of v14.0.0, it no longer injects document.domain into text/html pages by default. Consequently, cy.origin() must be used when navigating between any two origins in a test, including origins within the same superdomain. The injectDocumentDomain configuration option can temporarily restore the earlier behavior, but Cypress marks it deprecated and says it will be removed in a future version. This change concerns top-level origin navigation; it does not turn cy.origin() into an iframe solution.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Troubleshoot a test that cannot type
| Symptom | Likely cause | What to check |
|---|---|---|
contentDocument is null or cannot be used |
The frame may be cross-origin, or the test may have selected a different frame than intended. | Compare scheme, hostname, and port for the parent page and frame document. Confirm the iframe selector identifies the intended frame. Waiting will not remove a cross-origin restriction. |
| The body is empty or not ready | The iframe document has not finished rendering content when the query runs. | Use .its('0.contentDocument.body').should('not.be.empty') and check that Cypress has selected the correct frame. |
| The body is available but the field is not found | The field may render later, or its selector may not match the iframe’s markup. | Query the actual target field with a retrying query or assertion, and use a stable selector for that field. |
cy.origin() has no effect on the iframe |
It handles a second origin after top-level navigation, not a nested embedded document. | Determine whether the other-origin page is a top-level destination or remains inside an iframe; use the appropriate approach for that case. |
| The cross-origin workaround works in Chrome but not Firefox or WebKit | The documented chromeWebSecurity: false workaround is unsupported in those engines. |
Plan for the browser engines your suite must support rather than assuming the configuration is portable. |
| You are considering an iframe plugin for a same-origin frame | A plugin may add dependency without addressing the actual issue. | Cypress documents that same-origin iframe interaction is possible with existing commands; first verify origin, frame selection, readiness, and target selectors. |
Keep the test reliable and scoped
- Prefer stable selectors. Identify the frame and field by attributes maintained for testing, where your application provides them, rather than relying on a broad selector when several candidates exist.
- Wait for the condition you need. The body assertion establishes that the iframe body is populated. If the application renders the input afterward, wait on the target field as well.
- Preserve the frame context. Query from the body wrapped with
cy.wrap(); a query against the parent document is not a query inside the iframe. - Choose the approach by the test’s actual boundary. Same-origin frame access, cross-origin embedded content, and top-level navigation are distinct cases. Select the method that matches the document’s placement and origin rather than trying APIs interchangeably.
- Account for browser coverage. A Chromium-specific configuration workaround cannot stand in for support in Firefox or WebKit.
Cypress’s FAQ says there is no dedicated “switch into an iframe” command in its documented guidance. For a same-origin frame, the practical approach is to access and wrap the body, then use Cypress’s ordinary query and action chain.
Or skip the browser setup
If the job is to capture a website image or PDF rather than type into an iframe as part of a Cypress test, ScreenshotNeo is a separate option: it is a screenshot API and MCP server, not a replacement for Cypress iframe interaction. Its cleanup can accept cookie or consent banners like a visitor and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status. AI agents can use its MCP server tools, including take_screenshot, get_page_info, and capture_pdf.
For example, this cURL request captures a page; replace the URL with the page you want to capture and use your API key. See the ScreenshotNeo API documentation for request options:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo offers 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots. Learn about ScreenshotNeo or sign up for 1,000 free screenshots a month with no card.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

