How to build an NFT marketplace

How to build an NFT marketplace

Full Stack Product Engineer at NFTPort

As the popularity of NFTs grows, so does the demand for great NFT marketplaces. If you’re looking to build your own NFT marketplace (similar to OpenSea or Rarible) but don’t know where to start, you’ve come to the right place.

In this tutorial, we’ll take you through the entire creation of an NFT marketplace. Learn everything from creating your own contracts to minting NFTs at scale, pulling reliable NFT data into your marketplace from multiple blockchains, and putting it all together into a successful marketplace.

The must-have features & functions of an NFT Marketplace

Before getting into building our own marketplace, let’s take a quick look into what exactly we will need to build.

The most important aspects of every NFT marketplace are:

  • reliable, high-quality NFT data
  • ease to mint NFTs
  • great search functionality & ability to verify the originality of NFTs

In order to make the marketplace work, we will also need to add functions such as:

  • connecting a crypto wallet
  • mint NFTs & create listing
  • create an in-depth search functionality with filters
  • bid & buy

Using NFT APIs as building blocks

In general, you have two options to go about building your own marketplace: Build the NFT infrastructure in-house (the slow method) or use NFT Minting and Data APIs to put it all together (the fast method).

As developers, we tend to prefer figuring things out on our own, so building everything from scratch may sound like a good idea at first. But in reality, developing blockchain and NFT applications is very different from hacking together a project in Web2. Building in Web3 from scratch is harder, time-consuming, and expensive, as you’d need to cover Solidity, Web3.js, GraphQL, nodes, IPFS, etc. You’d also need to develop your own indexers etc. to manage your NFT infrastructure. As a result, it would take your whole team months of hard work before you’re ready to launch your marketplace.

So, for obvious reasons, we at NFTPort are all about being lean. When we first tried to build our own NFT projects a few years back, we quickly found out that figuring out all the nooks and crannies in the NFT infrastructure ecosystem is a massive hassle. So we decided to focus all our strengths on building the best NFT infrastructure and APIs to help fellow developers build their NFT projects a lot faster.

In general, to put together a marketplace, you’ll need to learn how to:

  • Create and list NFTs (by using NFT minting API)
  • Fetch all data related to the NFTs (by using NFT Data API)
  • Deliver reliable service for your users as the user base grows, while shipping awesome extra security features (by using Enhanced APIs)
  • How to do this on multiple chains and networks (by using an infrastructure provider that covers multiple blockchains)

With reliable and easy-to-use APIs in our hands, we can put together an NFT marketplace with just a few steps in a relatively short amount of time.

Excited to see it all in action?

Let’s dive right in 🏊🏻‍♂️

Step 1: Get your free API key

First things first, sign up for NFTPort for free and copy your API key from the "API key" section.

Step 2: Deploying your own contract

Before anything else, we need to create some NFT contracts so that we can start playing around with the lifecycle of an

1. Choose the blockchain you want to mint to

Before you can start minting NFTs, you need to choose a blockchain for it. NFTPort supports Polygon, Solana and Ethereum (mainnet),  and Görli (testnet). How do you decide which one is right for you?

  • Ethereum has been the default for a long time. Users perceive it to be high-status and secure; almost every wallet and NFT app support it. However, it is also expensive -- it can go above $10 just to mint a single NFT -- and transactions can take minutes to be finalized.
  • Polygon is a layer-2 chain that brings costs down to a few cents per minted NFT and transactions are faster. It is directly compatible with Ethereum, so it is easy for apps to integrate this, and in fact many have. The largest marketplaces like OpenSea support Polygon.
  • Solana is not compatible with Ethereum but has its own benefits: transactions are very fast (sub-second) and almost too cheap to meter. It's not universally supported like Ethereum, but it's seeing rapid adoption now.

2. Pick the type of contract flow that suits your use case

Once you’ve chosen the blockchain, you need to choose the contract type. There are two types of contracts for minting – collection contracts and product contracts.

  1. Collection contracts are typically used to launch NFT collections on NFT marketplaces, and therefore it is the collection type we will be using in this tutorial. The maximum supply of tokens is fixed at contract deployment time (e.g. 10,000 NFTs), and users mint the NFTs on a minting website (dApp) that the developer (you) have set up. That means the user needs to be advanced enough to sign a transaction with their wallet (more on that in a bit).
  2. Product contracts allow the end-user to mint on-demand using our REST APIs and are therefore more flexible. The total number of NFTs in the collection is not limited: you can mint more whenever you like. To send an NFT to a wallet, you don't need to ask the user to sign the transaction, which makes for a simpler user experience.

We explain the contract types and NFT minting in more detail in the NFT Minting Tutorial – head over there for more explanations and examples.

3. Deploy your contract

For this example, let’s deploy a collection contract on Ethereum. For this, we’ll need to:

Upload the asset of each NFT to IPFS:

const fs = require('fs');
const fetch = require('node-fetch');
const FormData = require('form-data');

const form = new FormData();
const fileStream = fs.createReadStream('image.jpg');
form.append('file', fileStream);

const options = {
  method: 'POST',
  body: form,
  headers: {
    "Authorization": "API-Key-Here",

fetch("https://api.nftport.xyz/v0/files", options)
  .then(response => {
    return response.json()
  .then(responseJson => {
    // Handle the response

Which should return a successful response like the following:

  "response": "OK",
  "ipfs_url": "https://ipfs.io/ipfs/QmcjGqcUYA5xVSwRb6sBpxYqED5L7avxcncnybueb4ismf",
  "file_name": "NFTs.png",
  "content_type": "image/png",
  "file_size": 1755632,
  "file_size_mb": 1.6743

Or you can also upload a directory of metadata files to IPFS. For this, we will first need to create the metadata files and put them into a single directory, e.g Metadata. Here’s an example of a metadata file:

  "name": "Lamp 1",
  "description": "My amazing Lamp",
  "image": "https://ipfs.io/ipfs/bafkreihqubrfvvp3vzc7tmqamfbodvcevhmnpep6wg6hc3cyrdixkrn25e",
  "attributes": [
      "trait_type": "Lamp Type",
      "value": "Classic"

Next, we can write up some simple code and upload all the files from the Metadata directory to an IPFS directory.

const fs = require('fs');
const path = require('path')
const request = require('request');

API_KEY = "YOUR_API_KEY" // Replace with your API key
METADATA_DIRECTORY_PATH = "Metadata" // Replace with your path to directory folder containing metadata json files

function isJson(filename) {
return filename.split('.').pop() === "json"

function getFileStreamForJSONFiles(directory) {
const jsonArray = []
fs.readdirSync(directory).forEach(file => {
    if(!isJson(file)) {
    const fileData = fs.createReadStream(path.join(directory, file));
return jsonArray

function sendRequest(metadataFileStreams, apiKey) {
    const options = {
        url: 'https://api.nftport.xyz/v0/metadata/directory',
        headers: { "Authorization": apiKey }
    const req = request.post(options, function (err, resp, body) {
        if (err) {
            console.error('Error: ' + err);
        } else {
            console.log('Response: ' + body);
    const form = req.form();
    metadataFileStreams.forEach(file => {
        form.append('metadata_files', file);


metadataFileStreams = getFileStreamForJSONFiles(METADATA_DIRECTORY_PATH)
sendRequest(metadataFileStreams, API_KEY)

Next comes the most critical part – deploying your collection contract. With the following code snippet it is possible to deploy a collection contract on Ethereum. If you are just validating the product, you can do it first on Polygon or Ethereum Rinkeby, as deploying to Ethereum Mainnet requires to be subscribed to the Growth plan. With the Free plan you are able to do 5 free contract deployments to Polygon or Rinkeby.

First we need to define our contract specs:

const contract = {
  "chain": "ethereum",
  "name": "CryptoLamps",
  "symbol": "CLAMP",
  "max_supply": 5000,
  "mint_price": 0.1,
  "tokens_per_mint": 10,
  "royalties_share": 500,
  "royalties_address": "0x5FDd0881Ef284D6fBB2Ed97b01cb13d707xxxx",
  "owner_address": "0x5FDd0881Ef284D6fBB2Ed97b01cb13d707f9xxxx",
  "treasury_address": "0x5FDd0881Ef284D6fBB2Ed97b01cb13d707f91e42",
  "public_mint_start": "2022-02-08T11:30:48+00:00",
  "metadata_updatable": true,
  "base_uri": "ipfs://bafybeif2sdh3a2ir5uy74ziwyhufkpd3upysrabpy22ziyeomvaql63idu/",
  "prereveal_token_uri": "ipfs://bafkreiedsysj5xeyulisdjrjh37tz2y47dlwzwiwfagmqng3melxtigaie",
  "presale_mint_start": "2022-02-08T11:30:48+00:00",
  "presale_whitelisted_addresses": [

Let’s break the contract info down:

The required parts are chain , name, symbol, max_supply, tokens_per_mint, owner_addres, treasury_address, and public_mint_start_date. By setting chain to "rinkeby" you can do a test deployment. Remember that setting metadata_updatable to true will allow you to later modify the metadata.

After getting you contract details ironed out, lets get it deployed. For this we just need to run one command:

const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json', Authorization: 'Your-API-key'},
  body: JSON.stringify(contract)

fetch('https://api.nftport.xyz/v0/contracts/collections', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

If everything went successfully, you should see a similar response:

  "response": "OK",
  "chain": "ethereum",
  "transaction_hash": "0xd07b2797c08656ac26391fe9f8119c41e9bf47ce6dbd5e07eec142f2b77a7152",
  "transaction_external_url": "https://polygonscan.com/tx/0xd07b2797c08656ac26391fe9f8119c41e9bf47ce6dbd5e07eec142f2b77a7152",
  "owner_address": "0x5FDd0881Ef284D6fBB2Ed97b01cb13d707f91e42",
  "name": "CryptoLamps"

Save the transaction hash stored in transaction_hash as this can help you validate you contract deployment on a block explorer like Polygonscan, Etherscan, or Rinkeby Testnet Explorer.

For detailed overview and code examples of this step, please check our Deploying an NFT Collection Docs.

Step 3: Minting your first NFTs

To mint NFTs, you’ll have two options: Easy Minting and Customizable Minting. We’ll briefly cover them both here, but for more in-depth explanation and examples, please refer to NFT Minting tutorial.

For NFT marketplace, we’ll be using Collections (customizable minting) to be able to mint NFTs to the contract we created in the previous step.

  • Easy Minting is the simplest form of minting and mints a single NFT. One simple API call is all that it takes to turn anything into an NFT. You would simply need to provide a name for your NFT, a description for your NFT, the chain where the NFT will be minted, the wallet address where to mint the NFT, the file URL or upload the file that you want to turn to an NFT. All file types are supported including binary, images, GIFs, videos, audio, documents, text, etc.Once you send your API request, Easy Minting will automatically upload the file to IPFS; create a metadata file (JSON) with the file's name, description and URL and uploads it to IPFS; and finally create the NFT.
  • Customizable Minting mints an NFT to your previously deployed contract for NFT products. This minting consists of multiple steps and enables you to customize the whole minting flow for your exact needs.
  1. First, you need contract_address using Deploy a contract for NFT products.
  2. Secondly, you need metadata_uri using Upload metadata to IPFS.
  3. After minting, the NFT will appear in the mint_to_address wallet.
curl --request POST \
--url https://api.nftport.xyz/v0/mints/customizable \
--header 'Authorization: ' \
--header 'Content-Type: application/json' \
--data '{
"chain": "ethereum",
"contract_address": "0xC8D297D7b496f86673551c933815B47973FCzzzz",
"metadata_uri": "ipfs://bafkreiedsysj5xeyulisdjrjh37tz2y47dlwzwiwfagmqng3melxtigaie",
"mint_to_address": "0x5FDd0881Ef284D6fBB2Ed97b01cb13d707f9xxxx"

For detailed code examples, have a look at the Customizable Minting API guide.

Step 4: Connecting to a Web3 wallet

After you have minted some NFTs, you can see the results in your wallet by enabling wallet support in your marketplace.

To get you started, let’s start with the most popular wallet currently out there – MetaMask. This part will need some JavaScript and HTML skills, but no prior blockchain experience.

The full details to connect to MetaMask can be found in our How to connect Metamask with your app guide. The main steps include:

  • Creating a MetaMask wallet
  • Installing Node.js
  • Creating a website and hosting it

Install the following dependencies:

npm install @metamask/onboarding
npm install express
npm install path

Create an HTML page. For example, on your index.html add the following parts (code can be found HERE):

Next, update your backend code to run the following page. For this, let’s create an app.js file:

// app.js

const express = require("express")
const path = require("path");
const app = express();
const port = 3000;
// Setting path for directory 
const static_path = path.join(__dirname, "");
app.use(express.urlencoded({ extended: true }));
// Handling request 
app.post("/wallet", (req) => {
   console.log(req.body.address) // This is the user's wallet address
// Server Setup
app.listen(port, () => {
   console.log(`server is running at ${port}`);

Use the next command in your terminal to serve the HTML page and run the app:

node app.js

This is how it finally looks. Every time a user clicks the "Connect" button, a POST request is made and the wallet address is retrieved from the wallet after it has been connected to the application.

NB! Please remember as you are enabling direct connections with a user's wallet, make sure all communication between the browser and backend application uses the most secure practices, for you have set up HTTPS for starters.

Step 5: Adding NFT Data to your marketplace

Now that you know how to create NFTs and access wallet data, let’s add more sauce to the mix.

The backbone of any NFT marketplace is the NFT data that is available to it. To make your marketplace useful, you’d probably want to add data such as NFT metadata, transactional data (different transaction events such as mint, buy, sell, transfer, etc.), sales statistic (such as volume, total_supply, total_mints, floor_price etc.), as well as current and historic owners of a given NFT or collections.

NFTPort Data API lets you access all of the above-mentioned data Ethereum and Polygon from three main categories that are all much needed for a marketplace:

Contracts, Metadata & Assets

  • Retrieve all NFTs – Returns all ERC721 and ERC1155 NFTs that have been minted on a given chain, including their metadata.
  • Retrieve NFT details – Returns details for a given NFT, including metadata.
  • Retrieve contract NFTs – Returns all NFTs for a given contract address, including their metadata.

All ‘Contracts, Metadata & Assets’ API endpoints can be set to include NFT metadata.

Ownership data

Transactional data

All transactional data API endpoints can be set to include transactions such as transfer, burn, mint, and sale, or all.

You can use these endpoints in various ways to make your marketplace actionable and useful, e.g. showing details of all the NFTs in a collection, or pulling in the latest floor price or current owners of an NFT.

For detailed overview and examples of how to get NFT data from multiple chains into your product, please refer to Multi-chain NFT API: How to get NFT Data.

For our NFT Marketplace use case, let’s look into a few examples. For this purpose, we created a small sneak peek in the following sandbox. As you can see, you are able to fetch all contracts with a simple JS fetch snippet:

fetch("https://api.nftport.xyz/v0/nfts?chain=ethereum", {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      Authorization: APIKEY

Or fetch NFT details with just the contract and token id:

        method: "GET",
        headers: {
          "Content-Type": "application/json",
          Authorization: APIKEY

Looking into the result of the NFT details endpoint, you’ll see that NFTPort API you will get a lot of data, so let’s break it down.

The nft contains all key information about a given NFT, such as metadata and assets. In order to ensure the highest availability, we are caching the assets to make sure you’ll get to show them in your product immediately without any lag. We are also live indexing new blocks on the chain as they are published, which means that after an NFT token with an ERC721 or ERC1155 is created, we index the ownership, assets, and transactions to give you the freshest NFT data at all times.

  "response": "OK",
  "nft": {
    "chain": "ethereum",
    "contract_address": "0x9451522d367fbb5269c37819e77444e0d9ddf0d5",
    "token_id": "21",
    "metadata_url": "ipfs://bafkreidytsas5lftv24imhiynz4r2o3kxyfmzrq2vpjohhe6tq3vu45e7u",
    "metadata": {
      "name": "ULTRAPASS (PRE-REVEAL)",
      "description": "A members-only community of 1,000 NFT collectors with access to events, curated drops, and more.",
      "external_url": "https://ultradao.org/ultrapass",
      "attributes": [
          "trait_type": "State",
          "value": "Pre-Reveal"
      "image": "ipfs://bafybeifhno7xmwhvy73ceclwmenarj2ko5cor2kia3ivdrybmzghgblvay"
    "file_information": {
      "height": 4000,
      "width": 4000,
      "file_size": 7909980
    "file_url": "ipfs://bafybeifhno7xmwhvy73ceclwmenarj2ko5cor2kia3ivdrybmzghgblvay",
    "animation_url": null,
    "cached_file_url": "https://storage.googleapis.com/sentinel-nft/raw-assets/85bddad053115b4d6f4bcb2df2f51ed5acbd780f0d0aff218929956965621301.jpeg",
    "cached_animation_url": null,
    "mint_date": "2022-08-25T12:15:07",
    "updated_date": "2022-08-25T12:22:04.183144"
  "owner": "0x9a1a94e850fa0348dc64c396dfaf8209289a94f0",
  "contract": {
    "name": "ULTRAPASS by UltraDAO",
    "symbol": "ULTRA",
    "type": "ERC721",
    "metadata": null

With a bit of CSS, you can show all the relevant NFT data in your marketplace like the example below:

Putting it all together into a marketplace

By now we have covered the three main building blocks of an NFT marketplace – minting NFTs, adding wallet connections, and showing relevant NFT data and sales stats.

Next, we want to turn it all into a visually pleasing marketplace with a great user experience. We’re not going to cover all the web design and UX aspects in this tutorial, but we recommend adding some ’must-have’ features to make the marketplace as user-friendly as possible:

  • Search function by collection names, NFTs, users
  • Browse option by categories (art, music, domain names, etc.)
  • Overview of the trending collections/NFTs currently trading
  • Overview of new collections

Once you’re ready to give it a go, grab your free API key and start building!

If you need any help along the way, make sure to join our Discord to ask any questions and connect with other NFT developers across the globe!

About NFTPort

The Stripe for NFTs — One-Stop, Simple and Developer-First NFT Infrastructure & APIs which Help Developers bring their NFT application to market in hours instead of months. We take care of the NFT infrastructure so you can focus on your application. By devs, for devs.

Website | Blog | Discord Community | Twitter | Docs | Contact Us

Similar Posts

Relevant Posts

Bring Your NFT Project to Life

Get Free API Key