Skip to main content

Prerequisites

Before this page: users who sign in to your app (see Post-login user setup) and a Dynamic environment with WaaS enabled.

What you’ll build

Some users may still hold an earlier, legacy generation of embedded wallet. The JavaScript SDK does not support these wallets: no extension registers a provider for them, so a user on a legacy wallet cannot sign transactions or messages, and calls fail with a NoWalletProviderFoundError. Upgrading to Dynamic WaaS is required for those users to use their wallets. Dynamic provides a ready-made upgrade app that performs the upgrade, and the wallet keeps the same address. Because the upgrade happens in a dedicated app (hosted by Dynamic or self-hosted, see Hosting the app), the only supported path is routing the user to it; there is no in-SDK upgrade. The @dynamic-labs-sdk/legacy-embedded-wallet-upgrade package wraps the whole flow so you only call functions: it derives the environment from your client, builds the app URL, validates the return URL, and handles the completion handshake. Your job is to:
  1. Detect which users need the upgrade.
  2. Route them to the upgrade app (by redirect, by embedding it, or by popup).
  3. React when the upgrade finishes.
This page covers what’s shared across the routes. Each route then has its own page: If none of those fit, going lower-level lets you build the URL and own the mounting yourself.

Install

The React entry point (/react) has react and @dynamic-labs-sdk/react-hooks as optional peer dependencies. Non-React apps import the root and never pull React in.

Detect who needs the upgrade

Two synchronous helpers tell you whether the signed-in user has any wallet that needs upgrading. They read the environment and wallets from your client, so single-client apps call them with no arguments.

Choose a route

Hosting the app

By default every helper points at Dynamic’s hosted upgrade app. You can run it three ways:
  1. Dynamic-hosted: use the shared Dynamic-hosted deployment as-is (the default; pass nothing).
  2. Your own subdomain: point a CNAME (e.g. upgrade.yourapp.com) at the deployment so it runs on your own domain and branding.
  3. Fork & self-host: clone the upgrade app repo, build, and host it yourself.
For options 2 and 3, tell the package where the app lives with baseUrl. Every entry point accepts it:

Required: allowlist the app’s origin (CORS)

Add the origin serving the app to your environment’s allowed origins in the Dynamic dashboard, or the app’s calls will be blocked:
  • Your own subdomain / self-host → add your origin (e.g. https://upgrade.yourapp.com).
  • Dynamic-hosted → add https://upgrade-wallet.dynamic.dev.
If the app can’t reach Dynamic, it shows an “add your domain to allowed origins” screen, a signal that the serving origin isn’t allowlisted.

Custom auth domains

If your environment authenticates through a custom domain (e.g. auth.yourapp.com in place of Dynamic’s default API), the Dynamic-hosted upgrade app only authenticates against that domain once it’s on Dynamic’s internal allowlist. Environments that already had a custom domain configured when Dynamic v5 shipped are allowlisted, so the flow works out of the box.
Set up a custom domain more recently and the upgrade fails to reach your API? Reach out to Dynamic to have your domain added to the allowlist. (If you fork and self-host the app, you control this list yourself.)

Smoother UX: skip the extra login

If you serve the app on a subdomain of your app’s domain and your environment uses cookie-based sessions, an already-signed-in user lands in the app already authenticated, with no second login. Otherwise the user simply signs in again with the same credential they use in your app.
Tell the just-arrived user to sign in with the same credential they use in your app: that’s how the app finds the wallet to upgrade.

Handling errors

Route-specific errors (blocked/closed popups, etc.) are covered on each route’s page.

See also

Last modified on September 21, 2026