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

# NFT assets

> How the Startale App displays NFTs a user holds, and the metadata structure your collection needs for that display to work correctly.

Users can hold NFTs from your Mini App in their smart account, and the Startale App surfaces them automatically in its Collectibles UI. There is no API to register a collection, display is driven entirely by standard onchain metadata that your contracts expose. Getting that metadata right is what determines whether your collection renders correctly.

## Where NFTs appear

| Surface                             | Behavior                                                                                                                                                                                                                                            |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Home screen (Collectibles tab)      | Groups the wallet's NFTs by issuing contract and shows up to 8 collection tiles. A count badge appears when a collection holds more than one token. Once the wallet holds more than 8 collections, a "View all" link appears, leading to `/wallet`. |
| `/wallet` screen (Collectibles tab) | Shows every collection the user holds, paginated via infinite scroll (25 collections per page).                                                                                                                                                     |

The app does not sort NFTs or collections client-side, display order comes directly from the wallet's NFT API response.

<Note>
  A newly received NFT can show a gray placeholder tile if its collection name hasn't finished backend enrichment yet. The app polls for updated data every 15 seconds for up to 60 seconds, then stops. If a tile is still incomplete after that window, treat it as a metadata issue rather than an enrichment delay.
</Note>

## Metadata structure

Two layers of metadata feed the Collectibles UI, and they serve different purposes.

### Token-level metadata (required)

Every NFT needs standard token metadata: `tokenURI()` for ERC-721, `uri()` for ERC-1155. The response must be JSON with an `image` field pointing to an actual image resource (a URL or `ipfs://` CID that resolves to `image/*` content). This is what renders in the NFT detail view, and what the app falls back to as a collection cover when collection-level metadata is missing or invalid.

### Collection-level metadata (optional)

`contractURI()` is optional. If you implement it, the Startale App uses its `image` field as the cover shown on collection tiles, instead of picking a token image. This gives you control over the tile's appearance, but only if the field is correct.

<Warning>
  If you implement `contractURI()`, its `image` field must resolve to an actual image resource (`image/*` Content-Type), not your project's website, a redirect page, or any other HTML page. A collection that returns its homepage URL in `image` does not fail outright: the URL passes the app's extension check, so it gets set as the tile's cover, fails to load, and falls back to a held token's image (or the placeholder, if none is available) rather than showing a visibly broken image. Collection-level metadata is indexed and cached on the backend rather than read live by the app, so a correction may take some time to propagate to the Collectibles UI.
</Warning>

You have two valid options:

1. **Skip `contractURI()` entirely.** The app falls back to a held token's image as the collection cover. Simplest option if you don't need a distinct collection-level cover.
2. **Implement `contractURI()` correctly.** Point `image` at a real image file.

```json theme={null}
// Collection-level metadata, contractURI() response
{
  "name": "Your Collection Name",
  "image": "https://yourproject.xyz/assets/collection-cover.webp"
}
```

```json theme={null}
// Token-level metadata, tokenURI()/uri() response
{
  "name": "Token #1",
  "image": "https://yourproject.xyz/assets/token-1.jpg",
  "attributes": [
    { "trait_type": "Rarity", "value": "Rare" }
  ]
}
```

<Info>
  The Startale App falls back to a token image when collection-level metadata is missing or unusable, picking one token's image and keeping it stable unless that specific token leaves the wallet. This exists to limit damage from bad data, not as a substitute for correct metadata: relying on it means your collection never gets a distinct cover, only whatever token image the app happens to pick.
</Info>
