How to extract NFT image URL from metadata URI using JavaScript?

I’m working on displaying NFT data in a table but having trouble getting the actual image URLs. My code loops through NFT data and shows the metadata URI, but I need to fetch the image from that URI.

Here’s what I’m working with:

for (let j=0; j < nftList.length; j++){
    console.log(nftList[j].metadata_uri)
    let tableRow = `<tr>
                    <td>${nftList[j].id}</td>
                    <td>${nftList[j].type}</td>
                    <td><h4>${nftList[j].contract_addr}</h4></td>
                    <td>${nftList[j].metadata_uri}</td>
                </tr>`
    nftTable.innerHTML += tableRow
}

The metadata URI gives me something like: ipfs://bafkreic47njf53ueqgsrtuqh4jtqzcxfheiifilnypfjckvqtyiwefjr2y

But when I access that URL, I get JSON metadata like:

{"name": "CryptoArt #123", "description": "Digital artwork collection", "image": "https://example.com/artwork123.png", "attributes": {"rarity": "rare"}}

I want to extract just the image URL and display it in my table instead of the metadata URI. How can I fetch this data and show the actual image?

Here’s my current setup:

async function loadNFTs(){
    const tokens = await Web3API.wallet.getTokens({chain: 'polygon'}).then(createNFTTable);
}

function createNFTTable(response){
    let nftList = response.result;
    document.getElementById("nftContainer").innerHTML = `<table class="table table-striped" id="tokenTable"></table>`;
    const nftTable = document.getElementById("tokenTable");
    const headerRow = `<thead><tr><th>Token ID</th><th>Contract Type</th><th>Address</th><th>Image</th></tr></thead>`
    nftTable.innerHTML += headerRow;
    
    for (let j=0; j < nftList.length; j++){
        let tableRow = `<tr>
                        <td>${nftList[j].id}</td>
                        <td>${nftList[j].type}</td>
                        <td><h4>${nftList[j].contract_addr}</h4></td>
                        <td>${nftList[j].metadata_uri}</td>
                    </tr>`
        nftTable.innerHTML += tableRow
    }
}

You’ll need to handle async requests since fetching metadata requires network calls. I hit this exact issue last year building an NFT gallery. Convert your createNFTTable function to work with promises. Use Promise.all() to fetch all metadata at once - way faster than doing it one by one. For each metadata_uri, grab the JSON and pull out the image field. IPFS URLs need gateway conversion - I swap ipfs:// with https://gateway.pinata.cloud/ipfs/ since it’s more reliable. Watch out for metadata missing image fields or returning null values. Always add fallbacks or your table will break. Show loading states too - network requests take time, especially with slow IPFS gateways. Wrap your fetch() calls in try-catch blocks and maybe add timeouts for URIs that hang.

Oh this is interesting! I’ve been working with similar stuff lately and ran into the same headache. You’re stuck at the metadata layer and need to dig deeper for the actual image URLs?

I’m curious - are all your metadata URIs following the same pattern? All IPFS links or some regular HTTP URLs mixed in? That might affect how you handle the fetching.

When you access that IPFS URL and get the JSON back, are you converting the ipfs:// protocol to a gateway URL first? I had to use something like https://ipfs.io/ipfs/ + the hash part to actually fetch the data.

Have you tried adding an async fetch inside your loop yet? Fetch each metadata_uri, parse the JSON response, then grab the image property. You’d need to make your createNFTTable function async too since you’ll be doing network requests.

One thing that might trip you up - what happens if some metadata URIs are broken or the image field is missing? Planning to handle those edge cases or just show a placeholder?

Another thought - since you’re doing this in a loop, you might want to consider the performance impact of multiple concurrent requests. Thought about batching them or adding rate limiting?

What’s your experience level with promises and async/await? That’s gonna be key for making this work smoothly.

Grab the metadata JSON first, then pull out the image URL. Add await fetch(nftList[j].metadata_uri).then(res => res.json()).then(data => data.image) in your loop and make the function async. Just remember IPFS URLs need different handling.