# 3) iiprofile – Portable On-Chain Profile + Key-Value Storage for II \[Mainnet\]

**URL:** <https://forum.dfinity.org/t/3-iiprofile-portable-on-chain-profile-key-value-storage-for-ii-mainnet/69053>\
**Category:** Showcase\
**Created:** [May 17, 2026, 4:24pm UTC](https://forum.dfinity.org/t/3-iiprofile-portable-on-chain-profile-key-value-storage-for-ii-mainnet/69053 "2026-05-17T16:24:43Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![kayicp](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/kayicp/32/36679_2.png) [@kayicp](https://forum.dfinity.org/u/kayicp)\
**Post date:** [May 17, 2026, 4:24pm UTC](https://forum.dfinity.org/t/3-iiprofile-portable-on-chain-profile-key-value-storage-for-ii-mainnet/69053/1 "2026-05-17T16:24:43Z")

</div>

### **Introduction**

Every ICP app that wants to show a user profile asks the same questions: What’s your name? Upload a photo. Add your bio. Social links?

Users answer the same questions on every app they use. That data lives in isolated app databases — inaccessible to other apps, owned by the platform instead of the user, and reset every time the user tries a new dApp.

**iiprofile** changes this. It’s a portable, decentralized key-value store built on the iilink principal layer. Write your profile once. Every iilink-integrated app reads the same data — automatically, with no re-entry, no per-app setup, and no centralized data custodian.

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/e/8/e882101991b9394c228283b45ef079f473aad72b.jpeg)

It’s live on ICP mainnet. I’m shipping it alongside iilink and iiname as the third layer of a portable ICP identity stack.

* * *

### **The Problem**

The ICP ecosystem has a data portability problem. Because every app sees a different principal per user (the root problem iilink solves at the identity layer), there’s also no practical way to share user data between apps. Even if two apps wanted to share profile data, they’d have no common user identifier to key it on.

iilink solves the identity layer. iiprofile solves the data layer.

With a unified main principal from iilink, it’s now possible to attach persistent, user-owned data to that principal — and have every app in the ecosystem read from the same source of truth.

* * *

### **The Solution: iiprofile**

iiprofile is an on-chain **key-value store** where:

- -\>Storage is rented annually per iilink main principal

- -\> **Only the principal owner can write** (authenticated via Internet Identity + iilink proxy auth)

- -\> **Anyone can read** — apps make anonymous read calls with the user’s principal

- -\>Keys follow an open naming convention: `iiprofile:` _for standard profile fields, `yourapp:`_ for app-specific data

- -\>The same canister stores everything — one round-trip fetches a complete profile

* * *

### **Key Features**

**For users:**

- -\>One profile setup covers every iilink-integrated app going forward

- -\>Free public profile page at `/@yourname` (if you have an iiname) or via principal

- -\>Store name, bio, avatar, banner, CTA button, social handles, up to 5 custom links

- -\>Full control — only you can write to your store; revoke nothing, because apps only read

**For developers:**

- -\>Fetch a complete user profile in one batched call — no auth required

- -\>Write app-specific keys to the same store (`yourapp:theme`, `yourapp:preferences`, etc.)

- -\>Open key convention: define your own namespace, document it, other apps can interoperate

- -\>The key-value model is intentionally simple — no schema enforcement

* * *

### **Storage Plans**

All plans are annual (365 days), payable in ICP or TCYCLES:

| **Plan** | **TCYCLES / year** | **Storage** | **Max Keys** | **Writes / day** |
| --- | --- | --- | --- | --- |
| Starter | 0.1 | 64 KiB | 128 | 50 |
| Builder | 0.5 | 256 KiB | 512 | 300 |
| Power | 2.0 | 1 MiB | 1,024 | 500 |

Write quotas refill daily. Unused writes don’t carry over. Plans can be upgraded at any time with data preserved.

* * *

### **Standard Profile Keys**

The `iiprofile:*` namespace is an open convention — not enforced by the canister. Any app can read these keys. Any app can extend the convention with new keys.

```auto
iiprofile:name iiprofile:bio
iiprofile:photo_url iiprofile:banner_photo_url
iiprofile:background_photo_url
iiprofile:twitter iiprofile:github
iiprofile:discord iiprofile:telegram
iiprofile:email iiprofile:website
iiprofile:cta_text iiprofile:cta_button_text
iiprofile:cta_url iiprofile:cta_photo_url
iiprofile:link1_text iiprofile:link1_url
iiprofile:link2_text iiprofile:link2_url
iiprofile:link3_text iiprofile:link3_url
iiprofile:link4_text iiprofile:link4_url
iiprofile:link5_text iiprofile:link5_url

```

* * *

### **Developer Integration**

#### **Read a Full Profile (Anonymous, One Call)**

```auto
// main = { owner: Principal, subaccount: [] }
// This is the user's iilink main principal — you get it from the iilink auth flow

const args = [
  { main, key: 'iiprofile:name' },
  { main, key: 'iiprofile:bio' },
  { main, key: 'iiprofile:photo_url' },
  { main, key: 'iiprofile:twitter' },
  { main, key: 'iiprofile:website' },
  { main, key: 'iiprofile:cta_text' },
  { main, key: 'iiprofile:cta_url' },
  // ... include all keys you need, up to ~25 in one batch
];

const res = await iiprofile.akvs_values(args);

// Build a profile object from results
const profile = {};
res.results.forEach((opt, i) => {
  if (opt[0]?.Text) profile[args[i].key] = opt[0].Text;
});

// profile['iiprofile:name'] → 'Kay'
// profile['iiprofile:twitter'] → '@kayicp'
// profile['iiprofile:photo_url'] → 'https://...'

```

#### **Write Your App-Specific Keys**

I will implement opening iiprofile popup for your user to write your app keyvalues. Soon™.

* * *

### **The Open Key Convention**

One design decision worth highlighting: the `iiprofile:*` keys are a **convention** , not a permission system. The canister doesn’t enforce which keys mean what. This is intentional.

Any app can:

1. Read standard `iiprofile:*` keys to show a user’s profile

2. Write to its own `yourapp:*` namespace for preferences/settings

3. Publish their key definitions so other apps can interoperate

This creates a composable data layer where each new app that defines useful keys makes the entire ecosystem more valuable. A user’s iiprofile storage gradually becomes a portable data record that follows them everywhere.

* * *

### **Current State & Limitations**

- -\> **Annual renewal required** — there’s no auto-renew mechanism. An on-chain reminder system is planned.

- -\> **Early stage** — I’m the first user. The canister is live and functional but the ecosystem of apps reading from it is just getting started.

* * *

### **Relationship to iilink and iiname**

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/6/f/6fc89cdc0cc593cf0eb9b3f3ca6b0a2386f4d51a.jpeg)

These three projects are designed to work together:

- -\> **iilink** provides the unified principal — the common identifier that makes cross-app data portable

- -\> **iiname** makes that principal human-readable — giving users an @handlehandlehandlehandle across the ecosystem

- -\> **iiprofile** attaches persistent, portable data to that principal — profile, preferences, and app-specific settings

Each is independently useful, but together they form a complete portable identity layer for ICP.

* * *

### **Call to Action**

If you’re building any app that involves user profiles, display names, or per-user settings, I’d love for you to consider iiprofile as your data layer instead of building it from scratch.

**The integration path:**

1. Get the user’s iilink main principal from the iilink auth flow

2. Call `akvs_values()` with the keys you need — no auth required for reads

3. Display the result; fall back gracefully if the user hasn’t set up iiprofile yet

**Try it:** [https://kvya4-zaaaa-aaaac-qgtea-cai.icp0.io/](https://kvya4-zaaaa-aaaac-qgtea-cai.icp0.io/)

Backend canister: lywes-wiaaa-aaaac-qgtdq-cai ([dashboard](https://dashboard.internetcomputer.org/canister/lywes-wiaaa-aaaac-qgtdq-cai))

My iiprofile:

[https://kvya4-zaaaa-aaaac-qgtea-cai.icp0.io/@e6agv-wen3n-4a4y3-4zpeu-47coa-kso4c-vvow5-p5fbv-2pjg4-bm53l-lqe](https://kvya4-zaaaa-aaaac-qgtea-cai.icp0.io/@e6agv-wen3n-4a4y3-4zpeu-47coa-kso4c-vvow5-p5fbv-2pjg4-bm53l-lqe)

or replace the principal with my iiname:

[https://kvya4-zaaaa-aaaac-qgtea-cai.icp0.io/@kayicp](https://kvya4-zaaaa-aaaac-qgtea-cai.icp0.io/@kayicp)

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/8/c/8c2b62d755b7ece6f22b7203637bcbd1a71afb7b.jpeg)

**Feedback welcome.**

previous topics:

1. [iilink](https://forum.dfinity.org/t/1-iilink-one-unified-internet-identity-principal-across-ii-powered-apps-mainnet/69048)
2. [iiname](https://forum.dfinity.org/t/2-iiname-portable-usernames-for-ii-built-on-iilink-mainnet/69050)

byebye
