How to Make Sure Your Hedera NFT Metadata Is Correct
Small profile pic michiel dec 2022
Jan 09, 2023
by Michiel Mulders
Developer Advocate at Swirlds Labs

NFT metadata has many use cases. One of the most well-known use cases is calculating the rarity of collectible NFTs. However, there are many use cases beyond collecting our digital furry friends. 

You can use NFT metadata for many other purposes:

  • Provenance: Metadata can be used to track the ownership history of an NFT and provide information about its authenticity and origin.
  • Attribution: Metadata can be used to provide information about the creators and rights holders of an NFT. This data can be helpful for artists, photographers, and other creators to control and monetize their work.
  • Licensing: Metadata can be used to specify the terms of use and licensing for an NFT, such as whether it can be resold or used for commercial purposes.
  • Searchability: Metadata can be used to make NFTs more easily searchable and discoverable by users.
  • Interoperability: Metadata can be used to provide information about the format and compatibility of an NFT, which can help with interoperability between different platforms and applications.

To ensure we can cater to all these use cases, Hedera introduced token metadata JSON schemas that try to standardize the structure of token metadata. HIP10 was the first version of such a standard. Now, HIP412 (v2) replaces the HIP10 standard. HIP412 represents the "token metadata JSON schema V2". 

So, why do we need the token metadata JSON schema V2, how can you implement it, and what does the token metadata JSON schema look like? Let's get started.

What is the Token Metadata JSON schema V2, and why use it?

The HIP412 specification provides the second version of our token metadata JSON schema. The token metadata JSON schema V2 provides a standard scheme for non-fungible token metadata on Hedera. This standard aims to provide a common JSON schema for structuring metadata to make it easier for NFT tooling to parse metadata. 

For example, NFT explorers want to scrape information about an NFT's attributes to calculate rarity. The token metadata JSON schema V2 defines the "attributes" property and its format to make it easier for NFT tooling to find the correct information about an NFT. 

In short, the token metadata JSON schema V2 defines a flexible specification for creating NFTs on Hedera. 

How do you connect metadata to an NFT?

It's essential to understand that the token metadata JSON schema V2 requires you to store metadata using a storage solution, centralized or decentralized, such as IPFS or Arweave. 

When creating a non-fungible token using the Hedera Token Service, you set the metadata value to the metadata JSON file to define your NFT, wherever it’s stored. This technique allows you to connect the metadata to the token created on the Hedera network. It's not allowed to use the "memo" or "symbol" fields on the NFT.

Here's an excerpt from the "NFT minting" tutorial

Code Snippet Background
// IPFS content identifiers for which we will create a NFT
let CID = "ipfs://QmTzWcVfk88JRqjTpVwHzBeULRTNzHY7mnBSG42CpwHmPa";

// Mint new NFT
let mintTx = await new TokenMintTransaction()
    .setTokenId(tokenId)
    .setMetadata([Buffer.from(CID)])
    .freezeWith(client);

What does the token metadata JSON schema V2 look like?

You can find the reference implementation for the token metadata JSON schema V2 in the Hedera Improvements Proposals GitHub repository, via the NFT.Storage gateway link, or IPFS itself (ipfs://bafkreidcsqzr5su356thecwuyzrhsgekfdsqzuyuqxtsu4vh7oc34iv5oy).

Required properties

The schema defines three required properties:

  • name: Full name of the NFT
  • type: MIME type for the image.
  • image: A URI pointing to an image.

The image field is required. It can both serve as a preview image or the full-resolution image for your NFT to ensure cross-platform compatibility. The image property will be displayed in wallets and marketplaces by default.

Creators are recommended to point to a thumbnail in the image field and put the high-resolution image in the files array with the is_default_file boolean set to indicate that this file represents the default image for the NFT.

Here's an example of a full implementation for a collectible NFT.

Code Snippet Background
{
    "name": "Example NFT 001",
    "creator": "Jane Doe, John Doe",
    "creatorDID": "did:hedera:mainnet:7Prd74ry1Uct87nZqL3ny7aR7Cg46JamVbJgk8azVgUm;hedera:mainnet:fid=0.0.123",
    "description": "This describes my NFT",
    "image": "https://myserver.com/preview-image-nft-001.png",
    "checksum": "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
    "type": "image/png",
    "format": "[email protected]",
    "properties" : {
        "external_url": "https://nft.com/mycollection/001"
    },
    "files": [
        {
            "uri": "https://myserver.com/high-resolution-nft-001.png",
            "checksum": "9defbb6402d4bf39f2ea580099c73194647b24a659b6f6b778e3dd71755b8862",
            "is_default_file": true,
            "type": "image/png"
        },
        {
            "uri": "ipfs://yusopwpksaioposjfopiapnnjlsl",
            "type": "image/png"
        }
    ],
    "attributes": [
        {
            "trait_type": "color",
            "display_type": "color",
            "value": "rgb(255,0,0)"
        },
        {
            "trait_type": "hasPipe",
            "display_type": "boolean",
            "value": true
        },
        {
            "trait_type": "coolness",
            "display_type": "boost",
            "value": 10,
            "max_value": 100
        },
        {
            "trait_type": "stamina",
            "display_type": "percentage",
            "value": 83
        }
        ,
        {
            "trait_type": "birth",
            "display_type": "datetime",
            "value": 732844800
        }
    ],
    "localization": {
        "uri": "ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/{locale}.json",
        "default": "en",
        "locales": ["es", "fr"]
    }
}

Optional properties

All other properties are optional, but they are essential to provide more information about your NFT. Here's an overview of the other properties you should look out for.

  • checksum: Represents a SHA-256 cryptographic hash that allows you to verify the integrity of any file type.
  • files: Represents an array containing file objects. For collectible NFTs, the files array allows you to store the high-resolution image of your NFT. However, you can also use this field for multi-file NFTs. Each file object requires a URI and type. It's recommended to use the is_default_file property to indicate which file is the main file for your NFT. Besides that, the files array allows you to upload or link file-specific metadata. This allows you to nest files indefinitely.
  • format: Indicates the implemented metadata schema specification. Currently, the default version (token metadata JSON schema V2) is represented by [email protected].
  • attributes: Attributes are used to calculate rarity and describe the NFT. You can define trait_typedisplay_type (how the trait value should be displayed), and value (value for the trait). You can set a max_value for numerical traits to set a ceiling for the value field.
  • localization: The standard also allows for localization. Each locale links to another metadata file containing localized metadata and files. This allows for a clean metadata structure. Don't define another localization object for a localized metadata file to avoid infinite looping when parsing an NFT's metadata file. Note that the localization.uri property contains "{locale}". The {locale} part references a locale in the locales array.
  • properties: It's not allowed to define additional properties on the root level of the metadata object. If you want to add custom properties, you can add them to the properties object. For example, you are linking to a website or social media pages.

Want to learn more about the specification? You can click the different URLs to find more information about each property or look up the JSON schema.

How to verify your NFT metadata against token metadata V2?

You can use the token metadata validator package to verify if your metadata is correctly structured. This code package allows you to validate your metadata against the token metadata JSON schema V2. The package is created using JavaScript and can be installed with a package manager like NPM or Yarn.

Here's a small code example of how to use the package.

Code Snippet Background
const { validator, defaultVersion } = require('@hashgraph/nft-utilities');

const metadata = {
    name: "My First NFT",
    attributes: [
        { trait_type: "Background", value: "Yellow" }
    ],
    creator: "NFT artist",
    image: "ipfs://bafkreibwci24bt2xtqi23g35gfx63wj555u77lwl2t55ajbfjqomgefxce"
};

const issues = validator(JSON.stringify(metadata), defaultVersion);

Token Metadata V2 NFT Examples

The metadata specification section has shown you how to create a collectible NFT on Hedera using the token metadata V2 schema. What else can we use the standard for?

Example 1: Multi-file NFT with localization

Here's a multi-file NFT that includes a video, which is the main file for the NFT, and a PDF document. The PDF document has a metadata object which again adheres to the specification.

Code Snippet Background
{
    "name": "Example NFT",
    "creator": "Jane Doe, John Doe",
    "creatorDID": "did:hedera:mainnet:7Prd74ry1Uct87nZqL3ny7aR7Cg46JamVbJgk8azVgUm;hedera:mainnet:fid=0.0.123",
    "description": "This is an example NFT metadata",
    "image": "https://myserver.com/preview-image-001.png",
    "checksum": "9defbb6402d4bf39f2ea580099c73194647b24a659b6f6b778e3dd71755b8862",
    "type": "image/png",
    "files": [
        {
            "uri": "ipfs://bawlkjaklfjoiaefklankfldanmfoieiajfl",
            "type": "video/mp4",
            "is_default_file": true
        },
        {
            "uri": "ipfs://bawlkjaklfjoiaefklankfldanmfoieiajfl",
            "type": "application/pdf",
            "metadata": {
                "name": "Example second file",
                "description": "The description is recommended but optional. The image provided is an optional preview",
                "image": "ipfs://bawlkjaklfjoiaefklankflda1313ieiajfl",
                "type": "image/jpeg"
            }
        }
    ],
    "localization": {
        "uri": "ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/{locale}.json",
        "default": "en",
        "locales": ["es", "fr"]
    }
}

Example 2: NFT with nested files

It's possible to indefinitely nest files. Here's an example with nested files (level 2 nesting).

The image listed in the files object represents a cover image for the PDF. Further, this object includes metadata which again lists a files array. This files array contains a file of type "application/vnd.ms-powerpoint" (PowerPoint presentation) attached to the PDF. For example, the PowerPoint presentation supplements the PDF.

Code Snippet Background
{
    "name": "Example NFT",
    "image": "ipfs://bafkreibwci24bt2xtqi23g35gfx63wj555u77lwl2t55ajbfjqomgefxce",
    "type": "image/png",
    "files": [
            {
                "uri": "ipfs://bawlkjaklfjoiaefklankfldanmfoieiajfl",
                "type": "application/pdf",
                "metadata": {
                    "name": "Example second file",
                    "description": "The description is recommended but optional. The image provided is an optional preview",
                    "image": "ipfs://bawlkjaklfjoiaefklankflda1313ieiajfl",
                    "type": "image/jpeg",
                    "files": [
                        {
                            "uri": "ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT",
                            "type": "application/vnd.ms-powerpoint"
                        }
                    ]
                }
            }
        ]
}

Example 3: Basic implementation of Token Metadata V2

Here's a basic NFT that defines a creator and description. Besides that, it lists the required properties "image", "type", and "name".

Further, the "properties" property includes additional metadata that the token metadata V2 specification does not specify. You can include any data in the "properties" object. As a best practice, if you define a boolean, start its naming with "is" or "has". For example, "hasProperty" or "isCollectible".

Code Snippet Background
{
    "name": "Example NFT",
    "creator": "John Doe",
    "description": "This is an example NFT metadata",
    "image": "ipfs://bafkreibwci24bt2xtqi23g35gfx63wj555u77lwl2t55ajbfjqomgefxce",
    "type": "image/png",
    "properties": {
        "license": "MIT-0",
        "collection": "Generic Collection Name",
        "website": "www.johndoe.com",
                "isCollectible": true
    }
}

What's next?

The token metadata JSON schema V2 will continue to evolve based on changing market dynamics and community needs. The sole purpose is to provide a "common language" for NFT metadata to make it easier for NFT tooling to interpret NFT metadata. 

Do you have suggestions or want to make changes? Go to the Hedera Improvement Proposals GitHub repository where you can submit an issue or create a pull request.