What NFT metadata is
An NFT’s name, picture and traits live in a small JSON file (plain text that lists names and values). The NFT’s contract hands out an address for each token: for ERC-721, the common standard for one-of-a-kind NFTs on Ethereum and similar chains, a function called tokenURI returns the address of that token’s file. OpenSea “reads token metadata from the URI returned by your ERC-721 tokenURI function” (OpenSea).
A generator such as Puffles Studio writes these files for you, one per NFT, next to the images.
The fields
The ERC-721 standard’s own metadata schema has three fields: name, description and image (EIP-721). OpenSea reads more. These are the fields on its Media and traits page, updated 21 July 2026:
| Field | What it holds | In the ERC-721 schema | Written by Puffles Studio |
|---|---|---|---|
| name | The NFT’s name | Yes | Yes: your NFT name and a number, like “Puff Editions #1” |
| description | Text about the NFT (OpenSea supports Markdown) | Yes | Only if you wrote one |
| image | The address of the picture | Yes | Yes: your images folder address plus the file name |
| attributes | The traits, as trait_type and value pairs | No | Yes: one per trait, with None left out |
| external_url | A link to your own site | No | No |
| animation_url | A video, audio, 3D or web page file | No | No |
| background_color | A six-character hex colour, without # | No | No |
The same page says to “use images at least 3000 by 3000 pixels”. Puffles Studio can export at any width from 64 to 8,192 pixels, or at your traits’ own size.
A real file, field by field
This is json/1.json from the Puff Editions starter kit, exactly as the studio’s planner writes it (100 NFTs, seed “puff-editions”, no image address set yet):
{
"name": "Puff Editions #1",
"description": "An original collection. Created with Puffles Studio.",
"image": "ipfs://REPLACE_WITH_IMAGES_CID/1.png",
"attributes": [
{ "trait_type": "Background", "value": "Mist" },
{ "trait_type": "Body", "value": "Frost" },
{ "trait_type": "Expression", "value": "Happy" },
{ "trait_type": "Headwear", "value": "Bucket" }
]
}- name: the NFT name (the collection name, unless you set another) and its number.
- description: the collection’s description, copied to every NFT. Leave it empty and the field is left out.
- image: your images folder address, then the file name. REPLACE_WITH_IMAGES_CID is a placeholder until you set the address.
- attributes: one entry per trait folder. The folder name becomes the trait_type, without the number in front (“04_Headwear” becomes “Headwear”), and the file name becomes the value.
The very next file, json/2.json, has no hat: its Headwear was the None choice, so its attributes list has three entries, not four.
File numbers and name numbers
Puffles Studio numbers files and names separately, in the Metadata tab. “File numbering starts at” sets the number of the image and metadata files; “Name numbering starts at” sets the number people read. Each can start at any whole number from 0 to 1,000,000, and both start at 1 unless you change them.
Starting at 0 or 1
Some contracts number tokens from 0 and others from 1. Match the file numbering to your contract: the file number is the token number.
A file called 0.png named “#1”
Set files to start at 0 and names at 1, and the first NFT’s files are 0.png and 0.json while its name is “Puff Editions #1”. With a real images folder address, the start of the file reads:
{
"name": "Puff Editions #1",
"description": "An original collection. Created with Puffles Studio.",
"image": "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi/0.png",With or without .json on the end
The Metadata tab’s “Metadata file extension” setting saves the files as 1.json or simply 1. Whether your contract expects the extension depends on how it builds each token’s address, so pick whichever it uses. The addresses inside the files are the same either way.
_metadata.json and the per-NFT files
The export also holds _metadata.json: every NFT’s metadata in one file, in collection order. The json/ folder is what you upload for the contract to point at. _metadata.json is handy for checking the whole collection at once, or for another tool.
The image address
Until you set it, every image field starts with the placeholder ipfs://REPLACE_WITH_IMAGES_CID. Upload your images folder first, then put the folder’s address (ipfs://…, https://… or ar://…) into the metadata. You don’t need to build the images again: set your NFT image address shows the three ways.
Fields Puffles does not write
external_url, animation_url, background_color and number or date traits (OpenSea’s display_type) are not written. Trait values come from file names, so they are always text, and OpenSea treats “a numeric value wrapped in quotes” as text too. To add one of these fields, edit the JSON files after export and keep _metadata.json in step.
Puffles Studio writes metadata in this EVM, OpenSea style only. For the spreadsheet OpenSea’s drops use instead of JSON, see the drop CSV.
Questions people ask
Is attributes required?
Not by the ERC-721 standard, which defines only name, description and image. But marketplaces read attributes to show and filter traits, so generative collections nearly always have them.
Why does my image say REPLACE_WITH_IMAGES_CID?
It’s a placeholder: your images folder has no address until you upload it. Set the address in the studio and download the metadata again (how).
Should metadata files end in .json?
Only if your contract adds .json when it builds each token’s address. Puffles Studio can save them either way.
Can I start numbering at 0?
Yes. File numbering and name numbering each start at any whole number from 0 to 1,000,000, so 0.png can be named “#1”.
Can I add an external_url?
Not in the studio today. Add it to the JSON files after export if you need it. The OpenSea drop CSV has an external_url column, which Puffles leaves empty.