How to create an NFT-gated website
Samina
Posted on April 13, 2022
One of the more dynamic use cases for NFTs is using them as a membership pass to the NFT holders. Let’s assume you want to create a website for your community that is gated by having access to a specific NFT from a collection. You can keep downloadable content or hidden pages by access to the NFT.
In this guide, we will create a website that restricts content based on owning an NFT using React.
You can grab a copy of the final project from our examples organization, check it out here.
Mint an NFT Drop
To create an NFT gated website, we will need either an NFT Collection, NFT Drop, Edition, or an Edition Drop contract already deployed on a blockchain. If you don’t have one created, you can create one using thirdweb’s TypeScript SDK or thirdweb’s dashboard.
If your NFTs are an NFT Drop or Edition Drop contract, set up claim phases before using the claiming functions mentioned later in the guide.
For our example, I am using an NFT Drop contract called Cookie Club for members of the Cookie Club. 🤫
You can view the Cookie Club NFT Drop on the thirdweb dashboard.
Clone the template repository
To get started will use a cra-javascript-template
which already includes a working SDK setup. This template will make it easy to learn and save time when getting started with our project.
If you’d prefer to use your own template, you can install the latest version of our SDK in your project with
npm install @thirdweb-dev/sdk react ethers
oryarn add @thirdweb-dev/sdk react ethers
First, navigate to the cra-javascript-starter GitHub repository and click on "Use this template" to create a copy.
Add the project’s name, description, and other settings, and then clone it locally on your device. Open the directory and run npm install
in your terminal to install all the dependencies.
Setup the blockchain
Inside our src
folder, we will open the index.js
file. We will first change the chain id to the chain of our NFT Drop. For this project, we’ll be using Rinkeby
since our NFT Drop contract is on the Rinkeby testnet.
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { ChainId, ThirdwebProvider } from "@thirdweb-dev/react";
// This is the chainId your dApp will work on.
const activeChainId = ChainId.Rinkeby;
ReactDOM.render(
<React.StrictMode>
<ThirdwebProvider desiredChainId={activeChainId}>
<App />
</ThirdwebProvider>
</React.StrictMode>,
document.getElementById("root")
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
Setup the connect wallet button
In the same folder, there is the app.js
file. In this one, we want to allow our user to connect to the app and then obtain our user’s wallet address. On the front end, we will create a button that lets users connect with MetaMask. When a wallet is connected, it will display the corresponding address.
import { useAddress, useMetamask } from "@thirdweb-dev/react";
import "./styles.css";
const App = () => {
// get address of user & allow them to connect with metamask
const address = useAddress();
const connectWithMetamask = useMetamask();
//if there isn't a wallet connected, display our connect MetaMask button
if (!address) {
return (
<>
<h1>Welcome to the Cookie Club</h1>
<button className="btn" onClick={connectWithMetamask}>
Connect MetaMask
</button>
</>
);
}
// if an address is connected, display address
return (
<div>
<p>Your address: {address}</p>
</div>
);
};
export default App;
Let’s preview what our app looks like and ensure it’s working by running npm start
in the terminal.
Conditionally render content & add an NFT minting button
In the same App.js
file, we will add conditionals that render specific pages based on the connection status of the user. We want the user to be able to mint an NFT from the drop if they don’t already hold an NFT. If the connected user does have one, we will display some congratulatory text.
As an extra, I added a helper function to display our shortened wallet address called truncateAddress
. Feel free to add or omit this as well in your app.
import { useAddress, useMetamask } from '@thirdweb-dev/react';
import { useState, useEffect } from 'react';
import "./styles.css";
const App = () => {
// get address of user & allow them to connect with metamask
const address = useAddress();
const connectWithMetamask = useMetamask();
// add nft Drop contract
const nftDrop = useNFTDrop("0x66463b3C1EBf08b9dE889BCc0A5cbf29dc0e2B7a");
const [hasClaimedNFT, setHasClaimedNFT] = useState(false);
const [isClaiming, setIsClaiming] = useState(false);
// function to claim NFT
const mintNFT = async () => {
try {
setIsClaiming(true);
await nftDrop.claim(1);
setHasClaimedNFT(true);
catch (error) {
setHasClaimedNFT(true);
console.error("Failed to mint NFT", error);
} finally {
setIsClaiming(false);
}
}
//if there isn't a wallet connected, display our connect MetaMask button
if (!address) {
return (
<>
<h1>Welcome to the Cookie Club</h1>
<button className="btn" onClick={connectWithMetamask}>
Connect MetaMask
</button>
</>
);
}
// if the user is connected and has an NFT from the drop, display text
if (hasClaimedNFT) {
return <h2>Congratulations! You have a Cookie NFT! 🍪</h2>;
}
// helper function to truncate the address so it displays in a nice format
function truncateAddress(address) {
return `${address.slice(0, 6)}...${address.slice(-4)}`;
}
//if the user does not have an NFT, show their address and mint an NFT button
return (
<>
<p className="address">
There are no Cookie NFTs held by:{" "}
<span className="value">{truncateAddress(address)}</span>
</p>
<button className="btn mint" disabled={isClaiming} onClick={mintNft}>
Mint NFT
</button>
</>
);
}
export default App;
Add useEffect to check for state changes
Lastly, we want to add a useEffect
function to ensure we are up to date with the latest state of the app. This function triggers every time something in the dependency array changes. For example, if the user’s address or nftDrop
disconnects or changes, we want to refresh and update it accordingly.
import { useAddress, useMetamask, useNFTDrop } from "@thirdweb-dev/react";
import { useState, useEffect } from "react";
import "./styles.css";
export default function App() {
// allow user to connect to app with metamask, and obtain address
const address = useAddress();
const connectWithMetamask = useMetamask();
//
const nftDrop = useNFTDrop("0x66463b3C1EBf08b9dE889BCc0A5cbf29dc0e2B7a");
const [hasClaimedNFT, setHasClaimedNFT] = useState(false);
const [isClaiming, setIsClaiming] = useState(false);
useEffect(() => {
// If they don't have an connected wallet, exit!
if (!address) {
return;
}
const checkBalance = async () => {
try {
const nfts = await nftDrop.getOwned(address);
setHasClaimedNFT(nfts?.length > 0);
} catch (error) {
setHasClaimedNFT(false);
console.error("Failed to get NFTs", error);
}
};
checkBalance();
}, [address, nftDrop]);
const mintNft = async () => {
try {
setIsClaiming(true);
await nftDrop.claim(1);
setHasClaimedNFT(true);
} catch (error) {
setHasClaimedNFT(false);
console.error("Failed to mint NFT", error);
} finally {
setIsClaiming(false);
}
};
//if there isn't a wallet connected, display our connect MetaMask button
if (!address) {
return (
<>
<h1>Welcome to the Cookie Club</h1>
<button className="btn" onClick={connectWithMetamask}>
Connect MetaMask
</button>
</>
);
}
// if the user is connected and has an NFT from the drop, display text
if (hasClaimedNFT) {
return <h2>Congratulations! You have a Cookie NFT! 🍪</h2>;
}
// truncates the address so it displays in a nice format
function truncateAddress(address) {
return `${address.slice(0, 6)}...${address.slice(-4)}`;
}
// if there are no NFTs from collection in wallet, display button to mint
return (
<>
<p className="address">
There are no Cookie NFTs held by:{" "}
<span className="value">{truncateAddress(address)}</span>
</p>
<button className="btn" disabled={isClaiming} onClick={mintNft}>
Mint NFT
</button>
</>
);
}
export default function app;
Link to Project
You can create a copy of this project from our example repository.
Congratulations!
Let’s go! You created an NFT gated membership website using React. Feel free to add some downloadable content or secret updates behind this new page for your NFT community members!
Posted on April 13, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.