Skip to Content

Profiles

🚧

Coming Soon — The ChainSocial SDK is not yet published. This documentation describes the planned API. Use the REST API for current integrations.

User profiles are the foundation of ChainSocial. Every user needs a profile before they can post.

Why Profiles Exist

Profiles serve multiple purposes:

  • Identity — Username, display name, bio, avatar
  • Discovery — Other users can find and follow you
  • Gate for actions — You need a profile to post, follow, or message

Creating a Profile

Users need a username (as bytes32) to create a profile. Use the stringToHex utility from viem.

import { stringToHex, padHex } from 'viem' // Convert username to bytes32 const username = padHex(stringToHex('alice'), { size: 32 }) // Create the profile const result = await client.profile.createProfile(username) console.log('Profile created:', result.hash)

Username Rules

  • Usernames are unique across the protocol
  • Must be lowercase alphanumeric (a-z, 0-9)
  • 3-20 characters
  • Cannot be reserved names

Profile Fields

Profile metadata is stored as content references. The profile system uses a flexible key-value structure.

Standard fields:

Field KeyDescription
displayNameHuman-readable name
bioUser biography
avatarProfile picture
coverImageBanner image
websitePersonal website URL
locationGeographic location

Setting a Field

import { stringToHex, padHex } from 'viem' // First, create content for the field value const bioContentId = await client.content.createInlineContent('Web3 developer and coffee enthusiast') // Then set the profile field const fieldKey = padHex(stringToHex('bio'), { size: 32 }) await client.profile.setProfileField(fieldKey, bioContentId)

Setting Multiple Fields (Batch)

More gas-efficient when updating multiple fields:

// Create content for each field const displayNameContent = await client.content.createInlineContent('Alice') const bioContent = await client.content.createInlineContent('Building cool stuff') // Batch update const fieldKeys = [ padHex(stringToHex('displayName'), { size: 32 }), padHex(stringToHex('bio'), { size: 32 }), ] const contentIds = [displayNameContent, bioContent] await client.profile.setProfileFieldBatch(fieldKeys, contentIds)

Removing a Field

const fieldKey = padHex(stringToHex('location'), { size: 32 }) await client.profile.removeProfileField(fieldKey)

Reading Profile Data

From the SDK

const fieldKey = padHex(stringToHex('bio'), { size: 32 }) const contentId = await client.profile.getProfileField(userAddress, fieldKey) // The contentId points to content storage // You'll need to resolve it to get the actual text

The API returns fully-resolved profile data:

const response = await fetch(`https://api.chainsocial.cc/api/profiles/${address}`) const data = await response.json() console.log(data.profile.username) // 'alice' console.log(data.profile.metadata?.bio) // 'Web3 developer...' console.log(data.profile.metadata?.avatar?.uri) // 'ipfs://...' console.log(data.followerCount) // 42

API response structure:

{ "profile": { "address": "0x...", "username": "alice", "joinedAt": 1704067200, "lastActiveAt": 1704153600, "isVerified": false, "isActive": true, "metadata": { "displayName": "Alice", "bio": "Web3 developer", "avatar": { "uri": "ipfs://bafkrei...", "mimeType": "image/png" }, "website": "https://alice.xyz" } }, "followerCount": 42, "followingCount": 18 }

Profile Metadata Schema

ChainSocial uses a standardized metadata format (CSPM-1):

{ "$schema": "https://chainsocial.cc/schemas/profile-metadata-v1.json", "version": "1.0", "displayName": "Alice", "bio": "Building on-chain social", "avatar": { "uri": "ipfs://bafkrei...", "mimeType": "image/png" }, "coverImage": { "uri": "ipfs://bafkrei...", "mimeType": "image/jpeg" }, "website": "https://alice.xyz", "location": "San Francisco", "links": [ { "type": "twitter", "url": "https://twitter.com/alice", "handle": "@alice" }, { "type": "github", "url": "https://github.com/alice" } ] }

Using ProfileMetadataBuilder

The SDK includes a builder for constructing valid metadata:

import { ProfileMetadataBuilder } from '@chainsocial/client' const metadata = new ProfileMetadataBuilder() .setDisplayName('Alice') .setBio('Web3 developer') .setAvatar('ipfs://bafkrei...', 'image/png') .setWebsite('https://alice.xyz') .addLink({ type: 'twitter', url: 'https://twitter.com/alice', handle: '@alice' }) .build() // Store as JSON in content system const metadataJson = JSON.stringify(metadata) const contentId = await client.content.createInlineContent(metadataJson)

Updating Avatar/Cover Images

Images should be uploaded to storage first, then referenced:

// 1. Upload image (example with your storage solution) const imageFile = await fetch('/path/to/avatar.png').then(r => r.blob()) const uploadResult = await uploadToStorage(imageFile) // Your upload function // 2. Build metadata with IPFS URI const metadata = new ProfileMetadataBuilder() .setAvatar(`ipfs://${uploadResult.cid}`, 'image/png') .build() // 3. Store metadata and update profile const contentId = await client.content.createInlineContent(JSON.stringify(metadata)) const fieldKey = padHex(stringToHex('metadata'), { size: 32 }) await client.profile.setProfileField(fieldKey, contentId)

Deactivating a Profile

Users can deactivate their profile (soft delete):

await client.profile.deactivateProfile()

Deactivated profiles:

  • Still exist on-chain
  • Won’t appear in feeds/search
  • Can be reactivated

Activity Tracking

Update your last-active timestamp (useful for “online” indicators):

await client.profile.updateLastActive()

Delegation: On-Behalf-Of

If you have delegation permissions, you can update someone else’s profile:

// Acting as a delegate for another user await client.profile.setProfileFieldOnBehalfOf( userAddress, // The profile owner fieldKey, contentId )

See the Advanced section for delegation setup.

Common Patterns

Check if User Has Profile

async function hasProfile(address: string): Promise<boolean> { const response = await fetch(`https://api.chainsocial.cc/api/profiles/${address}`) return response.ok }

Create Profile if Not Exists

async function ensureProfile(client, username: string) { const address = client.walletClient.account.address const response = await fetch(`https://api.chainsocial.cc/api/profiles/${address}`) if (!response.ok) { const usernameBytes = padHex(stringToHex(username), { size: 32 }) await client.profile.createProfile(usernameBytes) } }

Next Steps