How to Embed a Privy Wallet in Your Website
By Shawn Michael Thomas II, Founder of Simple Easy Transactions · Published ·
How do I embed a Privy wallet in my website? To embed a Privy wallet in a website, run the wallet app on its own origin and frame it from the site. Three settings must agree: your Privy app's allowed origins must include the website, because Privy's iframe checks every frame ancestor in production; the wallet's Content-Security-Policy must name the website in frame-ancestors; and the website must size the frame, since it cannot measure a page from another origin. Card purchases through Stripe's onramp need a top-level page.
AT A GLANCE
Wallet app framed on your site vs Privy SDK inside your own pages.
| Question | Wallet app framed on your site | Privy SDK inside your own pages |
|---|---|---|
| Where the wallet code runs | On its own origin, such as a wallet subdomain, inside an iframe | On your website's own pages |
| Privy allowed origins | The wallet's origin and every website that frames it | Your website's origin |
| Security policy | The wallet's CSP names your site in frame-ancestors | Your site's CSP allows Privy's frames, as Privy's CSP guide lists |
| Page height | The wallet reports its height with postMessage; the site checks who sent it | Ordinary page layout |
| Stripe's card onramp | Not inside the frame; link to the wallet's own page | Runs on your page, which is top level |
| Releases | The wallet ships on its own; the website only hosts the frame | Wallet and website ship together |
HOW EACH ONE WORKS
How each one works.
Privy decides first whether your page may use the wallet at all. Its allowed origins setting restricts which domains may use your Privy app ID in a browser, and Privy's list of client errors includes one for exactly this case: “Your request is coming from an iFrame whose parent origin is not allowlisted.” So the website that frames the wallet goes on that list, not only the wallet's own domain.
The check is enforced inside Privy's own frame too. Privy's security FAQ says that once allowed origins are set for production, “the served iframe enforces that all frame ancestors must be within those allowed origins,” through both frame-ancestor CSP checks and checks in Privy's code.
The wallet's own page has to agree to be framed. Privy's Content Security Policy guide recommends frame-ancestors 'none' “unless you expect your website to be embedded”. For an embedded wallet you expect exactly that, so frame-ancestors names your site instead. The older X-Frame-Options header has no value that names one outside site, so a framable wallet page leaves it off and relies on frame-ancestors.
The website cannot measure the wallet. A page cannot read the layout of a frame from another origin, so the wallet has to say how tall it is. It sends a message to its parent with postMessage, and the website accepts it only from the wallet's origin and from that frame's own window.
Card purchases are the exception. Stripe's crypto onramp will not run inside a frame, so an embedded wallet sends people to its own top-level page for that one step.
FIELD NOTES
What I've learned building this.
- On this site the Private Wallet runs on wallet.simpleeasytransactions.com, and the home page and /wallets frame it with ?embed=1, which hides the wallet's own header and footer so the website's show instead.
- The wallet measures its own container, not the document, before it reports a height: a document is never shorter than its frame, so its height could grow but never shrink. It uses a timer rather than requestAnimationFrame, because browsers pause animation frames in a cross-origin frame that is off screen, and the wallet often starts below the fold.
- The website takes a height only from the wallet's origin and from that frame's window, and only between 100 and 6,000 pixels.
- Stripe's onramp script checks for a frame itself. On 2026-10-02 it threw “Stripe Crypto Onramp is not able to run in an iframe. Please redirect to Onramp at the top level.” So the framed wallet never loads Stripe; its Buy crypto card opens the wallet's own page in a new tab.
- My staging site could not start Privy inside the frame until I added the staging website's origin to the staging Privy app's allowed origins. That is the first thing to check when a framed wallet stays blank.
HOW TO CHOOSE
How I'd choose.
- Frame the wallet when one wallet app should appear on several pages or sites and you want to release it once.
- Build Privy into your own pages when the wallet is the product, or when Stripe's card onramp has to run on the same page.
- Before you ship a framed wallet, add every framing origin to Privy's allowed origins and to the wallet's frame-ancestors, and test sign-in inside the frame on staging.
SOURCES
Where these facts come from.
Sources checked on . Providers change their products and rules, so the linked pages are the final word.