Integrating NEAR Protocol into a React or Next.js application is straightforward with the near-api-js library and the NEAR Wallet Selector. This guide covers the complete integration from wallet connection to contract interactions.

Setup

Install the required packages:

npm install near-api-js @near-wallet-selector/core @near-wallet-selector/my-near-wallet @near-wallet-selector/meteor-wallet

The wallet selector handles connection to multiple NEAR wallets (MyNearWallet, Meteor Wallet, Ledger, etc.) with a unified interface.

Wallet Connection

Create a NEAR context provider for your React app:

import { setupWalletSelector } from '@near-wallet-selector/core';
import { setupMyNearWallet } from '@near-wallet-selector/my-near-wallet';
import { setupMeteorWallet } from '@near-wallet-selector/meteor-wallet';

const selector = await setupWalletSelector({
  network: 'mainnet',
  modules: [
    setupMyNearWallet(),
    setupMeteorWallet(),
  ],
});

const modal = setupModal(selector, {
  contractId: 'your-contract.near',
});

Display the modal on a button click: modal.show(). The selector manages the connection state and exposes a wallet object for signing transactions.

Reading Contract State

View calls (read-only) do not require wallet connection:

import { providers } from 'near-api-js';

const provider = new providers.JsonRpcProvider({
  url: 'https://rpc.mainnet.near.org',
});

const result = await provider.query({
  request_type: 'call_function',
  account_id: 'your-contract.near',
  method_name: 'get_data',
  args_base64: Buffer.from(JSON.stringify({ key: 'value' })).toString('base64'),
  finality: 'final',
});

const data = JSON.parse(Buffer.from(result.result).toString());

Writing Transactions

Change calls require a signed transaction from the connected wallet:

const wallet = await selector.wallet();

await wallet.signAndSendTransaction({
  signerId: accountId,
  receiverId: 'your-contract.near',
  actions: [
    {
      type: 'FunctionCall',
      params: {
        methodName: 'set_data',
        args: { key: 'value', data: 'payload' },
        gas: '30000000000000',
        deposit: '0',
      },
    },
  ],
});

Next.js Specific Patterns

NEAR wallet selector uses browser APIs and cannot run server-side. Use dynamic imports with ssr: false for wallet-related components:

import dynamic from 'next/dynamic';

const WalletButton = dynamic(
  () => import('../components/WalletButton'),
  { ssr: false }
);

For Next.js App Router, mark wallet components with 'use client' at the top. Store wallet selector initialization in a React context that lazy-initializes on mount.

Production Patterns

Cache contract reads using SWR or React Query to avoid unnecessary RPC calls. NEAR RPCs support read queries up to about 100/second per IP before rate limiting. For high-traffic apps, consider a backend proxy to the NEAR RPC.

Handle wallet disconnection gracefully: users can disconnect from the wallet extension outside your app. Check selector.isSignedIn() on each page load and handle the disconnected state explicitly.

For testnet development, use network: 'testnet' and the testnet wallet at testnet.mynearwallet.com. Create separate contract IDs for testnet and mainnet using environment variables.