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

# Phantom Redirect

<Card title="Recommended: JavaScript SDK with React Hooks" icon="react" color="#4779FE">
  For new React apps, we recommend the JavaScript SDK with React Hooks (`@dynamic-labs-sdk/react-hooks`) instead of the legacy React SDK documented here. The JS SDK comes with many benefits such as a much smaller bundle size and other optimizations. Use the [React quickstart (JavaScript SDK)](/javascript/reference/react-quickstart) to get started.
</Card>

## Introduction

This guide will help you use the Phantom redirect-based connect feature on mobile. Instead of deeplinking into the Phantom in-app browser, your users can enjoy a redirect-based connection, where they are automatically redirected between the app and their wallet to facilitate the connect, sign and additional method calls.

## Why redirect events are necessary

Unlike browser-extension wallets (like MetaMask or Phantom browser extension), Phantom on mobile operates via deep links. When you request a signature:

1. Your app opens Phantom via a deep link (`phantom://`)
2. User approves or rejects in the Phantom app
3. Phantom redirects back to your app

**On mobile web browsers**, this redirect opens a new tab, which means:

* The original JavaScript execution context is lost
* Any `Promise` awaiting the signature result never resolves
* Your app loses track of the pending operation

This is fundamentally different from browser-extension wallets where everything happens in the same page context via injected providers. To handle this, you must use event listeners to capture the redirect results.

## Setup

### `mobileExperience` prop

Make sure you set `mobileExperience` to `redirect` on your DynamicContextProvider:

```jsx theme={"system"}
<DynamicContextProvider
  settings={{
    mobileExperience: 'redirect'
    // ... other settings
  }}
>
```

With just this code, your users will connect with the redirect-based approach. If you want to learn how to make method calls (like `signAndSendTransaction`) and access the result, read on.

## Handling redirect events

When using redirect-based signing on mobile, Phantom opens via deep link and redirects back after the user approves or rejects. Because the original Promise context is lost, you must use event listeners to capture the results.

Use the `usePhantomRedirectEvents` hook to listen for redirect results:

```jsx theme={"system"}
import { usePhantomRedirectEvents } from '@dynamic-labs/sdk-react-core';

const MyComponent = () => {
  usePhantomRedirectEvents({
    onSignMessage: ({ signature, errorCode, errorMessage }) => {
      if (signature) {
        console.log('Message signed:', signature);
      } else {
        console.error('Sign failed:', errorCode, errorMessage);
      }
    },
    onSignAndSendTransaction: ({ signature, transaction, errorCode, errorMessage }) => {
      if (signature) {
        console.log('Transaction sent:', signature);
      } else {
        console.error('Transaction failed:', errorCode, errorMessage);
      }
    },
    onSignTransaction: ({ signature, transaction, errorCode, errorMessage }) => {
      // Handle signed transaction
    },
    onSignAllTransactions: ({ signature, transactions, errorCode, errorMessage }) => {
      // Handle signed transactions
    },
  });

  return <div>Your app content</div>;
};
```

Mount this hook in a component that renders when your app loads so it can capture the redirect result.

### Available events

| Event / Callback                                            | Payload                                                               | Description                                         |
| ----------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------- |
| `signMessageResult` / `onSignMessage`                       | `{ signature?, message?, requestId?, errorCode?, errorMessage? }`     | Fired after signing a message.                      |
| `signTransactionResult` / `onSignTransaction`               | `{ transaction?, requestId?, errorCode?, errorMessage? }`             | Fired after signing a single transaction.           |
| `signAndSendTransactionResult` / `onSignAndSendTransaction` | `{ signature?, transaction?, requestId?, errorCode?, errorMessage? }` | Fired after signing and broadcasting a transaction. |
| `signAllTransactionsResult` / `onSignAllTransactions`       | `{ transactions?, requestId?, errorCode?, errorMessage? }`            | Fired after signing multiple transactions.          |

All callbacks/events are optional. The events are persisted and re-emitted when the app regains focus, ensuring you always receive the result even if the app was backgrounded.
