> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Embed the upgrade app (iframe)

> Render the Dynamic upgrade app inline in an iframe within your own sheet or modal, reacting to its origin-checked completion message.

Render the app in an iframe instead of navigating away. When embedded, the app **posts an origin-checked completion message** instead of redirecting, so your page never unloads and you keep full control of the surrounding UI (e.g. your bottom sheet or modal). See [the overview](https://docs.dynamic.xyz/docs/javascript/building-ui/legacy-wallet-upgrade.md) for detection, hosting, and the shared CORS requirements.

> [tab] TypeScript
>
> `openUpgradeIframe` appends an iframe into a container you provide and resolves `completed` when the app reports done (refreshing the session on success). Call `close()` if the user dismisses your sheet first.
>
> ```typescript theme={"system"}
> import { openUpgradeIframe } from '@dynamic-labs-sdk/legacy-embedded-wallet-upgrade';
>
> async function embedUpgrade(container: HTMLElement) {
>   const session = openUpgradeIframe({ container });
>
>   const outcome = await session.completed;
>   if (outcome.status === 'success') {
>     // Session already refreshed. closeSheet is your implementation.
>     closeSheet();
>   } else {
>     offerRetry();
>   }
> }
>
> // If the user dismisses your sheet before completion:
> // session.close();
> ```

> [tab] React
>
> `useUpgradeIframe` renders no DOM — it returns the `upgradeUrl` for you to put in your own `<iframe>`, and attaches the origin-checked completion listener while `active`. Alongside `onComplete`, it returns `result` — the outcome, `undefined` until completion — so you can render off it directly.
>
> ```tsx theme={"system"}
> import { useState } from 'react';
> import { useUpgradeIframe } from '@dynamic-labs-sdk/legacy-embedded-wallet-upgrade/react';
>
> function UpgradeSheet() {
>   const [isOpen, setIsOpen] = useState(false);
>
>   const { upgradeUrl, result } = useUpgradeIframe({
>     active: isOpen,
>     // Session already refreshed on success. showToast is your implementation.
>     onComplete: ({ status }) => {
>       showToast(status);
>       setIsOpen(false);
>     },
>   });
>
>   // You can also drive UI off `result` instead of the callback:
>   if (result?.status === 'success') return <p>Wallet upgraded.</p>;
>
>   return (
>     <>
>       <button type="button" onClick={() => setIsOpen(true)}>
>         Upgrade wallet
>       </button>
>       {isOpen && upgradeUrl ? (
>         <iframe title="Wallet upgrade" src={upgradeUrl} />
>       ) : null}
>     </>
>   );
> }
> ```

> [!NOTE]
>
> This route is web-only — there is no DOM iframe in React Native. React Native customers should use the [Popup route](https://docs.dynamic.xyz/docs/javascript/building-ui/legacy-wallet-upgrade/popup.md), which runs in the system auth session.

## See also

* [Upgrade overview](https://docs.dynamic.xyz/docs/javascript/building-ui/legacy-wallet-upgrade.md) — detection, hosting, and shared requirements
* [Redirect to the app](https://docs.dynamic.xyz/docs/javascript/building-ui/legacy-wallet-upgrade/redirect.md)
* [Popup (new window)](https://docs.dynamic.xyz/docs/javascript/building-ui/legacy-wallet-upgrade/popup.md)
* [Going lower-level](https://docs.dynamic.xyz/docs/javascript/building-ui/legacy-wallet-upgrade/lower-level.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.