> ## Documentation Index
> Fetch the complete documentation index at: https://www.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](/docs/javascript/building-ui/legacy-wallet-upgrade) for detection, hosting, and the shared CORS requirements.

<Tabs>
  <Tab title="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>

  <Tab title="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}
        </>
      );
    }
    ```
  </Tab>
</Tabs>

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

## See also

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