ERC721: Split an NFT into public and private part

First I will explain what it consists of and then I will give a practical example


Today it is normal to hear people wondering why they want an NFT if anyone can see it, listen to it, copy it, etc. Clearly, the people saying this sort of thing don’t have a good understanding of the underlying technology.

To refute this kind of thinking and also to give NFTs more exclusivity, I present this idea.

What does it consist of

It consists of dividing the NFT into two parts, the public part, which is the one that everyone can see, share, etc. (although it still has a single owner, that is, the typical NFT) and the private or hidden part, which can only be viewed when interacting with the owner address.

Use cases

A book, the public part would be the cover and if you want a few pages and the rest of the book is in the private part.

As for the world of music, you can apply it to songs, showing a few seconds of test or discs showing one or two test songs.

Even in the world of cinema, the party publishes a trailer and the private the movie…

These are just a few use cases that came to mind quickly, but I’m sure you can think of many others


What is intended to achieve with this is to have a greater incentive when purchasing an NFT.

I hope you have found it interesting and do not forget to share your opinions, I will read them all.

Practical example

This is a simple way to do it, I hope you help me to get bugs and improve it

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract ERC721_Public_Private is ERC721
    uint256 private token_count;
    // Mapping from token ID to owner hash
    mapping(uint256 => bytes32) private _hashes;

    constructor() ERC721("Bitcoin Whitepaper","BTC-W") {}

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory)
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        if(_hashes[tokenId] == keccak256(abi.encodePacked(msg.sender,tokenId))){
            return "";
            return "";

    function mintNFT(address to) public

        token_count += 1;
        _mint(to, token_count);
        _hashes[token_count] = keccak256(abi.encodePacked(msg.sender,token_count));


I think this is a simple missing link in NFTs right now.
Can you hint on how are you going to solve the “privatization” part?
I assume the content will have to be encoded and only decoded with the owners signature?
I’m really curious! Good luck, I will follow your progress!

I’m glad you’re interested!
I just updated the post with a simple example to get feedback and improve it.


I really like this idea!

Great in real life examples. Core value is clear, too.

I’m also surprised at how simple the implementation is. Very nice work.

1 Like