
Other articles on this blog have said that a CID makes NFT metadata tamper-evident. This one shows you how to verify a CID yourself instead of taking that claim on faith, by recomputing it from a file and comparing it to what's on-chain. If they match, nothing changed. If they don't, something did.
TL;DR:
ipfs add --only-hash <file>, which computes a CID locally without uploading anythingA CIDv1 is built from four parts: a multibase prefix indicating the encoding (b for base32, the default), a version identifier, a multicodec identifying how the data is structured, and a multihash, which itself contains the hash algorithm used (SHA2-256 by default) and the resulting digest. None of this is assigned by whoever's hosting the file. It's derived entirely from the file's own bytes. Two identical files uploaded from two different computers by two different people produce the exact same CID, and per IPFS's own documentation, "any difference in the content will produce a different CID."
That's the whole mechanism behind CID-based tamper detection: there's no separate "integrity check" bolted on, the address and the fingerprint are the same thing.
NFT metadata sometimes references more than one file, an image plus a separate metadata JSON, or a folder of assets for a generative collection. ipfs add --only-hash works recursively too: pointed at a directory rather than a single file, it computes a CID for the whole folder structure the same way it would for one file, without uploading anything. This matters because a directory's CID depends on every file inside it, covered in more depth in how IPFS represents files and directories, so verifying a collection's root CID in one pass confirms every file inside it is unaltered, not just the top-level structure. It's the same verification principle scaled up: one recomputed hash, one comparison, covering an entire collection instead of a single asset.
The Kubo CLI (IPFS's reference implementation) has a flag built for exactly this: --only-hash.
ipfs add --only-hash --cid-version 1 my-nft-metadata.json
This computes what the CID would be if you pinned the file, without actually adding it to your local node or uploading it anywhere. It's a pure, local hash computation, useful specifically for verification: you're not trying to store the file, you're trying to confirm what its CID should be.
Put those two things together and you get a real, repeatable verification workflow:
ipfs://{cid} reference (through any gateway)ipfs add --only-hash --cid-version 1 on the downloaded fileipfs:// URI the NFT contract actually referencesIf they match, you've confirmed the content being served today is byte-for-byte the same as whatever was originally pinned under that CID, not just "probably fine" but cryptographically verified. If they don't match, either the gateway served you something different than the actual pinned content (worth investigating on its own), or the CID reference itself was never actually the file people assumed it was.
Recomputing a CID and getting a different result doesn't automatically mean the content changed, it's worth ruling out a simpler explanation first: CID version mismatch. An NFT minted a while back may reference a CIDv0 identifier (the 46-character string starting with Qm), while ipfs add --only-hash without an explicit flag defaults to CIDv1 on current versions of the Kubo CLI, producing a completely different-looking string (starting with b) for the exact same underlying content. This isn't a tampering signal, it's the same file represented two different ways. Always pass --cid-version 0 explicitly if the on-chain reference is a Qm... CIDv0 string, or convert one representation to the other before comparing, rather than concluding the content changed just because the string format doesn't match. The CID anatomy breakdown covers exactly what differs between the two versions if the distinction isn't already familiar.
A regular file you download once and move on. An NFT's metadata is a claim that persists as long as the token exists, someone minted it, someone else may buy it later based on what that metadata says, and there's no built-in mechanism forcing anyone to re-check it after the fact. Being able to independently verify a CID, rather than trusting whatever a marketplace's cached preview shows you, is the actual practical value of content addressing for this specific use case. It's not just a technical curiosity, it's the difference between "the metadata probably hasn't changed" and "I checked."
What determines an NFT's CID? The content of the file itself, hashed with SHA2-256 by default and combined with codec metadata. It's not assigned by a server or chosen by whoever uploads it.
Can I verify a CID without re-uploading the file? Yes, with ipfs add --only-hash <file> using the Kubo CLI. It computes the CID locally without adding the file to your node or the network.
What does it mean if my recomputed CID doesn't match the on-chain reference? Either the content you downloaded differs from what was originally pinned under that CID, or the reference itself doesn't point at what you expected. Either way, it's worth investigating before trusting the metadata.
Does changing even a small part of a file change its CID? Yes. Per IPFS's own documentation, any difference in content produces a different CID, there's no threshold, even a single byte change is enough.
Why does content addressing matter more for NFTs than regular file storage? NFT metadata is a persistent claim tied to a token that may be resold based on what it says. Independently verifying the CID confirms the metadata is exactly what was originally set, rather than trusting a marketplace's cached display.

IPFS defaults to 256 KiB fixed-size chunks, but also ships Rabin and Buzhash content-defined chunkers. Here is why the choice affects deduplication.

An IPFS CID is not a random string. It encodes a version, a codec, and a hash algorithm plus digest. Here is how to decode a real CID piece by piece.

IPFS does not use a B-tree for large directories. It uses a HAMT, a Hash Array Mapped Trie. Here is exactly how it shards a folder once it outgrows one block.

AIOZ Pin image resizing happens straight in the gateway URL, no upload step or separate service. Here is every img- parameter, with real srcset examples.

x402 payments let ERC-8004 weight a paid AI agent interaction more heavily than free work in its reputation score. Here is exactly how that link works.

AIOZ Pin NFT API calls pin an asset and its metadata as two tracked pins under one record. Here is how to automate it directly over REST, no SDK needed.