The ERC-721 Metadata Standard: A Complete Developer Reference
The ERC-721 Metadata Standard: A Complete Developer Reference
If your NFT metadata is wrong, OpenSea shows a blank card. Here's the complete guide to getting it right — from required fields to advanced display types.
Table of Contents
- How ERC-721 Metadata Works
- The JSON Structure
- Required Fields
- Optional Fields
- The Attributes Array
- Display Types Deep Dive
- OpenSea-Specific Features
- Our Metadata: 9 Attributes in Practice
- IPFS vs Centralized Hosting
- tokenURI and baseURI Pattern
1. How ERC-721 Metadata Works
An ERC-721 token is just a number (token ID) owned by an address. By itself, it has no image, no name, no description. All that information lives in metadata — a JSON file that the smart contract points to via the tokenURI function.
When OpenSea (or any marketplace) displays your NFT, it:
- Calls
tokenURI(tokenId)on your contract - Gets back a URL (usually IPFS)
- Fetches the JSON at that URL
- Reads the fields and renders the NFT card
If any step fails — wrong URL, malformed JSON, missing fields — your NFT appears as a blank card. Getting metadata right is essential.
2. The JSON Structure
Here's a complete example with all major fields:
{
"name": "Quantum Genesis #42",
"description": "A unique piece of generative art created from measurements on IBM Quantum's ibm_fez processor. The quantum circuit used Hadamard gates and CNOT entanglement to produce genuinely random bits that drive the color palette, geometry, and composition.",
"image": "ipfs://bafybeifges7tei5x7drj37f34yhzqofwlz2icbo7z67isg6g446k65yw3a/42.png",
"external_url": "https://opensea.io/collection/quantum-genesis",
"background_color": "0a0a2e",
"attributes": [
{
"trait_type": "Quantum Source",
"value": "IBM Quantum ibm_fez"
},
{
"trait_type": "Color Harmony",
"value": "Triadic"
},
{
"trait_type": "Qubit Count",
"display_type": "number",
"value": 8
},
{
"trait_type": "Entropy Score",
"display_type": "number",
"value": 94
},
{
"display_type": "date",
"trait_type": "Generation Date",
"value": 1710892800
}
]
}
3. Required Fields
Technically, the ERC-721 standard only requires tokenURI to return a valid URI. But for marketplaces to render your NFT properly, three fields are effectively required:
name (string)
The name of the individual token. This appears as the title on marketplace cards.
"name": "Quantum Genesis #42"
Convention: Collection name + # + token ID. Keep it under 50 characters for clean display.
description (string)
A text description of the token. Supports Markdown on OpenSea. This appears in the "Description" section of the NFT detail page.
"description": "A unique piece of generative art created from real quantum computer measurements..."
Tips: Include what makes the piece unique. Mention the process. Keep it under 500 characters for best readability. OpenSea supports basic Markdown (bold, italic, links).
image (string — URI)
URL to the image. Supported formats: PNG, JPG, GIF, SVG, WebP. Maximum recommended size: 40MB (OpenSea limit).
"image": "ipfs://bafybeifges7tei5x7drj37f34yhzqofwlz2icbo7z67isg6g446k65yw3a/42.png"
Use the ipfs:// protocol prefix — marketplaces resolve this through their own IPFS gateways. Avoid using a specific gateway URL (like https://gateway.pinata.cloud/ipfs/...) because if that gateway goes down, your image breaks.
Important: The image field is what appears as the NFT thumbnail everywhere — in wallets, marketplaces, social media embeds. Get this right.
4. Optional Fields
external_url (string — URI)
A URL that appears as a clickable link on the NFT's OpenSea page under the token name. Use this to link to your project website or a detailed page about the piece.
"external_url": "https://yourproject.com/nft/42"
animation_url (string — URI)
For multimedia NFTs. Supports HTML pages, GLB/GLTF 3D models, MP4/WebM video, MP3/WAV audio, and interactive content. If present, this takes priority over image for display, while image becomes the thumbnail.
"animation_url": "ipfs://Qm.../interactive.html"
background_color (string — hex without #)
A six-character hex color for the background of the NFT card on OpenSea. No # prefix.
"background_color": "0a0a2e"
This fills the space around your image if it doesn't perfectly match the card dimensions.
5. The Attributes Array
Attributes are the most powerful part of NFT metadata. They define the traits that appear in the "Properties," "Stats," and "Levels" sections on OpenSea. They also power filtering and rarity calculations.
Each attribute is an object with:
{
"trait_type": "Color Harmony", // The trait category
"value": "Triadic" // The trait value
}
That's it for basic string traits. They appear as rectangular badges under "Properties" on OpenSea. Collectors can filter your collection by these traits.
Numeric Attributes
{
"trait_type": "Entropy Score",
"display_type": "number",
"value": 94
}
Numeric attributes appear under "Stats" with a simple number display. OpenSea automatically calculates the range across your collection.
Optional: max_value
{
"trait_type": "Entropy Score",
"display_type": "number",
"value": 94,
"max_value": 100
}
Adding max_value shows a progress bar on OpenSea. Without it, OpenSea infers the max from the highest value in your collection.
6. Display Types Deep Dive
OpenSea supports several display_type values that change how attributes render:
| display_type | Renders As | Value Type | Section |
|---|---|---|---|
| (omitted) | Text badge | string | Properties |
"number" | Plain number | integer/float | Stats |
"boost_number" | Number with + prefix | integer/float | Boosts |
"boost_percentage" | Circular progress + % | integer (0-100) | Boosts |
"date" | Formatted date | Unix timestamp | Properties |
boost_number
{
"display_type": "boost_number",
"trait_type": "Quantum Advantage",
"value": 12
}
// Renders as: "+12" in a circular badge
boost_percentage
{
"display_type": "boost_percentage",
"trait_type": "Randomness Quality",
"value": 95
}
// Renders as: circular progress bar showing 95%
date
{
"display_type": "date",
"trait_type": "Generation Date",
"value": 1710892800
}
// Renders as: "March 20, 2024" (human-readable)
// Value MUST be Unix timestamp (seconds since epoch)
7. OpenSea-Specific Features
OpenSea has introduced additional metadata conventions beyond the basic ERC-721 standard:
Collection-Level Metadata
Set via the OpenSea UI or API — not in individual token metadata. Includes collection name, banner image, description, royalty percentage, and social links.
Trait Rarity
OpenSea automatically calculates rarity based on trait distribution across your collection. If only 5 out of 100 NFTs have "Quantum Source: Origin Quantum WK_C180," that trait shows as "5% have this trait." You don't need to specify rarity — it's computed from the data.
Refresh Metadata
If you update your metadata JSON on IPFS (by re-uploading and updating the tokenURI), you can force OpenSea to re-fetch it by clicking "Refresh metadata" on the NFT page or calling the API.
8. Our Metadata: 9 Attributes in Practice
Each Quantum Genesis NFT has 9 carefully chosen attributes:
{
"name": "Quantum Genesis #42",
"description": "Generative art from real quantum computer measurements...",
"image": "ipfs://bafybeifges7tei5x7drj37f34yhzqofwlz2icbo7z67isg6g446k65yw3a/42.png",
"external_url": "https://opensea.io/collection/quantum-genesis",
"attributes": [
{ "trait_type": "Quantum Source", "value": "IBM Quantum ibm_fez" },
{ "trait_type": "Color Harmony", "value": "Triadic" },
{ "trait_type": "Visual Style", "value": "Orbital" },
{ "trait_type": "Background Tone", "value": "Dark" },
{ "trait_type": "Complexity", "value": "High" },
{ "trait_type": "Qubit Count", "display_type": "number", "value": 8 },
{ "trait_type": "Entropy Score", "display_type": "number", "value": 94 },
{ "trait_type": "Gate Depth", "display_type": "number", "value": 12 },
{ "display_type": "date", "trait_type": "Generation Date", "value": 1710892800 }
]
}
The string traits (Quantum Source, Color Harmony, Visual Style, Background Tone, Complexity) create filterable categories on OpenSea. The numeric traits (Qubit Count, Entropy Score, Gate Depth) appear as stats. The date trait records when the quantum measurement was taken.
Why These 9 Attributes?
- Quantum Source — provenance: which quantum computer generated the data
- Color Harmony — the palette algorithm used (triadic, complementary, etc.)
- Visual Style — the geometric pattern type
- Background Tone — dark or light background
- Complexity — visual complexity level
- Qubit Count — technical parameter of the quantum circuit
- Entropy Score — quality measure of the quantum randomness (0-100)
- Gate Depth — circuit depth (more gates = more entanglement)
- Generation Date — exact timestamp for provenance
9. IPFS vs Centralized Hosting
Your metadata JSON and images need to be hosted somewhere accessible. Two main options:
IPFS (Recommended)
IPFS (InterPlanetary File System) is a decentralized storage network. Content is addressed by hash — the URL is derived from the content itself. If anyone in the world has a copy, it's accessible.
- Pros: Decentralized, content-addressed (tamper-proof), permanent if pinned
- Cons: Slower initial load, requires pinning service to stay available
- Services: Pinata (we use this), NFT.Storage, Infura IPFS, Filebase
We use Pinata for IPFS pinning. All 100 art PNGs are in a single IPFS directory, and all 100 metadata JSONs are in another. The directory CID becomes our baseURI.
Centralized (Not Recommended)
You could host metadata on any web server (AWS S3, your own domain). But if that server goes down, every NFT in your collection shows a blank card. This defeats the permanence that blockchain promises.
Always use IPFS for NFT metadata and images. Collectors rightfully distrust centralized metadata — it means the creator can change or delete the art at any time.
10. tokenURI and baseURI Pattern
Your smart contract needs to return the correct metadata URL for each token. Two common patterns:
Pattern 1: Individual tokenURI
Store each token's full URI in the contract. Flexible but expensive (one storage write per mint).
// Solidity
mapping(uint256 => string) private _tokenURIs;
function tokenURI(uint256 tokenId) public view returns (string memory) {
return _tokenURIs[tokenId];
}
Pattern 2: baseURI + tokenId (Recommended)
Store one base URI. Each token's URI is baseURI + tokenId. Much cheaper for large collections.
// Solidity (OpenZeppelin pattern)
string private _baseTokenURI;
function _baseURI() internal view override returns (string memory) {
return _baseTokenURI;
}
// tokenURI(42) returns: "ipfs://QmBaseHash/42"
// The JSON file at that IPFS path contains the metadata for token 42
This is what we use for Quantum Genesis. Our baseURI points to an IPFS directory containing files named 1 through 100 (no extension). Each file is a JSON metadata document.
The IPFS directory structure:
ipfs://QmMetadataCID/
├── 1 ← JSON metadata for token #1
├── 2 ← JSON metadata for token #2
├── ...
└── 100 ← JSON metadata for token #100
And in each JSON, the image field points to the art directory:
"image": "ipfs://bafybeifges7tei5x7drj37f34yhzqofwlz2icbo7z67isg6g446k65yw3a/42.png"
Desenvolvo sistemas que usam hardware quântico real (IBM Quantum, Origin Quantum) para gerar arte e NFTs com proveniência verificável on-chain. Escrevo sobre computação quântica aplicada, criptografia, Web3 e arte generativa — tudo com código que roda em processadores quânticos de verdade.
Comentários
Postar um comentário