Skip to content

Instantly share code, notes, and snippets.

@rafinskipg
Created December 3, 2025 06:55
Show Gist options
  • Select an option

  • Save rafinskipg/d81905145a4cbec40d793ae52d46ee18 to your computer and use it in GitHub Desktop.

Select an option

Save rafinskipg/d81905145a4cbec40d793ae52d46ee18 to your computer and use it in GitHub Desktop.

Phantom SDK Integration Guide

This guide will help you integrate Phantom's SDK to enable users to connect with Google (user wallets) or via the Phantom browser extension/mobile app.

Overview

When a user clicks the Phantom button in your existing modal, they will have two options:

  1. Continue with Google - Creates a non-custodial user wallet authenticated via Google
  2. Connect via Extension/App - Connects to the user's existing Phantom browser extension or mobile app

Both options provide full wallet functionality including signing transactions, sending funds, and managing accounts.

Installation

Option 1: React SDK (Recommended for React apps)

npm install @phantom/react-sdk@beta

Option 2: Browser SDK (For vanilla JS or non-React frameworks)

npm install @phantom/browser-sdk@beta

Note: Make sure to install the latest beta version to get access to the newest features including Google authentication and improved mobile browser support.

Setup

Step 1: Get Your App ID

  1. Visit phantom.com/portal
  2. Create or select your application
  3. Copy your appId
  4. Configure your URLs under the URL config section.
    • Whitelisted domains
    • Whitelisted auth redirect URLs

Step 2: Configure Auth Redirect URLs

Important: When using Google authentication, you must configure redirect URLs to handle the OAuth callback. This is critical for the authentication flow to work properly.

Set Up Your Redirect Route

Create a callback route in your app (e.g., /auth/callback) that will handle the OAuth redirect:

// Example: /auth/callback route
import { useConnect, usePhantom } from "@phantom/react-sdk";

function AuthCallback() {
  const { isConnected, isConnecting } = usePhantom();
  const { error: connectError } = useConnect();

  // Loading state
  if (isConnecting) {
    return (
      <div>
        <div className="spinner" />
        <h3>Connecting to your wallet...</h3>
        <p>Please wait while we complete authentication.</p>
      </div>
    );
  }

  // Success state
  if (isConnected) {
    return (
      <div>
        <div className="success-icon"></div>
        <h3>Authentication Successful</h3>
        <p>You are now connected to your wallet.</p>
        <button onClick={() => window.location.href = "/"}>
          Continue to App
        </button>
      </div>
    );
  }

  // Error state
  if (connectError) {
    return (
      <div>
        <div className="error-icon"></div>
        <h3>Authentication Failed</h3>
        <p>{connectError.message || "An error occurred during authentication."}</p>
        <div>
          <button onClick={() => window.location.reload()}>Retry</button>
          <button onClick={() => window.location.href = "/"}>Go Home</button>
        </div>
      </div>
    );
  }

  return null;
}

Configure Redirect URL in SDK

Set the redirectUrl in your SDK configuration to point to your callback route:

import { PhantomProvider } from "@phantom/react-sdk";
import { AddressType } from "@phantom/browser-sdk";

function App() {
  return (
    <PhantomProvider
      config={{
        providers: ["google", "injected"], // Google auth + extension/app
        appId: "your-app-id-from-portal", // Required for Google auth
        addressTypes: [AddressType.solana, AddressType.ethereum], // Or just Solana
        authOptions: {
          // Set your callback URL - this is where users will be redirected after Google auth
          redirectUrl: window.location.origin + "/auth/callback"
        },
      }}
    >
      <YourApp />
    </PhantomProvider>
  );
}

Using Browser SDK

import { BrowserSDK, AddressType } from "@phantom/browser-sdk";

const sdk = new BrowserSDK({
  providers: ["google", "injected"], // Google auth + extension/app
  appId: "your-app-id-from-portal", // Required for Google auth
  addressTypes: [AddressType.solana, AddressType.ethereum], // Or just Solana
  authOptions: {
    // Set your callback URL
    redirectUrl: window.location.origin + "/auth/callback"
  },
});

Step 3: Set Up Your Router

Make sure your routing is configured to handle the callback route:

React Router Example

import { Routes, Route } from "react-router-dom";
import { PhantomProvider } from "@phantom/react-sdk";
import { AuthCallback } from "./AuthCallback";
import { YourMainApp } from "./YourMainApp";

function App() {
  const config = {
    providers: ["google", "injected"],
    appId: "your-app-id",
    addressTypes: [AddressType.solana, AddressType.ethereum],
    authOptions: {
      redirectUrl: window.location.origin + "/auth/callback",
    },
  };

  return (
    <Routes>
      <Route
        path="/auth/callback"
        element={
          <PhantomProvider config={config}>
            <AuthCallback />
          </PhantomProvider>
        }
      />
      <Route
        path="/"
        element={
          <PhantomProvider config={config}>
            <YourMainApp />
          </PhantomProvider>
        }
      />
    </Routes>
  );
}

Next.js Example

// app/auth/callback/page.tsx
"use client";

import { PhantomProvider } from "@phantom/react-sdk";
import { AuthCallback } from "@/components/AuthCallback";

export default function CallbackPage() {
  const config = {
    providers: ["google", "injected"],
    appId: process.env.NEXT_PUBLIC_APP_ID!,
    addressTypes: [AddressType.solana, AddressType.ethereum],
    authOptions: {
      redirectUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/auth/callback`,
    },
  };

  return (
    <PhantomProvider config={config}>
      <AuthCallback />
    </PhantomProvider>
  );
}

Important Notes on Redirect Handling

  1. Loading State: Always show a loading indicator while isConnecting is true. The SDK handles the OAuth flow automatically when the user returns to your callback URL.

  2. Error Handling: Check for connectError and display user-friendly error messages. Common errors include:

    • User cancelled authentication
    • Network errors
    • Invalid redirect URL configuration
  3. Success State: Once isConnected is true, you can redirect users to your main app or show a success message.

  4. URL Matching: The redirectUrl must exactly match the URL where your callback component is mounted. Make sure there are no trailing slashes or query parameters that could cause mismatches.

  5. Environment Variables: For production, use environment variables for your redirect URL:

    redirectUrl: process.env.NEXT_PUBLIC_REDIRECT_URL || 
                 import.meta.env.VITE_REDIRECT_URL || 
                 window.location.origin + "/auth/callback"

Implementation

Updating Your Phantom Button

When a user clicks your existing Phantom button, you'll want to show them connection options. Here's how to implement it:

React SDK Example

import { useConnect, usePhantom } from "@phantom/react-sdk";

function PhantomConnectButton() {
  const { connect, isConnecting } = useConnect();
  const { isConnected, addresses } = usePhantom();

  const handlePhantomClick = async () => {
    if (isConnected) {
      // Already connected, show wallet info or disconnect
      return;
    }

    // Show connection options modal
    // Option 1: Connect with Google
    const connectWithGoogle = async () => {
      try {
        await connect({ provider: "google" });
        console.log("Connected with Google:", addresses);
      } catch (error) {
        console.error("Google connection failed:", error);
      }
    };

    // Option 2: Connect with Extension/App
    const connectWithExtension = async () => {
      try {
        await connect({ provider: "injected" });
        console.log("Connected with extension:", addresses);
      } catch (error) {
        console.error("Extension connection failed:", error);
      }
    };

    // Show your modal with both options
    showConnectionModal({
      onGoogle: connectWithGoogle,
      onExtension: connectWithExtension,
    });
  };

  return (
    <button onClick={handlePhantomClick} disabled={isConnecting}>
      {isConnecting ? "Connecting..." : "Connect Phantom"}
    </button>
  );
}

Browser SDK Example

import { BrowserSDK, AddressType } from "@phantom/browser-sdk";

const sdk = new BrowserSDK({
  providers: ["google", "injected"],
  appId: "your-app-id",
  addressTypes: [AddressType.solana, AddressType.ethereum],
});

// Handle Phantom button click
async function handlePhantomClick() {
  if (sdk.isConnected()) {
    // Already connected
    return;
  }

  // Show connection options
  const option = await showConnectionModal(); // Your modal implementation

  if (option === "google") {
    try {
      const { addresses } = await sdk.connect({ provider: "google" });
      console.log("Connected with Google:", addresses);
    } catch (error) {
      console.error("Google connection failed:", error);
    }
  } else if (option === "extension") {
    try {
      const { addresses } = await sdk.connect({ provider: "injected" });
      console.log("Connected with extension:", addresses);
    } catch (error) {
      console.error("Extension connection failed:", error);
    }
  }
}

Connection Flow

Google Authentication Flow

  1. User clicks "Continue with Google"
  2. SDK redirects to Google OAuth
  3. User authenticates with Google
  4. SDK creates a non-custodial wallet (keys encrypted client-side)
  5. User is redirected back to your app, connected and ready

Extension/App Connection Flow

  1. User clicks "Connect via Extension/App"
  2. SDK detects if Phantom extension is installed (desktop) or prompts to open mobile app
  3. User approves connection in extension/app
  4. Connection established, wallet ready to use

Using the Connected Wallet

Once connected, you can use the wallet for all standard operations:

React SDK

import { useSolana, useEthereum } from "@phantom/react-sdk";

function TransactionExample() {
  const { solana } = useSolana();
  const { ethereum } = useEthereum();

  // Sign and send Solana transaction
  const sendSolanaTx = async () => {
    const result = await solana.signAndSendTransaction(transaction);
    console.log("Transaction sent:", result.signature);
  };

  // Sign and send Ethereum transaction
  const sendEthereumTx = async () => {
    const result = await ethereum.sendTransaction({
      to: "0x...",
      value: "1000000000000000000",
    });
    console.log("Transaction sent:", result.hash);
  };

  // Sign messages
  const signMessage = async () => {
    const signature = await solana.signMessage("Hello Polymarket!");
    console.log("Signature:", signature);
  };
}

Browser SDK

// Sign and send Solana transaction
const solanaResult = await sdk.solana.signAndSendTransaction(transaction);
console.log("Transaction sent:", solanaResult.signature);

// Sign and send Ethereum transaction
const ethResult = await sdk.ethereum.sendTransaction({
  to: "0x...",
  value: "1000000000000000000",
});
console.log("Transaction sent:", ethResult.hash);

// Sign messages
const signature = await sdk.solana.signMessage("Hello Polymarket!");
console.log("Signature:", signature);

Auto-Connect

The SDK automatically attempts to reconnect users who have previously connected:

// React SDK - auto-connect is enabled by default
<PhantomProvider
  config={{
    providers: ["google", "injected"],
    appId: "your-app-id",
    addressTypes: [AddressType.solana],
  }}
>
// Browser SDK
const sdk = new BrowserSDK({
  providers: ["google", "injected"],
  appId: "your-app-id",
  addressTypes: [AddressType.solana],
});

// Manually trigger auto-connect
await sdk.autoConnect();

Best Practices

  1. Show connection status: Use isConnected to show wallet status in your UI
  2. Handle loading states: Use isConnecting or isLoading to show loading indicators
  3. Error handling: Always wrap connection calls in try-catch blocks
  4. User experience: Show clear options for Google vs Extension connection
  5. Mobile optimization: Test on mobile browsers to ensure smooth experience

Next Steps

  1. Get your appId from phantom.com/portal
  2. Install the latest beta version of the SDK:
    npm install @phantom/react-sdk@beta
    # or
    npm install @phantom/browser-sdk@beta
  3. Set up your auth callback route (/auth/callback or similar) with proper loading, success, and error states
  4. Configure redirectUrl in your SDK config to point to your callback route
  5. Update your Phantom button to show connection options (Google vs Extension)
  6. Test the complete flow:
    • Test Google authentication flow end-to-end
    • Test Extension/App connection
    • Verify redirect handling works correctly
    • Test error scenarios (user cancellation, network errors)
  7. Deploy and monitor connection success rates

Troubleshooting

Redirect URL Issues

If authentication isn't completing:

  • Verify your redirectUrl exactly matches the URL where your callback component is mounted
  • Check that your callback route is properly configured in your router
  • Ensure there are no CORS issues blocking the redirect
  • Check browser console for any error messages
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment