# How to Add Custom Assets or Tokens to Nautilus Wallet: A Developer Guide

> Developers learn to add custom assets or tokens to Nautilus Wallet by creating metadata, persisting it, and refreshing the runtime store for UI display. Follow this guide.

- Repository: [Nautilus Team/nautilus-wallet](https://github.com/nautls/nautilus-wallet)
- Tags: how-to-guide
- Published: 2026-03-07

---

**Developers can add custom tokens to Nautilus Wallet by creating an `IAssetInfo` metadata object, persisting it via `assetInfoDbService.addIfNotExists()`, and refreshing the runtime store with `assetsStore.loadMetadata()` to display the token in the UI.**

While Nautilus Wallet automatically discovers assets from the Ergo blockchain, developers often need to manually register test-net tokens, private tokens, or assets not exposed by the GraphQL endpoint. This guide explains how to programmatically add custom assets or tokens to the `nautls/nautilus-wallet` browser extension, ensuring they appear in the asset list with proper metadata and icons without requiring server-side changes.

## Define the Token Metadata

To register a custom token, first create a metadata object that implements the **`IAssetInfo`** interface defined in [`src/types/database.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/types/database.ts). This interface requires the token ID, name, decimal precision, and asset subtype.

```typescript
import type { IAssetInfo } from '@/types/database';
import { AssetSubtype } from '@/types/internal';

const MY_TOKEN: IAssetInfo = {
  id: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', // token-ID (hex string)
  name: 'MyCustomToken',
  decimals: 2,
  subtype: AssetSubtype.Fungible,
  // optional visual assets
  artworkUrl: 'https://example.com/my-token.png',
  artworkCover: 'https://example.com/my-token-cover.png'
};

```

The `AssetSubtype` enum (located in [`src/types/internal.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/types/internal.ts)) categorizes the token as `Fungible`, `PictureArtwork`, or other types, affecting how the UI renders the asset.

## Persist Metadata to Local Storage

Once defined, persist the metadata using **`assetInfoDbService.addIfNotExists()`** from [`src/database/assetInfoDbService.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/database/assetInfoDbService.ts). This method inserts records only when the token ID is not already present, preventing duplicate entries.

```typescript
import { assetInfoDbService } from '@/database/assetInfoDbService';

async function registerCustomToken() {
  await assetInfoDbService.addIfNotExists([MY_TOKEN]);
}

```

This step stores the token permanently in the browser's local IndexedDB, making it available across wallet sessions.

## Load Metadata into the Runtime Store

After persistence, you must refresh the in-memory cache so the UI can display the token name, decimals, and icon. Call **`assetsStore.loadMetadata()`** from [`src/stores/assetsStore.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/stores/assetsStore.ts), which checks the local database first via `assetInfoDbService.getAnyOf()` and falls back to the GraphQL service only for missing items.

```typescript
import { useAssetsStore } from '@/stores/assetsStore';

async function refreshMetadata() {
  const assetsStore = useAssetsStore();
  await assetsStore.loadMetadata([MY_TOKEN.id]);   // forces remote-fetch only if needed
}

```

This step bridges the gap between the database layer and the reactive UI store, ensuring the token appears instantly in the **Assets** view.

## Register Custom Icons (Optional)

To display a custom SVG or PNG instead of the default placeholder, map the token ID to an icon filename in **`assetIconMap`** from [`src/mappers/assetIconMap.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/mappers/assetIconMap.ts). Place the actual image file under `public/icons/assets/`.

```typescript
// src/mappers/assetIconMap.ts
export const assetIconMap = new Map<string, string>([
  // …existing entries…
  [
    '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
    'my-token.svg'   // place the file under public/icons/assets/
  ]
]);

```

The `<AssetIcon>` component uses this map to resolve the correct graphic for each token in the asset list.

## Complete Implementation Example

Combine these steps into a reusable utility module. This example shows how to register a token programmatically and refresh the UI from a Vue component.

```typescript
// src/utils/customToken.ts
import type { IAssetInfo } from '@/types/database';
import { AssetSubtype } from '@/types/internal';
import { assetInfoDbService } from '@/database/assetInfoDbService';
import { useAssetsStore } from '@/stores/assetsStore';

// 1️⃣ Token metadata
const MY_TOKEN: IAssetInfo = {
  id: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
  name: 'MyCustomToken',
  decimals: 2,
  subtype: AssetSubtype.Fungible,
  artworkUrl: 'https://example.com/my-token.png'
};

// 2️⃣ Persist metadata (run once, e.g., on extension install)
export async function registerMyToken() {
  await assetInfoDbService.addIfNotExists([MY_TOKEN]);
}

// 3️⃣ Refresh the runtime store (call after registration or when the app boots)
export async function refreshMyTokenMetadata() {
  const assetsStore = useAssetsStore();
  await assetsStore.loadMetadata([MY_TOKEN.id]);
}

```

You can trigger registration from a UI button or automatically on startup for test-net environments:

```vue
<!-- src/components/AddCustomTokenButton.vue -->
<template>
  <Button @click="addToken" variant="outline">
    Add MyCustomToken
  </Button>
</template>

<script setup lang="ts">
import { registerMyToken, refreshMyTokenMetadata } from '@/utils/customToken';
import { useToast } from '@/components/ui/toast';

const toast = useToast();

async function addToken() {
  try {
    await registerMyToken();          // persists the metadata
    await refreshMyTokenMetadata();   // updates the in-memory store
    toast.success('MyCustomToken added successfully');
  } catch (e) {
    toast.error('Failed to add token: ' + (e as Error).message);
  }
}
</script>

```

## Summary

- **Create an `IAssetInfo` object** with the token's hex ID, name, decimals, and subtype according to [`src/types/database.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/types/database.ts).
- **Persist the metadata** using `assetInfoDbService.addIfNotExists()` from [`src/database/assetInfoDbService.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/database/assetInfoDbService.ts) to avoid duplicates.
- **Refresh the runtime store** by calling `assetsStore.loadMetadata()` from [`src/stores/assetsStore.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/stores/assetsStore.ts) to make the token visible in the UI.
- **Optionally add a custom icon** by updating `assetIconMap` in [`src/mappers/assetIconMap.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/mappers/assetIconMap.ts) with the token ID and icon filename.

## Frequently Asked Questions

### What is the IAssetInfo interface in Nautilus Wallet?

The **`IAssetInfo`** interface is defined in [`src/types/database.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/types/database.ts) and serves as the contract for token metadata within the wallet. It requires properties including `id` (the token's unique hex string), `name`, `decimals` for precision, and `subtype` (imported from [`src/types/internal.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/types/internal.ts)). Optional fields like `artworkUrl` allow you to specify remote images for the token icon.

### How does assetInfoDbService prevent duplicate token entries?

The **`addIfNotExists`** method in [`src/database/assetInfoDbService.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/database/assetInfoDbService.ts) checks whether a token ID already exists in the local IndexedDB before inserting. It accepts an array of `IAssetInfo` objects and only adds new records, ensuring that calling the registration function multiple times does not create duplicate entries or overwrite existing metadata.

### Can I add custom icons for my tokens?

Yes. Map the token's hex ID to a local icon filename in **`assetIconMap`** from [`src/mappers/assetIconMap.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/mappers/assetIconMap.ts). Place the SVG or PNG file in the `public/icons/assets/` directory. The wallet's `<AssetIcon>` component automatically resolves and displays the custom graphic when rendering the asset list, falling back to a default placeholder if no mapping exists.

### Do I need to restart the wallet after adding a custom token?

No. After persisting the metadata with `assetInfoDbService.addIfNotExists()`, simply invoke **`assetsStore.loadMetadata([tokenId])`** to refresh the in-memory cache immediately. The token will appear in the Assets view without requiring a browser extension reload or application restart, as the store update triggers reactive UI changes.