{"id":"ERC-721","name":"Non-Fungible Token Standard","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"}],"uxImpact":"Each token is unique with distinct ownership — the foundation of all NFT UX. Design implications: show single-item detail views with ownership info and provenance history, display unique token IDs prominently, design 1:1 transfer flows (not quantity selectors), implement approval flows for marketplace listings with clear 'Approve' vs 'Approve All' distinction. Design decisions: balance between showing technical token IDs vs friendly names, whether to expose raw contract addresses or use ENS/profiles, how much provenance history to surface without overwhelming users.","hasDetailedContent":true,"content":{"id":"ERC-721","summary":"ERC-721 defines non-fungible tokens (NFTs). Unlike ERC-20 where every token is identical, each ERC-721 token has a unique ID. This enables digital art, collectibles, game items, membership passes, and anything where each item is distinct. It specifies ownership, transfers, approvals, and metadata linking — the foundation of the NFT ecosystem.","designerTakeaways":["You can preview image, collection name, and token id before irreversible transfers.","You can use per-token approval unless marketplace trust justifies operator approve.","You can lazy-load metadata with placeholders when images or traits fail to load."],"applicability":{"whenToUse":["Each asset has a unique id and separate ownership.","Marketplaces or wallets must list, transfer, or approve single items.","Metadata (image, traits) is tied to tokenURI per token."],"whenToAvoid":["Large quantities of identical items (prefer ERC-1155).","Fungible positions or vault shares (use ERC-20 or ERC-4626).","You only need off-chain collectibles with no wallet transfers."]},"designDecisions":[{"question":"Single-token approve or operator approve?","recommendation":"Use setApprovalForAll only with marketplace trust copy; default to per-token approve for unknown spenders.","rationale":"Operator approval grants control over the entire collection, not one listing."},{"question":"How is metadata failure shown?","recommendation":"Placeholder art plus \"metadata unavailable\" instead of a broken image tile.","rationale":"Broken media reads as a scam or bug during high-intent purchase moments."},{"question":"What does the transfer confirmation show?","recommendation":"Preview image, collection name, token id, and recipient before sign.","rationale":"NFT transfers are irreversible; users need identity checks beyond a hex address."},{"question":"How do you surface collection-level risk?","recommendation":"Flag unverified collections and spoofed names separately from verified badges.","rationale":"Users confuse lookalike collections when browsing quickly."}],"statesToDesign":[{"state":"Metadata loading","trigger":"tokenURI fetch or image CDN request pending.","userNeed":"Know the item exists while media loads.","designResponse":"Skeleton tile with collection name and token id visible."},{"state":"Not owner","trigger":"User attempts action on a token they do not hold.","userNeed":"Understand why buy, list, or transfer is disabled.","designResponse":"Disable primary action with \"You do not own this item\" copy."},{"state":"Approval for marketplace","trigger":"Marketplace needs operator or token approval.","userNeed":"Know scope of access being granted.","designResponse":"State whether approval is for one token or all items in the collection."},{"state":"Transfer in progress","trigger":"safeTransferFrom submitted.","userNeed":"Confidence the item is leaving the wallet.","designResponse":"Pending state on item card; remove or dim after confirmation."},{"state":"Received airdrop","trigger":"Unexpected token appears in wallet.","userNeed":"Avoid interacting with malicious airdrops.","designResponse":"Hide or quarantine unverified drops; warn before first interaction."}],"problemsSolved":[{"problem":"No standard for unique digital items","oldWay":"Each project invented its own ownership system","newWay":"ERC-721: universal interface for unique tokens","impact":"critical"},{"problem":"Marketplaces couldn't support all NFTs","oldWay":"Custom integration for each NFT contract","newWay":"Any ERC-721 works on OpenSea, Blur, etc.","impact":"critical"},{"problem":"No standard way to link NFT to its image/metadata","oldWay":"Random ways to store and retrieve NFT info","newWay":"tokenURI() returns metadata JSON with image, attributes","impact":"high"},{"problem":"Couldn't approve operators for all NFTs at once","oldWay":"Approve each NFT individually before selling","newWay":"setApprovalForAll() for marketplace integration","impact":"high"}],"uxPatterns":[{"name":"NFT Collection Gallery","description":"Display user's NFT holdings in a visual grid","mockup":"concept/nft-gallery","userFlow":["App queries user's NFT holdings","Fetches tokenURI for each","Loads and caches images","Displays in responsive grid","Lazy loads as user scrolls"]},{"name":"NFT Detail View","description":"Single NFT with full metadata and actions","mockup":"concept/nft-gallery","userFlow":["User selects NFT from gallery","App fetches tokenURI metadata","Parses JSON for attributes","Shows rarity percentages","Displays action buttons"]},{"name":"NFT Transfer","description":"Send NFT to another address","mockup":"concept/nft-gallery","userFlow":["User selects NFT to transfer","Enters recipient address","App validates address format","Shows value and warning","User confirms transfer","Calls safeTransferFrom()"]},{"name":"Marketplace Approval","description":"Approve marketplace to list NFTs","mockup":"generic/token-approval","userFlow":["User tries to list NFT","Marketplace detects no approval","Shows approval options","User selects scope","Calls approve() or setApprovalForAll()","Can now list NFTs"]}],"uiComponents":[{"name":"NFTCard","description":"Thumbnail card showing NFT image, name, collection","states":["loading","loaded","error","selected"],"props":["tokenId","contractAddress","metadata","onClick"]},{"name":"NFTImage","description":"Handles various media types (image, video, audio, 3D)","states":["loading","loaded","error","fallback"],"props":["uri","type","fallbackImage"]},{"name":"AttributeList","description":"Displays NFT traits with rarity percentages","states":["loading","loaded","no-attributes"],"props":["attributes[]","showRarity"]},{"name":"CollectionBadge","description":"Shows collection name with verified checkmark","states":["verified","unverified","flagged"],"props":["name","address","isVerified"]},{"name":"NFTTransferForm","description":"Form for transferring NFT to another address","states":["input","validating","ready","sending","success"],"props":["nft","onTransfer"]}],"antiPatterns":[{"pattern":"Not validating recipient can receive NFTs","why":"Some contracts can't receive NFTs, tokens get stuck","instead":"Use safeTransferFrom() which checks ERC-721Receiver","severity":"critical"},{"pattern":"Loading all NFT images at once","why":"Large collections crash browser, waste bandwidth","instead":"Virtualize list, lazy load images as they scroll into view","severity":"high"},{"pattern":"Trusting tokenURI without validation","why":"Malicious metadata can include XSS, phishing links","instead":"Sanitize metadata, validate URLs, sandbox iframes","severity":"critical"},{"pattern":"Not caching metadata","why":"Every view re-fetches from IPFS/HTTP, slow and wasteful","instead":"Cache tokenURI responses, invalidate on transfer","severity":"medium"},{"pattern":"Assuming all NFTs have metadata","why":"Some contracts return empty tokenURI or fail","instead":"Graceful fallback: show token ID, placeholder image","severity":"high"},{"pattern":"Not explaining setApprovalForAll risks","why":"Users don't realize they're approving ALL NFTs in collection","instead":"Clear warning: \"This approves ALL your [collection] NFTs\"","severity":"high"}],"onMonad":[{"aspect":"Transfer Speed","ethereum":"Transfer takes 12+ seconds to confirm","monad":"Sub-second finality","designImplication":"Instant ownership updates in UI"},{"aspect":"Minting Experience","ethereum":"Mint transaction → wait → check if succeeded","monad":"Mint → instant confirmation","designImplication":"Can show NFT immediately after mint"},{"aspect":"Batch Operations","ethereum":"Each transfer is separate transaction","monad":"Batch transfers via 7702 possible","designImplication":"Enable \"Send multiple NFTs\" feature"},{"aspect":"Gas for Transfers","ethereum":"Transfer costs significant gas","monad":"Much cheaper per transfer","designImplication":"More viable to move NFTs frequently"}],"keyTakeaways":["ERC-721 = unique tokens, each with distinct ID","Always use safeTransferFrom() to prevent stuck NFTs","Lazy load images, cache metadata","Sanitize tokenURI metadata for security","Explain setApprovalForAll risks clearly"],"technicalNotes":"ERC-721 specifies: balanceOf, ownerOf, safeTransferFrom, transferFrom, approve, setApprovalForAll, getApproved, isApprovedForAll. Events: Transfer, Approval, ApprovalForAll. Optional: name(), symbol(), tokenURI(). Metadata JSON format: { name, description, image, attributes[] }. safeTransferFrom checks if recipient is contract and calls onERC721Received()."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-721","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-721","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-721","markdown":"https://www.eipsfordesigners.com/standards/ERC-721/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-721/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-721","official":"https://eips.ethereum.org/EIPS/eip-721","discussion":"https://ethereum-magicians.org/search?q=ERC-721"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}}