You mint a signing session URL, drop it into an iframe, and get a blank white box. Open the same URL in a normal tab and it works fine, so the document is not the problem: the embedding is. Open the browser console first, because the error there usually points straight at one of these four causes.
1. The signing page refuses to be framed
If the console says something like "Refused to display ... in a frame", the provider is sending an anti-framing header. X-Frame-Options: DENY blocks framing entirely, and SAMEORIGIN allows it only when every ancestor frame shares the page's origin. The modern equivalent is the Content-Security-Policy frame-ancestors directive, which names the parents allowed to embed the page. Note that X-Frame-Options ALLOW-FROM is obsolete and modern browsers ignore the header completely when they see it, so a provider cannot allowlist your domain that way. The fix is provider-specific: use the embed-oriented signing view they document, register your parent domain in their allowlist, or, if they do not support framing at all, open the signing session in a new tab or popup.
2. The signing URL already expired or was used
Embedded signing URLs are deliberately short lived and single use. Docusign's API reference for EnvelopeViews:createRecipientView says the returned URL "can be used only once and expires after 5 minutes" and warns you not to store or email it. Other providers apply similar time-to-live rules. So if you generate the URL in one request, persist it, and render the page a few minutes later, or if a component mounts twice in development and burns the token on the first mount, the second load gets an expired-token page that often paints as an empty frame. Generate the URL server side at the moment you render the iframe, and mint a fresh one on every reload rather than reusing the stored value.
3. The signer's session cookie is being dropped
Inside an iframe, the provider's cookies are third-party (cross-site) cookies, and browsers treat those very differently. Firefox enables Total Cookie Protection by default through Enhanced Tracking Protection, which gives third-party cookies a separate jar per site. Safari applies comparable protections by default under Intelligent Tracking Prevention. Chrome does not block third-party cookies by default, only in Incognito or when the user turns blocking on. That asymmetry is why an embed can look perfect in your Chrome dev loop and render blank for a Safari user. Cross-site cookies also have to be set with SameSite=None and Secure to be sent at all. You cannot change the provider's cookie headers, but you can test in Safari and a Firefox private window before shipping, and check whether the provider offers an embedded flow that carries session state in the URL or through postMessage instead of relying on cookies.
4. Your own sandbox attribute is too tight
If you added a sandbox attribute to the iframe, the signing app starts with everything switched off. Without allow-scripts it cannot run JavaScript at all. Without allow-forms a form will display normally but submitting it will not validate input or send data to the server. Without allow-same-origin the resource is treated as coming from a special origin that always fails the same-origin policy, which can cut it off from its own cookies and storage. Either drop the attribute or grant exactly the tokens the provider documents. One caveat: when the embedded document has the same origin as the embedding page, combining allow-scripts and allow-same-origin lets the embedded document remove the sandbox attribute, so it buys you nothing.
Quick triage
A "Refused to display" console error means a framing header. A frame that works on first load and goes blank on refresh means the URL time-to-live. Working in Chrome but blank in Safari means cookies. Blank with no console or network errors at all usually means your own sandbox attribute.
Back to All Questions