Part 2: Fetch an NFT from OpenSea

Now that you've set up the bones of an NFT display website, you'll want to update the code to take a few inputs, call the OpenSea API, and render some information about an NFT.

Get an OpenSea API Key

First, you'll need an OpenSea API Key. Follow this guide to get one.

Find an NFT to display

Go to the OpenSea website and click around to find a NFT you want to display. For this tutorial, we'll be using Pudgy Penguins and you'll be displaying the first NFT in the collection.

Note: If you look at this sample Pudgy Penguin URL (https://opensea.io/assets/ethereum/0xbd3531da5cf5857e7cfaa92426877b022e612cf8/1) -- the end of the path is in the format chain/contractAddress/tokenId, which is OpenSea's way of uniquely identifying a particular NFT.

For the rest of the exercise, we'll use the values:

  • contractAddress: 0xbd3531da5cf5857e7cfaa92426877b022e612cf8
  • tokenId: 1

Update your code

Now that you've chosen the NFT to display, you can update the code to do two things:

  1. take contractAddress and tokenId as inputs
  2. call the OpenSea NFT API to fetch metadata for this NFT and display it.

On our website, you'll likely want to display a few things:

  • name
  • description
  • collection
  • traits

Here's the updated code:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My NFT Display Website</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin: 20px;
        }

        #image-container {
            margin-top: 20px;
        }

        #additional-info {
            margin-top: 20px;
            text-align: left;
            /* Align text to the left */
        }

        #additional-info p,
        #additional-info ul {
            max-width: 400px;
            /* Adjust this value to control the text width */
            margin: 0 auto;
            /* Center the text within the specified width */
        }

        #additional-info ul {
            list-style: none;
            /* Remove bullet points from the unordered list */
            padding: 0;
        }

        #additional-info span {
            display: inline-block;
            /* Display traits as inline elements */
            margin-right: 0;
            /* No spacing between traits */
        }
    </style>
</head>

<body>
    <h1>My NFT Display Website</h1>

    <!-- Input fields for contract address and token ID -->
    <label for="contractAddress">Contract Address:</label>
    <input type="text" id="contractAddress" placeholder="Enter contract address">

    <label for="tokenId">Token ID:</label>
    <input type="text" id="tokenId" placeholder="Enter token ID">

    <button onclick="fetchImage()">Load Image</button>

    <div id="image-container"></div>
    <div id="additional-info"></div>

    <script>
        function fetchImage() {
            // Replace 'YOUR_API_KEY' with your actual OpenSea API key
            const apiKey = 'YOUR_API_KEY';

            // Get contract address and token ID from input fields
            const contractAddress = document.getElementById('contractAddress').value;
            const tokenId = document.getElementById('tokenId').value;

            // OpenSea API Endpoint for fetching NFT metadata for a single NFT: https://docs.opensea.io/reference/get_nft
            const apiUrl = 'https://api.opensea.io/api/v2/chain/ethereum/contract/' + contractAddress + '/nfts/' + tokenId;
            console.log(apiUrl);

            // Make a fetch request to the API with headers
            fetch(apiUrl, {
                headers: {
                    'X-API-KEY': `${apiKey}`,
                    'Content-Type': 'application/json',
                    // Add any other headers required by your API
                },
            })
                .then(response => response.json())
                .then(data => {
                    if (data.nft && data.nft.image_url) {
                        const imageUrl = data.nft.image_url;

                        // Display the resized image in the #image-container div
                        const imageElement = new Image();
                        imageElement.src = imageUrl;
                        imageElement.alt = 'API Image';

                        // Set the maximum width and height for the image
                        const maxWidth = 400; // Adjust this value as needed
                        const maxHeight = 400; // Adjust this value as needed

                        // Ensure the image is loaded before calculating dimensions
                        imageElement.onload = function () {
                            const aspectRatio = imageElement.width / imageElement.height;

                            // Resize the image while maintaining aspect ratio
                            if (imageElement.width > maxWidth) {
                                imageElement.width = maxWidth;
                                imageElement.height = maxWidth / aspectRatio;
                            }

                            if (imageElement.height > maxHeight) {
                                imageElement.height = maxHeight;
                                imageElement.width = maxHeight * aspectRatio;
                            }

                            // Clear previous content and append the resized image
                            document.getElementById('image-container').innerHTML = '';
                            document.getElementById('image-container').appendChild(imageElement);

                            // Display additional text fields below the image
                            const additionalInfoElement = document.getElementById('additional-info');
                            additionalInfoElement.innerHTML = `
                                <p><strong>Name:</strong> ${data.nft.name}</p>
                                <p><strong>Description:</strong> ${data.nft.description}</p>
                                <p><strong>Collection:</strong> ${data.nft.collection}</p>
                                <p><strong>Traits:</strong> ${data.nft.traits.map(trait => `<span><strong>${trait.trait_type}:</strong> ${trait.value}</span>`).join(',')}</p>
                            `;
                        };
                    } else {
                        console.error('Invalid API response format.');
                    }
                })
                .catch(error => {
                    console.error('Error fetching image:', error);
                });
        }
    </script>
</body>

</html>

The only modification you need to make is at Line 66, where you'll add your OpenSea API key:

// Replace 'YOUR_API_KEY' with your actual OpenSea API key
const apiKey = 'YOUR_API_KEY';

Note: the OpenSea API returns the NFTs image (imageUrl) in a specific size format, so we added some resizing logic in Javascript to make sure it looks good.

Test it!

Now that the code is updated, pull up your web page and enter in the Contract Address and Token ID. Once you click the "Load NFT" button, you'll see something like this:

Congratulations! You've just created a website that leverages the OpenSea API to display metadata for any NFT on Ethereum.