> ## 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.

# Upgrade by redirect

> Navigate the user to the Dynamic upgrade app and read the outcome when they return, using detectUpgradeRedirect and completeUpgradeRedirect.

Navigate the user to the upgrade app, then handle the outcome when they return. This is the simplest route — see [the overview](/docs/javascript/building-ui/legacy-wallet-upgrade) for detection, hosting, and the shared CORS requirements.

The return leg is two functions, matching how social sign-in and device registration consume their redirects:

* `detectUpgradeRedirect({ url })` — a pure, synchronous check for whether the URL is a return from the upgrade app.
* `completeUpgradeRedirect({ url }, client?)` — reads the outcome, refreshes the session on success, and returns it (`null` when there's nothing to consume). The refresh is best-effort: the upgrade already succeeded on the backend, so a failed refresh still reports `success` and reconciles on the next auth refresh.

You always pass the URL yourself — `window.location.href`.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={"system"}
    import {
      startUpgradeRedirect,
      detectUpgradeRedirect,
      completeUpgradeRedirect,
    } from '@dynamic-labs-sdk/legacy-embedded-wallet-upgrade';

    // On your "Upgrade wallet" button. redirectUrl defaults to the current page.
    function startUpgrade() {
      void startUpgradeRedirect();
    }

    // Run once on the page the user returns to.
    async function handleUpgradeReturn() {
      if (!detectUpgradeRedirect({ url: window.location.href })) return;

      const outcome = await completeUpgradeRedirect({ url: window.location.href });
      if (outcome?.status === 'success') {
        // The session was already refreshed for you. refreshUi is your implementation.
        refreshUi();
      } else {
        // offerRetry is your implementation — the upgrade failed or was cancelled.
        offerRetry();
      }
    }
    ```
  </Tab>

  <Tab title="React">
    `useUpgradeRedirectResult` runs the detect + complete steps once on mount and strips the result parameter from the URL for you. Drive your UI off `result` (the outcome once the user returns, `undefined` until then) and `error` (set if consuming the return fails). `onComplete` / `onError` callbacks are also available if you prefer.

    ```tsx theme={"system"}
    import {
      startUpgradeRedirect,
      useUpgradeRedirectResult,
    } from '@dynamic-labs-sdk/legacy-embedded-wallet-upgrade/react';

    function UpgradeButton() {
      const { result, error } = useUpgradeRedirectResult();

      if (result?.status === 'success') {
        // The session was already refreshed for you.
        return <p>Wallet upgraded.</p>;
      }

      const failed = error !== undefined || result?.status === 'error';

      return (
        <>
          <button type="button" onClick={() => void startUpgradeRedirect()}>
            Upgrade wallet
          </button>
          {failed && <p>Upgrade failed — try again.</p>}
        </>
      );
    }
    ```
  </Tab>
</Tabs>

## Handling errors

| Situation                   | What to do                                           |
| --------------------------- | ---------------------------------------------------- |
| Outcome `status` is `error` | The upgrade failed or was cancelled — offer a retry. |

## See also

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