Trying to get nftMetadata() for the last 100 nfts in a wallet, but running into rate limits

Hello :slight_smile:

import Moralis from "moralis";
import { EvmChain } from "@moralisweb3/evm-utils";

export default async function handler(req, res) {
  const chain = EvmChain.ETHEREUM;
  await Moralis.start({ apiKey: process.env.MORALIS_API_KEY });

  async function getNftMetaData(address, chain, tokenId) {
    console.log("Address: ", tokenId);

    const response = await Moralis.EvmApi.nft.getNFTTransfers({
      address,
      chain,
      tokenId,
    });

    const priceInEth = (
      Number(response.result[0].value) / 1000000000000000000000000000000000000
    ).toFixed(3);

    if (priceInEth > 0) {
      return { price: priceInEth };
    } else return { price: null };
  }

  async function getAllNftMetaData() {}

  const response = await Moralis.EvmApi.nft.getWalletNFTs({
    address: req.body.user.address,
    chain,
  });

  const newResult = await Promise.all(
    response.data.result.map(async (nft) => {
      const nftData = await getNftMetaData(
        nft.token_address,
        chain,
        nft.token_id
      );

      return {
        lastNftPrice: nftData,
        ...nft,
      };
    })
  );
  
  const newResponse = {
    ...response,
    data: { ...response.data, result: [...newResult] },
  };

  res.status(200).json(newResponse);
}

I’m trying to get all the nfts for an address (just the first page), then get the data for each of those nfts (to get the last price if any), in the end sending it all combined as a response, last 100 nfts list for a wallet including last price

The code works ok for a few nfts, but runs into a rate limit error after that

Any adivce?

you can try to add a delay between requests, you can try with a delay up to a second

1 Like

Like this? It’s not working

import Moralis from "moralis";
import { EvmChain } from "@moralisweb3/evm-utils";

export default async function handler(req, res) {
  const chain = EvmChain.ETHEREUM;
  await Moralis.start({ apiKey: process.env.MORALIS_API_KEY });

 unction delay(t) {
  return new Promise((resolve) => setTimeout(resolve, t));
 }

  async function getNftMetaData(address, chain, tokenId) {
    await delay(100);
    const response = await Moralis.EvmApi.nft.getNFTTransfers({
      address,
      chain,
      tokenId,
    });

    const priceInEth = (
      Number(response.result[0].value) / 1000000000000000000000000000000000000
    ).toFixed(3);

    if (priceInEth > 0) {
      return { price: priceInEth };
    } else return { price: null };
  }

  async function getAllNftMetaData() {}

  const response = await Moralis.EvmApi.nft.getWalletNFTs({
    address: req.body.user.address,
    chain,
  });

  const newResult = await Promise.all(
    response.data.result.map(async (nft) => {
      const nftData = await getNftMetaData(
        nft.token_address,
        chain,
        nft.token_id
      );

      return {
        lastNftPrice: nftData,
        ...nft,
      };
    })
  );
  const newResponse = {
    ...response,
    data: { ...response.data, result: [...newResult] },
  };

  res.status(200).json({ ...response });
}

It still gets the NFT list, but it gets stuck when running map() on them. So it’s not the whole account that is rate-limited

you have to add delay between requests, you may have to use a for and not something that runs concurrently

1 Like

Thanks @cryptokid, using for( in ) worked.

Now it waits too long to get everything.

What I want basically is to get the NFTs an address bought recently ( for example last 20 NFTs bought), together with the required metadata for those NFTs to be able to display them in the front-end, and get the data again each time a user changes the address via an input let’s say.

How should I go about it using the Moralis NFT api?

what is the information that you know at the beginning?

last 20 NFTs bought by a wallet address? from a contract?

1 Like

I know the address to start with. I want to find out last 20 NFTs it bought, then display them.

you could try to use the endpoint specific to nft transfers

Yes. I tried this variant just now. And that response has no NFT metadata like picture and name, so the need to make another query for each incoming transfer, to

url: `https://deep-index.moralis.io/api/v2/nft/${address}/${token_id},

in order to get the picture and name for that particular transferred NFT.

It’s how this problem started, just that before I took all nfts a user had, than afterwards made a query to get the last price on each nft.

If I get the transfer value, I dont have the picture, and if I get the picture I dont have the transfer value, always two queries.

there are so many wallets with more than 100 nfts?

you should be able to get 100 results for a request

1 Like

The one I’m trying as an example has a lot more, but for now it would be ok to work for the first page, 100 results. I’m not iterating pages yet.

Finiliar
Finiliar
Finiliar
Old Lunar Colony Limited
Finiliar
House of Queens Originals
Finiliar
Terraforms
Finiliar
Finiliar
AxiosError
AxiosError
Finiliar
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError
AxiosError

Above is an example of all the returned NFT names

it looks like you got some errors, how did you get the nft names?

1 Like
async function getNftMetaData(address, token_id) {
    console.log("Parameters:", address, token_id);
    const nftMetadata = {
      method: "GET",
      url: `https://deep-index.moralis.io/api/v2/nft/${address}/${token_id}`,
      params: { chain: "eth", format: "decimal" },
      headers: {
        accept: "application/json",
        "X-API-Key": process.env.MORALIS_API_KEY,
      },
    };

    return await axios
      .request(nftMetadata)
      .then(function (response) {
        return response.data;
      })
      .catch(function (error) {
        return error;
      });
  }

Then looping and asking the data if transfer has value, so it’s not even running on all 100 results

 for (const i in nftBuysResult.data.result) {
    const transfer = nftBuysResult.data.result[i];

    if (transfer.value !== "0") {
      console.log(transfer.value);
      getNftMetaData(transfer.token_address, transfer.token_id)
        .then((nftData) => {
          nftDataArray.push(nftData.name);
          console.log(nftData.name);
        })
        .catch((error) => console.log("error"));
    }
  }

maybe you can log more about that error when it says AxiosError

1 Like
 response: {
    status: 429,
    statusText: 'Too Many Requests',

this is the rate limit error, you have to add a delay between requests

1 Like

I consoled the name and also the price from the return, it seems the name is AxiosError, and somehow the price is received ok?

{ name: 'AxiosError', price: '4981000000000000000' }
{ name: 'AxiosError', price: '16690000000000000000' }
{ name: 'SuperRare', price: '1030000000000000000' }