> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ton.org/llms.txt
> Use this file to discover all available pages before exploring further.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.ton.org/feedback

```json
{
  "path": "/standard/tokens/metadata",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Metadata

export const Aside = ({type = "note", title = "", icon = "", iconType = "regular", children}) => {
  const asideVariants = ["note", "tip", "caution", "danger"];
  const asideComponents = {
    note: {
      outerStyle: "border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10",
      innerStyle: "text-sky-900 dark:text-sky-200",
      calloutType: "note",
      icon: <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-sky-500" aria-label="Note">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
    },
    tip: {
      outerStyle: "border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10",
      innerStyle: "text-emerald-900 dark:text-emerald-200",
      calloutType: "tip",
      icon: <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="text-emerald-600 dark:text-emerald-400/80 w-3.5 h-auto" aria-label="Tip">
          <path d="M3.12794 12.4232C3.12794 12.5954 3.1776 12.7634 3.27244 12.907L3.74114 13.6095C3.88471 13.8248 4.21067 14 4.46964 14H6.15606C6.41415 14 6.74017 13.825 6.88373 13.6095L7.3508 12.9073C7.43114 12.7859 7.49705 12.569 7.49705 12.4232L7.50055 11.3513H3.12521L3.12794 12.4232ZM5.31288 0C2.52414 0.00875889 0.5 2.26889 0.5 4.78826C0.5 6.00188 0.949566 7.10829 1.69119 7.95492C2.14321 8.47011 2.84901 9.54727 3.11919 10.4557C3.12005 10.4625 3.12175 10.4698 3.12261 10.4771H7.50342C7.50427 10.4698 7.50598 10.463 7.50684 10.4557C7.77688 9.54727 8.48281 8.47011 8.93484 7.95492C9.67728 7.13181 10.1258 6.02703 10.1258 4.78826C10.1258 2.15486 7.9709 0.000106649 5.31288 0ZM7.94902 7.11267C7.52078 7.60079 6.99082 8.37878 6.6077 9.18794H4.02051C3.63739 8.37878 3.10743 7.60079 2.67947 7.11294C2.11997 6.47551 1.8126 5.63599 1.8126 4.78826C1.8126 3.09829 3.12794 1.31944 5.28827 1.3126C7.2435 1.3126 8.81315 2.88226 8.81315 4.78826C8.81315 5.63599 8.50688 6.47551 7.94902 7.11267ZM4.87534 2.18767C3.66939 2.18767 2.68767 3.16939 2.68767 4.37534C2.68767 4.61719 2.88336 4.81288 3.12521 4.81288C3.36705 4.81288 3.56274 4.61599 3.56274 4.37534C3.56274 3.6515 4.1515 3.06274 4.87534 3.06274C5.11719 3.06274 5.31288 2.86727 5.31288 2.62548C5.31288 2.38369 5.11599 2.18767 4.87534 2.18767Z"></path>
        </svg>
    },
    caution: {
      outerStyle: "border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10",
      innerStyle: "text-amber-900 dark:text-amber-200",
      calloutType: "warning",
      icon: <svg className="flex-none w-5 h-5 text-amber-400 dark:text-amber-300/80" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-label="Warning">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
        </svg>
    },
    danger: {
      outerStyle: "border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10",
      innerStyle: "text-red-900 dark:text-red-200",
      calloutType: "danger",
      icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" className="text-red-600 dark:text-red-400/80 w-4 h-4" aria-label="Danger">
          <path d="M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zm41.6-48c-4.3 7.4-4.3 16.6 0 24l88.3 152.9c4.3 7.4 12.2 12 20.8 12l176.6 0c8.6 0 16.5-4.6 20.8-12L453.4 268c4.3-7.4 4.3-16.6 0-24L365.1 91.1c-4.3-7.4-12.2-12-20.8-12l-176.6 0c-8.6 0-16.5 4.6-20.8 12L58.6 244zM256 128c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"></path>
        </svg>
    }
  };
  let variant = type;
  let gotInvalidVariant = false;
  if (!asideVariants.includes(type)) {
    gotInvalidVariant = true;
    variant = "danger";
  }
  const iconVariants = ["regular", "solid", "light", "thin", "sharp-solid", "duotone", "brands"];
  if (!iconVariants.includes(iconType)) {
    iconType = "regular";
  }
  return <>
      <div className={`callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border ${asideComponents[variant].outerStyle}`} data-callout-type={asideComponents[variant].calloutType}>
        <div className="mt-0.5 w-4" data-component-part="callout-icon">
          {}
          {icon === "" ? asideComponents[variant].icon : <Icon icon={icon} iconType={iconType} size={14} />}
        </div>
        <div className={`text-sm prose min-w-0 w-full ${asideComponents[variant].innerStyle}`} data-component-part="callout-content">
          {gotInvalidVariant ? <p>
              <span className="font-bold">
                Invalid <code>type</code> passed!
              </span>
              <br />
              <span className="font-bold">Received: </span>
              {type}
              <br />
              <span className="font-bold">Expected one of: </span>
              {asideVariants.join(", ")}
            </p> : <>
              {title && <p className="font-bold">{title}</p>}
              {children}
            </>}
        </div>
      </div>
    </>;
};

The metadata standard covering NFTs, NFT collections, and jettons is outlined in [TEP-64](https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md) (TON Enhancement Proposal 64).

On TON, entities can have three types of metadata: on-chain, semi-chain, and off-chain.

* **On-chain metadata:** stored on the blockchain, including name, attributes, and image.
* **Off-chain metadata:** stored via a link to a metadata file hosted off-chain.
* **Semi-chain metadata:** a hybrid approach that stores small fields (e.g., name or attributes) on-chain, while hosting the image off-chain and storing only a link to it.

## Snake data encoding

The Snake encoding allows a portion of data to be stored in a standardized cell, with the remainder stored recursively in child cells. In this scheme, Snake-encoded data is typically prefixed with the `0x00` byte (see the note below for exceptions). TL-B schema:

```tlb title="TL-B" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
tail#_ {bn:#} b:(bits bn) = SnakeData ~0;
cons#_ {bn:#} {n:#} b:(bits bn) next:^(SnakeData ~n) = SnakeData ~(n + 1);
```

[Read more about similar examples](/languages/tl-b/complex-and-non-trivial-examples).

When the payload exceeds the maximum size of a single cell, Snake stores the remaining data in child cells. Part of the data is placed in the root cell, and the rest in the first child cell, continuing recursively until all data is stored.

Below is an example of Snake encoding and decoding in TypeScript:

<Aside type="note">
  `bufferToChunks`, `BitBuilder`, and `BitReader` are provided by the surrounding tooling and helper utilities.
</Aside>

```ts title="TypeScript" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
export function makeSnakeCell(data: Buffer): Cell {
  const chunks = bufferToChunks(data, 127)

  if (chunks.length === 0) {
    return beginCell().endCell()
  }

  if (chunks.length === 1) {
    return beginCell().storeBuffer(chunks[0]).endCell()
  }

  let curCell = beginCell()

  for (let i = chunks.length - 1; i >= 0; i--) {
    const chunk = chunks[i]

    curCell.storeBuffer(chunk)

    if (i - 1 >= 0) {
      const nextCell = beginCell()
      nextCell.storeRef(curCell)
      curCell = nextCell
    }
  }

  return curCell.endCell()
}

export function flattenSnakeCell(cell: Cell): Buffer {
  let c: Cell | null = cell;

  const bitResult = new BitBuilder();
  while (c) {
    const cs = c.beginParse();
    if (cs.remainingBits === 0) {
      break;
    }

    const data = cs.loadBits(cs.remainingBits);
    bitResult.writeBits(data);
    c = c.refs && c.refs[0];
  }

  const endBits = bitResult.build();
  const reader = new BitReader(endBits);

  return reader.loadBuffer(reader.remaining / 8);
}
```

The `0x00` byte prefix is not always required in the root cell when using Snake, for example, with off-chain NFT content. Also, cells are filled with bytes rather than bits to simplify parsing. To avoid issues when adding a reference in a child cell after it has already been written to its parent, the Snake cell is constructed in reverse order.

## Chunked encoding

The chunked encoding stores data in a dictionary that maps `chunk_index` to a chunk. Chunked encoding must be prefixed with the `0x01` byte. This in-structure marker is distinct from the top-level content marker `0x01` that indicates off-chain content. TL-B schema:

```tlb title="TL-B" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
chunked_data#_ data:(HashMapE 32 ^(SnakeData ~0)) = ChunkedData;
```

Below is an example of chunked data decoding in TypeScript:

```typescript title="TypeScript" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
interface ChunkDictValue {
  content: Buffer;
}
export const ChunkDictValueSerializer = {
  serialize(src: ChunkDictValue, builder: Builder) {},
  parse(src: Slice): ChunkDictValue {
    const snake = flattenSnakeCell(src.loadRef());
    return { content: snake };
  },
};

export function ParseChunkDict(cell: Slice): Buffer {
  const dict = cell.loadDict(
    Dictionary.Keys.Uint(32),
    ChunkDictValueSerializer
  );

  let buf = Buffer.alloc(0);
  for (const [_, v] of dict) {
    buf = Buffer.concat([buf, v.content]);
  }
  return buf;
}
```

## NFT metadata attributes

| Attribute     | Type         | Requirement | Description                                                                                             |
| ------------- | ------------ | ----------- | ------------------------------------------------------------------------------------------------------- |
| `uri`         | ASCII string | optional    | A URI pointing to a JSON document with metadata used by the semi-chain content layout.                  |
| `name`        | UTF-8 string | optional    | Identifies the asset.                                                                                   |
| `description` | UTF-8 string | optional    | Describes the asset.                                                                                    |
| `image`       | ASCII string | optional    | A URI pointing to a resource with an image MIME type.                                                   |
| `image_data`  | binary       | optional    | Either a binary representation of the image for the on-chain layout or base64 for the off-chain layout. |

## Jetton metadata attributes

| Attribute      | Type         | Requirement | Description                                                                                                                                                                                                                                                |
| -------------- | ------------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uri`          | ASCII string | optional    | A URI pointing to a JSON document with metadata used by the semi-chain content layout.                                                                                                                                                                     |
| `name`         | UTF-8 string | optional    | Identifies the asset.                                                                                                                                                                                                                                      |
| `description`  | UTF-8 string | optional    | Describes the asset.                                                                                                                                                                                                                                       |
| `image`        | ASCII string | optional    | A URI pointing to a resource with an image MIME type.                                                                                                                                                                                                      |
| `image_data`   | binary       | optional    | Either a binary representation of the image for the on-chain layout or base64 for the off-chain layout.                                                                                                                                                    |
| `symbol`       | UTF-8 string | optional    | Token symbol — for example, "XMPL" — used in the form "You have received 99 XMPL".                                                                                                                                                                         |
| `decimals`     | UTF-8 string | optional    | The number of decimal places used by the token. If not specified, the default is 9. A UTF-8–encoded string containing a number from 0 to 255; for example, 8 means the on-chain amount must be divided by 100000000 to get the user-facing representation. |
| `amount_style` | string       | optional    | Defines how token amounts should be displayed for external applications. One of `n`, `n-of-total`, `%`.                                                                                                                                                    |
| `render_type`  | string       | optional    | Indicates how external applications should categorize and render the token. `currency` — display as a currency (default). `game` — game-style display: renders like an NFT, also shows the number of tokens, and respects `amount_style`.                  |

### `amount_style`

* `n` — number of jettons (default). If the user has 100 tokens with 0 decimals, display 100.
* `n-of-total` — the number of jettons out of the total issued. For example, if the `totalSupply` is 1000 and the user has 100, display "100 of 1000" (or an equivalent representation of the ratio).
* `%` — the percentage of total issued jettons. For example, with a total of 1000 and a user balance of 100, display 10% (100 ÷ 1000 = 0.1).

### `render_type`

* `currency` — display as a currency (default).
* `game` — game-style display that appears as an NFT, shows the number of tokens, and respects `amount_style`.

### `decimals`

<Aside type="danger" title="Funds at risk">
  Each jetton stores a `decimals` parameter in its metadata that determines how amounts are displayed. Transferring without accounting for `decimals` can result in sending drastically more tokens than expected.

  Mitigation: Always retrieve and apply the correct `decimals` value before calculating transfer amounts. Test transfers with small amounts on testnet first.
</Aside>

The `decimals` parameter defines the number of decimal places for displaying token amounts. The on-chain balance is stored as an integer in the smallest unit (nano-tokens), and must be divided by 10^decimals to get the user-facing value.

Common values:

* Most jettons use `decimals: 9` (default when not specified)
* USDT uses `decimals: 6`

Example: If the on-chain balance is 1000000000 nano-tokens:

* With `decimals: 9` → displayed as 1.0 token
* With `decimals: 6` → displayed as 1000.0 tokens

When transferring jettons programmatically, the amount must be calculated as: `on_chain_amount = display_amount × 10^decimals`.

For example, to transfer 1 USDT (`decimals: 6`):

* Correct on-chain amount: `1 × 10^6 = 1000000`
* Incorrect (using default 9): `1 × 10^9 = 1000000000` (transfers 1000 USDT instead of 1)

## Parsing metadata

To parse metadata, first retrieve the NFT data from the blockchain. For details, see [retrieving NFT data](/standard/tokens/nft/metadata).

After the on-chain NFT data is retrieved, determine the content type by reading the first byte of the content, then parse accordingly.

### Off-chain

If the metadata byte string starts with `0x01`, the content is off-chain. Decode the remainder using Snake as an ASCII string to obtain the URL. Once you fetch the off-chain metadata and identification data, the process is complete. Example URL for off-chain NFT metadata:
`https://s.getgems.io/nft/b/c/62fba50217c3fe3cbaad9e7f/95/meta.json`

Contents of the referenced URL:

```json title="json" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
{
   "name": "TON Smart Challenge #2 Winners Trophy",
   "description": "TON Smart Challenge #2 Winners Trophy 1 place out of 181",
   "image": "https://s.getgems.io/nft/b/c/62fba50217c3fe3cbaad9e7f/images/943e994f91227c3fdbccbc6d8635bfaab256fbb4",
   "content_url": "https://s.getgems.io/nft/b/c/62fba50217c3fe3cbaad9e7f/content/84f7f698b337de3bfd1bc4a8118cdfd8226bbadf",
   "attributes": []
}
```

### On-chain and semi-chain

If the metadata byte string starts with `0x00`, it indicates on-chain or semi-chain NFT metadata.

The metadata is stored in a dictionary where the key is the SHA-256 hash of the attribute name, and the value is data stored using the Snake or chunked format.

Read known attributes such as `uri`, `name`, `image`, `description`, and `image_data`. If the `uri` field is present, the layout is semi-chain: download the off-chain content specified by `uri` and merge it with the dictionary values.

Examples:

On-chain NFT: [`EQBq5z4N_GeJyBdvNh4tPjMpSkA08p8vWyiAX6LNbr3aLjI0`](https://tonviewer.com/EQBq5z4N_GeJyBdvNh4tPjMpSkA08p8vWyiAX6LNbr3aLjI0)

Semi-chain NFT: [`EQB2NJFK0H5OxJTgyQbej0fy5zuicZAXk2vFZEDrqbQ_n5YW`](https://tonviewer.com/EQB2NJFK0H5OxJTgyQbej0fy5zuicZAXk2vFZEDrqbQ_n5YW)

On-chain jetton master: [`EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs`](https://tonviewer.com/EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs)

## How to parse

Use the following API to parse metadata: [API Metadata](/ecosystem/api/toncenter/v3/accounts/metadata?playground=open). It handles most cases within gas limits; in rare cases, parsing may fail.

## Important notes on NFT metadata

1. For NFT metadata, the `name`, `description`, and `image` (or `image_data`) fields are commonly used to display the NFT.
2. For jetton metadata, the `name`, `symbol`, `decimals`, and `image` (or `image_data`) fields are commonly used.
3. Anyone can create an NFT or jetton using any `name`, `description`, or `image`. To prevent scams and confusion, apps should clearly distinguish tokens by their address rather than by names or tickers.
4. Some items may include a `video` field linking to video content associated with the NFT or jetton.

## References

* [TON Enhancement Proposal 64 (TEP-64)](https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md)
