{"id":"ERC-4906","name":"NFT Metadata Update Extension","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":"ERC-4906 is an optional metadata update extension. Its MetadataUpdate and BatchMetadataUpdate events signal JSON metadata changes so indexers can refresh, while collections without the extension still need a fallback refresh policy.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-4906","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-4906","sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-4906","type":"official-spec"}],"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","summary":"ERC-4906 is an optional metadata update extension. Its MetadataUpdate and BatchMetadataUpdate events signal JSON metadata changes so indexers can refresh, while collections without the extension still need a fallback refresh policy.","designerTakeaways":["Subscribe to ERC-4906 events and refetch metadata when the target collection implements the extension.","Show an Updated state only after a refresh succeeds, and keep stale/error states visible.","Debounce batch updates and retain a fallback refresh policy for collections without the optional events."],"applicability":{"whenToUse":["NFT metadata changes post-mint (reveals, evolving art).","Collection uses ERC-4906 update events.","Marketplaces must show fresh images."],"whenToAvoid":["Immutable metadata frozen at mint.","No event subscription infrastructure.","Updates so frequent UI cannot stabilize."]},"prototypeFirst":[{"screen":"Reveal moment refresh","why":"Pre-reveal to post-reveal is highest-stakes update.","covers":["Placeholder","Updating","Revealed"],"include":["Skeleton art","Refreshing spinner","New image fade-in"]},{"screen":"Updated badge on owned item","why":"Owners should know their NFT changed.","covers":["First view after update","Dismissed badge"],"include":["Updated chip","View changes link","Optional history"]},{"screen":"Batch metadata update","why":"Whole collection updates at once.","covers":["Batch event","Progress refresh"],"include":["Refreshing collection banner","Count updated","Done state"]},{"screen":"Stale cache fallback","why":"When refetch fails show honest state.","covers":["Fetch failed","Retry"],"include":["Could not refresh","Retry button","Last updated timestamp"]}],"mentalModel":[{"label":"Static metadata","description":"Metadata may change after mint; ERC-4906 optionally signals JSON metadata changes so indexers can refresh, while tokenURI-only or unsupported changes still need a fallback refresh policy."},{"label":"Update event","description":"Optional on-chain signal that the JSON metadata changed; a tokenURI-only URI change with unchanged JSON may not emit it."},{"label":"Refetch","description":"App pulls new JSON and image after event."},{"label":"Reveal","description":"Special case of update — placeholder to final art."},{"label":"Batch update","description":"Many tokens updated — refresh without N separate spinners."}],"statesToDesign":[{"state":"Current metadata displayed","trigger":"Cache valid.","userNeed":"See accurate art.","designResponse":"Normal card display."},{"state":"Update detected — refreshing","trigger":"ERC-4906 support is detected and a MetadataUpdate or BatchMetadataUpdate event is received.","userNeed":"Know image may change.","designResponse":"Subtle spinner overlay; keep old until new loads."},{"state":"Refresh complete","trigger":"New metadata fetched.","userNeed":"Notice change if owned.","designResponse":"Fade to new image; Updated badge optional."},{"state":"Batch collection refresh","trigger":"BatchMetadataUpdate.","userNeed":"Not see 1000 flickers.","designResponse":"Collection-level banner; debounced grid refresh."},{"state":"Refetch failed","trigger":"Gateway timeout.","userNeed":"Trust or retry.","designResponse":"Stale indicator with Retry refresh."}],"designDecisions":[{"question":"Notify owner on metadata update?","recommendation":"Optional push for owned tokens; silent for listings.","rationale":"Owners care; browsers do not need spam."},{"question":"Crossfade or hard swap?","recommendation":"Crossfade on reveal; instant on minor trait fix.","rationale":"Reveal is ceremonial; typo fix should be invisible."},{"question":"Cache TTL when no events?","recommendation":"Long cache with manual pull-to-refresh.","rationale":"4906 makes events primary refresh trigger."}],"problemsSolved":[{"problem":"Stale NFT images after reveal","oldWay":"Cache shows placeholder forever","newWay":"Event-driven refetch when the collection supports ERC-4906, with a fallback refresh policy otherwise","impact":"critical"},{"problem":"Platforms poll constantly","oldWay":"Wasteful polling every N seconds","newWay":"Use 4906 events as a refresh signal where supported, plus a fallback for collections without the optional extension","impact":"medium"},{"problem":"Users unaware metadata changed","oldWay":"Silent swap confuses owners","newWay":"Updated badge after refresh","impact":"medium"}],"uxPatterns":[{"name":"Event-Driven Refresh","description":"Auto-refetch on ERC-4906 metadata events.","components":["EventListener","RefreshOverlay","UpdatedBadge"],"userFlow":["Event fires","Refetch starts","New art loads","Badge shows"]},{"name":"Reveal Transition","description":"Placeholder to final art crossfade.","components":["PlaceholderArt","Crossfade","RevealBanner"],"userFlow":["Pre-reveal","Event received","Crossfade","Revealed state"]}],"antiPatterns":[{"pattern":"Never refetching after mint cache","why":"Permanent stale images post-reveal","instead":"Detect ERC-4906 support, subscribe when available, and retain a fallback refresh path","severity":"critical"},{"pattern":"Full grid flicker on batch update","why":"Epilepsy and distrust","instead":"Debounced batch refresh with banner","severity":"high"},{"pattern":"Hard swap without loading state","why":"Jarring image jump","instead":"Crossfade or skeleton during fetch","severity":"medium"}],"vocabulary":[{"use":"Artwork updated","avoid":"MetadataUpdate event emitted","why":"User-visible outcome."},{"use":"Refreshing","avoid":"Refetching tokenURI","why":"Loading state language."},{"use":"Reveal","avoid":"Batch metadata transition","why":"Collectible culture term."}],"specConstraints":[{"id":"metadata-update-event","constraint":"MetadataUpdate or BatchMetadataUpdate must be emitted when token JSON metadata changes.","appliesTo":"application","normativity":"normative","specQuote":"The `MetadataUpdate` or `BatchMetadataUpdate` event MUST be emitted when the JSON metadata of a token, or a consecutive range of tokens, is changed.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-4906#specification","designImplication":"Subscribe and refetch metadata after the event, show stale/loading/error states, and do not mark the card updated before refresh succeeds."},{"id":"metadata-permission","constraint":"Offchain metadata update triggers must have correct permission controls.","appliesTo":"account-implementation","normativity":"security-considerations","specQuote":"## Security Considerations\n\nIf there is an off-chain modification of metadata, a method that triggers `MetadataUpdate` can be added, but ensure that the function's permission controls are correct.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-4906#security-considerations","designImplication":"Show metadata provenance and update authority and treat unexpected changes as a trust/review state."}],"technicalNotes":"ERC-4906 is optional and defines MetadataUpdate(uint256 _tokenId) and BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId) as signals that JSON metadata changed. The specification recommends no event when only tokenURI changes while the referenced JSON is unchanged. Detect support, debounce batch refreshes, and keep a fallback policy for unsupported collections or missed events.","relatedStandards":[{"id":"ERC-721","relationship":"Metadata update extension"},{"id":"ERC-5773","relationship":"Multi-asset tokens may update per asset"}]},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-4906","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-4906","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4906","markdown":"https://www.eipsfordesigners.com/standards/ERC-4906/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4906/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4906","official":"https://ercs.ethereum.org/ERCS/erc-4906","discussion":"https://ethereum-magicians.org/search?q=ERC-4906"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}