Where to store NFT metadata and where to set the price?

Thank you @abcoathup for this awesome tutorial! A few questions, if you or any good member can please indulge me…

  1. I would like to make a JPG or any file into an NFT. Where can I specify the file (jpg, gif, etc.) from which you would create the NFT from? From my understanding, if this were an actual transaction, the file would ideally be stored in an IPFS.
  2. Where in this tutorial would I specify the COST of the NFT? This is in the smart contract correct? And if so, please provide a sample code in full and in which file of this tutorial I could use to simulate this.

Apologies for the beginner questions… Been only about 2 weeks since I’ve been studying this and I have no formal educational background in computer science.

1 Like

Hi @m3nt0r,

Welcome to the community :wave:

You can use centralized metadata, where you create an API to server the metadata. This is lower cost for minting. The metadata can even use IPFS for the image.

Or you can store the entire metadata in decentralized storage such as IPFS. When you mint a token you will need to store the IPFS hash as the token URI (assuming the marketplaces you want to use support this). Due to the storage onchain, this is higher cost to mint.

You can use existing NFT marketplaces to sell NFTs such as OpenSea.

Alternatively you can create your own sale contract. I recommend only keeping functionality required for the life of the contract in the contract. Assuming that sales aren’t for the life of the token, any sale functionality should be in a separate contract.


Thank you for this! @abcoathup

1 Like

@abcoathup on point1 above. I’m investigating the best place for my metadata to live. It seems like the top recommendations is IPFS. I can’t run an IPFS node so I’m looking at pinning services. I looked at Pinata but it seems to have a node.js dependency (I might be wrong here) and I’m using Laravel. Do you have any recommendations on other pinning services that would work better in a PHP/Laravel framework?

also–I’m incredibly impressed by your platform. the contracts, forum and articles are perfect for someone just getting started with Ethereum dev. This is what makes for a loyal follower. Great job.

1 Like

Hi @scottsuhy,

For decentralized metadata then you can use IPFS. If you know the metadata for all the tokens at time of deployment, you can deploy a directory of JSON files to IPFS, and then use ipfs://qmhash/ as your baseURI and then the token URI will be the concatenation of the baseURI and the tokenID.

As for a pinning service, I thought you could use Pinata through a web interface to upload and pin items.

I am not familiar with Laravel.

Glad to hear that you are enjoying the community. Feel free to answer other peoples questions to help us grow the community.

1 Like

Thanks @abcoathup on Pinata… it’s pretty incredible. I was confused because all of their examples use node.js but you can use other standard mechanisms just as easily. Here is a simple upload with dropzone and creation of metadata example.

<!doctype html>
    <link rel="stylesheet" href="https://rawgit.com/enyo/dropzone/master/dist/dropzone.css">

    <form action="" method="POST" enctype="multipart/form-data" class="dropzone " role="form">        
        <div class="dropzone" id="dropzone"></div>
        <div class="dropzonePreview dropzone"></div>
    <div id="response_from_upload"></div>
    <input id="clickMe" type="button" value="Create JSON for metadata" onclick="pinJSONToIPFS2();" />
    <div id="response_from_upload_json"></div>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/min/dropzone.min.js"></script>


        Dropzone.autoDiscover = false;
        const pinataApiKey = STORE THESE ON A SERVER;
        const pinataSecretApiKey = STORE THESE ON A SERVER;

            previewsContainer: ".dropzonePreview",
            url: "https://api.pinata.cloud/pinning/pinFileToIPFS",
            //maxFilesize: 2, 
            //maxFiles: 1,
            acceptedFiles: ".jpeg,.jpg,.png",
            //uploadMultiple: true,
            //parallelUploads: 1,
            headers: {                
                pinata_api_key: pinataApiKey, 
                pinata_secret_api_key: pinataSecretApiKey,
            init: function() {
                this.on("sending", function(file, xhr, formData){                        
                        const metadata = JSON.stringify({
                            name: 'testname',
                            keyvalues: {
                                exampleKey: 'exampleValue'
                        formData.append('pinataMetadata', metadata);
            error: function(file, message) {
                console.log("ERROR: ", message.error);
            success:function(file, response) {                                        
                console.log("SUCCESS: ", response);                
                $('#response_from_upload').html("Response: " + response.IpfsHash); 

        function pinJSONToIPFS2() {              

            const obj = {
                //not stored on ipfs, just used at pinata for search queries and naming                
                "pinataOptions": {
                    "cidVersion": 1
                "pinataMetadata": {
                    "name": 'ItemStatus.json',
                    "keyvalues": {
                        "ItemID": 'Item001',
                        "CheckpointID": 'Checkpoint002',
                        "Source": 'CompanyA',
                        "WeightInKilos": 5.25
                "pinataContent": {
                    "itemName": 'exampleItemName',
                    "inspectedBy": 'Inspector001',

                type: 'POST',
                url: "https://api.pinata.cloud/pinning/pinJSONToIPFS",
                headers: {                
                    pinata_api_key: pinataApiKey, 
                    pinata_secret_api_key: pinataSecretApiKey,
                data: JSON.stringify(obj),
                contentType: "application/json; charset=utf-8",
                traditional: true
            }).done(function(data) {