> ## Documentation Index
> Fetch the complete documentation index at: https://docs.near.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Privy

> Enable users to login with their social accounts (Google, GitHub, etc.)

export const Github = ({url, start, end, fname, language, withSourceLink = true}) => {
  const [code, setCode] = useState(null);
  function toRaw(ref) {
    const fullUrl = ref.slice(ref.indexOf('https'));
    const [url] = fullUrl.split('#');
    const [org, repo, , branch, ...pathSeg] = new URL(url).pathname.split('/').slice(1);
    return `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${pathSeg.join('/')}`;
  }
  async function fetchCode(url, fromLine, toLine) {
    let res;
    if (typeof window !== 'undefined') {
      const validUntil = localStorage.getItem(`${url}-until`);
      if (validUntil && Number(validUntil) > Date.now()) {
        res = localStorage.getItem(url);
      }
    }
    if (!res) {
      try {
        res = await (await fetch(url)).text();
        if (typeof window !== 'undefined') {
          localStorage.setItem(url, res);
          localStorage.setItem(`${url}-until`, String(Date.now() + 60000));
        }
      } catch {
        return 'Error fetching code, please try reloading';
      }
    }
    let body = res.split('\n');
    const from = fromLine ? Number(fromLine) - 1 : 0;
    const to = toLine ? Number(toLine) : body.length;
    body = body.slice(from, to);
    const precedingSpace = body.reduce((prev, line) => {
      if (line.length === 0) return prev;
      const spaces = line.match(/^\s+/);
      if (spaces) return Math.min(prev, spaces[0].length);
      return 0;
    }, Infinity);
    return body.map(line => line.slice(precedingSpace === Infinity ? 0 : precedingSpace)).join('\n');
  }
  function buildSourceUrl(url, start, end) {
    const base = url.split('#')[0];
    if (start && end) return `${base}#L${start}-L${end}`;
    if (start) return `${base}#L${start}`;
    return base;
  }
  useEffect(() => {
    const rawUrl = toRaw(url);
    fetchCode(rawUrl, start, end).then(res => setCode(res));
  }, [url, start, end]);
  const sourceUrl = buildSourceUrl(url, start, end);
  const fileName = fname ?? sourceUrl.split('/').pop();
  return <div className="my-5">
      {code === null ? <div>Loading...</div> : <CodeBlock language={language} filename={fileName} lines>
          {code}
        </CodeBlock>}
      {withSourceLink && <div className="flex justify-end" style={{
    marginTop: "-1rem"
  }}>
          <a href={sourceUrl} target="_blank" rel="noreferrer noopener" className="text-[0.6875rem] font-medium text-[#656d76] no-underline hover:text-[#1f2328] dark:text-[#8b949e] dark:hover:text-[#e6edf3]">
            See code on GitHub
          </a>
        </div>}
    </div>;
};

[Privy](https://www.privy.io/) is a third-party service that allows users to login using their email or social accounts (Google, Facebook, Twitter, etc). Upon login, a NEAR wallet is created for the user, which they can fund and use to interact with your dApp.

![Preview](https://framerusercontent.com/images/ugUCPrqIGlKFdxBwSbRoWriZtE.png?scale-down-to=2048\&width=4018\&height=2262)

<Tip>
  See full working example [here](https://github.com/near-examples/hello-privy)
</Tip>

<Info>
  **Web3Auth**
  For an alternative social login method you can check [Web3Auth](https://web3auth.io/). We have a functional [Web3Auth Integration Example](https://github.com/near-examples/hello-web3auth/) to show how to integrate Web3Auth into your web app.
</Info>

***

## Installation

Choose whether to expose your Privy wallet through [NEAR Connect](/web3-apps/tutorials/wallet-login.mdx) or integrate Privy directly into your application:

<Tabs>
  <Tab title="NEAR Connect">
    Install the plugin, NEAR Connect, and the UI packages used by the signing page:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    npm install @peerfolio/privy-near-connect @hot-labs/near-connect @radix-ui/themes @radix-ui/react-collapsible @radix-ui/react-icons
    ```
  </Tab>

  <Tab title="Direct Privy">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    npm install @privy-io/react-auth @near-js/accounts @near-js/providers @near-js/transactions @near-js/tokens @noble/hashes
    ```
  </Tab>
</Tabs>

### Which should I choose?

Using **NEAR Connect** would give your application access to **all NEAR Wallets** that support NEAR Connect, **plus social login** with Privy. This will provide an experience closer to Web3 applications.

Integrating **Privy directly** would make your application support **only social login** (through Privy). This should be the preferred way for applications that want to abstract away the wallet and provide a Web2-like experience to their users.

***

## Setup

<Tabs>
  <Tab title="NEAR Connect">
    [`privy-near-connect`](https://github.com/beneviolabs/privy-near-connect) lets you expose a Privy embedded wallet through [NEAR Connect](https://github.com/azbang/near-connect).

    <Steps>
      <Step title="Create a Privy app">
        Create an application in the [Privy dashboard](https://dashboard.privy.io/) and copy its **App ID** and **Client ID**. Store both values in your application's environment variables:

        ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
        VITE_PRIVY_APP_ID=your-privy-app-id
        VITE_PRIVY_APP_CLIENT_ID=your-privy-client-id
        ```
      </Step>

      <Step title="Publish a wallet manifest">
        Add `manifest.json` to your application's public directory. Replace the example URLs and wallet metadata with your own:

        ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
        {
          "version": "1.0.0",
          "wallets": [
            {
              "id": "myprivywallet",
              "name": "My Privy Wallet",
              "icon": "https://yourdapp.com/favicon.ico",
              "description": "Web wallet for NEAR",
              "website": "https://yourdapp.com",
              "version": "1.0.0",
              "executor": "https://raw.githubusercontent.com/beneviolabs/privy-near-connect/3d56b782669d242a1ea432921e291abc26b4ebc7/executor.js",
              "type": "sandbox",
              "platform": {
                "web": "https://yourdapp.com"
              },
              "features": {
                "signMessage": true,
                "signInWithoutAddKey": true,
                "signInAndSignMessage": true,
                "signInWithFunctionCallKey": true,
                "signAndSendTransaction": true,
                "signAndSendTransactions": true,
                "mainnet": true,
                "testnet": true
              },
              "permissions": {
                "isPrivyConnect": true,
                "storage": true,
                "allowsOpen": [
                  "https://yourdapp.com"
                ]
              },
              "metadata": {
                "signPageURL": "https://yourdapp.com/sign"
              }
            }
          ]
        }
        ```

        <Warning>
          Keep the `executor` URL pinned to an immutable commit SHA. NEAR Connect fetches and runs this script at runtime, so you should update the SHA deliberately when adopting a new executor build.
        </Warning>
      </Step>

      <Step title="Create the signing page">
        Add a `/sign` route and render the plugin's signing component there:

        ```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
        import Privy, { LocalStorage } from '@privy-io/js-sdk-core'
        import { SignPagePlugin } from '@peerfolio/privy-near-connect/sign-page-plugin'
        import '@radix-ui/themes/styles.css'
        import '@peerfolio/privy-near-connect/sign-page-plugin/theme.css'

        const privy = new Privy({
          appId: import.meta.env.VITE_PRIVY_APP_ID,
          clientId: import.meta.env.VITE_PRIVY_APP_CLIENT_ID,
          storage: new LocalStorage(),
        })

        export default function SignPage() {
          return (
            <SignPagePlugin
              privy={privy}
              options={{ allowedOrigins: ['https://yourdapp.com'] }}
            />
          )
        }
        ```

        `allowedOrigins` limits which applications can send requests to the signing page. Add every dApp origin that should be able to use the wallet.
      </Step>

      <Step title="Load the plugin with NEAR Connect">
        Initialize `NearConnector` with the manifest you created:

        ```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
        import { NearConnector } from '@hot-labs/near-connect'

        const connector = new NearConnector({
          manifest: '/manifest.json',
          network: 'testnet',
        })
        ```

        That's it! The plugin will now be available in the NEAR Connect modal.
      </Step>
    </Steps>

    <Tip>
      Continue with the [wallet login tutorial](/web3-apps/tutorials/wallet-login) to connect the wallet and use it from your dApp.
    </Tip>
  </Tab>

  <Tab title="Direct Privy">
    Wrap your application with `PrivyProvider` and a custom `NEARxPrivy` context that bridges Privy's authentication with a NEAR account:

    <Github url="https://github.com/near-examples/hello-privy/blob/main/src/App.jsx" language="jsx" />

    <Accordion title="Get a Privy App ID">
      1. Sign up at [privy.io](https://www.privy.io/) and create a new app.
      2. Copy the **App ID** from the dashboard and set it as your `appId` prop.
      3. Configure your allowed login methods and other settings in the Privy dashboard.
    </Accordion>

    ### Context

    The `NEARxPrivy` provider listens to Privy's authentication state. Once the user is logged in, it creates a NEAR wallet (if one doesn't exist yet) and exposes a `nearAccount` instance through context:

    <Github url="https://github.com/near-examples/hello-privy/blob/main/src/context/provider.jsx" language="jsx" />

    | Value         | Type              | Description                                                |
    | ------------- | ----------------- | ---------------------------------------------------------- |
    | `walletId`    | `string`          | The user's NEAR account address                            |
    | `nearAccount` | `Account`         | A `@near-js/accounts` `Account` ready to sign transactions |
    | `provider`    | `JsonRpcProvider` | A read-only RPC provider to query the network              |

    ***

    ### Custom signer

    Privy signs transactions through its embedded wallet via `signRawHash`. The `privySigner` class adapts that API to the interface expected by `@near-js/accounts`:

    <Github url="https://github.com/near-examples/hello-privy/blob/main/src/context/signer.jsx" language="jsx" />

    ***

    ### Signing in and out

    Use `useLogin` and `useLogout` from Privy to open the login modal and sign the user out:

    <Github url="https://github.com/near-examples/hello-privy/blob/main/src/components/navigation.jsx" language="jsx" />

    ***

    ### Call read-only methods

    Use the `provider` from context to call view methods — no login required:

    ```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    const greeting = await provider.callFunction(CONTRACT, 'get_greeting', {})
    ```

    ***

    ### Call change methods

    Use the `nearAccount` from context to call change methods. The transaction is signed silently by Privy's embedded wallet, providing a Web2-like UX:

    ```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    await nearAccount.callFunction({
      contractId: CONTRACT,
      methodName: 'set_greeting',
      args: { greeting: newGreeting },
    })
    ```

    ***

    ### Get balance

    ```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    import { NEAR } from '@near-js/tokens'

    const balance = await nearAccount.getBalance()
    const formatted = Number(NEAR.toDecimal(balance)).toFixed(2)
    console.log(`Balance: ${formatted} Ⓝ`)
    ```
  </Tab>
</Tabs>
