The Magic of Revealing NFTs
NFTs that reveal after mint may seem complex, but a little bit of Solidity magic makes it quite an easy trick to do.
With our recently released Wandering Witches, we did something we have not before — though is common throughout the NFT space. Upon minting, the witches were not immediately revealed, instead all showing the same placeholder image. After reveal, each have unique names, but before they just had a number. So how do projects like this work?

First, we need to understand how an NFT itself works. When an NFT is minted, it creates a token on the blockchain that can be identified by a unique combination of token ID and smart contract address. To get additional information about the NFT — metadata, even who owns it — one must call functions on the smart contract. This “smart contract” is essentially a small app that lives on the blockchain forever, which, in this case, is managing the collection of non-fungible tokens.
The name, description, traits, and image URL for an NFT all exist as JSON somewhere. In the case of “on-chain” NFTs, as discussed in a prior article, this is generated, along with the image, directly by the smart contract itself. Much more commonly, the smart contract instead passes a location where the JSON can be found — ideally on a decentralized service like IPFS or Arweave less prone to the pitfalls of centralization, unlike a cloud storage provider.
By overriding a function called _baseURI()
, we can easily configure how this JSON is loaded for the whole collection — the token’s ID will be tacked onto the end of whatever this function returns, enabling you to effectively just point at a folder of sequentially numbered JSON files. For collections that lack a reveal mechanic, this may just pass back a hard-coded string.
However, any logic we want can be put in this function — and we can modify variables that function uses elsewhere. For instance, a simple way to handle reveals is by creating a baseURI
variable, returning that in _baseURI()
, and then creating another function named something like setBaseURI()
, which allows modifying that variable.
You can even do multi-stage reveals easily this way, such as was most infamously done with Beanz, the collection airdropped to Azuki holders — without them even knowing what was inside. At first, they appeared as a crate, then as a pile of dirt atop the remains of the crate, and then — only after a long wait — the Beanz themselves. Because you can keep calling setBaseURI()
, you can keep “revealing” new stages.
However, that does create a risk with some implementations of reveals: the smart contract owner is left with power to modify the NFT metadata. There are ways to code around it, such as allowing a revealed baseURI
only to be set once — though that removes the ability to fix any issues too. The contract owner can also relinquish ownership of it once minted out, leaving no one with the power to call the owner-only functions.
Though the above approach is — in my opinion — the most straightforward way of handling such a mechanic, it is also possible to override the tokenURI() function instead, which handles the logic one sooner. This function takes a token ID and does the logic on on a per-token basis, rather than assuming all tokens share the same base.
To summarize:
Each NFT has an ID and a smart contract address
That smart contract can give you JSON data for that NFT
Smart contracts can be coded to change what JSON they return
What may seem like a complex and overwhelming mechanic for NFT launches is, in fact, quite doable for anyone with at least a decent grasp on Solidity. We were excited to test out this mechanic with the launch of the Wandering Witches, and we were so happy that a lot of our early minters were excited to see their witch unveiled. While this approach is not the right fit for many projects, we just hope you will not be deterred by it feeling too tricky. You are capable of such a conjuring.