Mentions

This guide will show you how mentions work on Lens.


Mentions are tracked by the Lens API when included in the content field of the Post metadata.

Example
import { textOnly } from "@lens-protocol/metadata";
const metadata = textOnly({  content: `Hey @lens/stani, how are you?`,});

Lens supports two types of mentions: Account and Group mentions.

Account Mentions

In Lens, an Account can have multiple usernames, but only one username per Username Namespace.

Global Lens Namespace

A special case is the global Lens Username namespace (i.e., lens/). In this case, account mentions take the familiar form:

@lens/<local_name>

where <local_name> is the Lens Account's name under the global Lens Username namespace.

For example:

Hey @lens/stani, how are you?

Custom Namespaces

The general format for a mention is:

@<namespace_address>/<account_address>

where:

  • <namespace_address>: The address of the Username namespace contract associated with the account.

  • <account_address>: The address of the Lens Account being mentioned.

For example:

Hey @0x123abc456…/0x789def123…, how are you?
  • 0x123abc456… is the Username namespace contract address.

  • 0x789def123… is the mentioned Lens Account address.

Group Mentions

Group mentions are similar to Account mentions, but with a different format:

#<group_address>

where <group_address> is the address of the Group being mentioned.

For example:

To all #0x123abc456… members, please check the latest update.

Rendering Mentions

Use the post.mentions field to replace raw mentions in the Post content with a more user-friendly format.

const content = "Hey @0x123abc456…/0x789def123…, how are you?";
const processed = post.mentions.reduce(  (updated, mention) =>    updated.replace(mention.replace.from, mention.replace.to),  content);
// Hey @lens/wagmi, how are you?

Below a more detailed example with React.

1

Mention Components

Define components for group and account mentions.

mentions.tsx
import React from "react";
export function AccountMention({ children, address }: MentionProps) {  return <a href={`/account/${address}`}>{children}</a>;}
export function GroupMention({ children, address }: MentionProps) {  return <a href={`/group/${address}`}>{children}</a>;}
type MentionProps = {  children: React.ReactNode;  account: string;};

2

Render Post Content

Replace mentions in the Post content with the corresponding mention component.

This example use markdown-to-jsx to render the Post content, but you can use any other library or custom renderer.

import React from "react";import Markdown from "markdown-to-jsx";
import { AccountMention } from "./AccountMention";import { GroupMention } from "./GroupMention";import { PostContentProps } from "./PostContentProps";
export function PostContent({ content, mentions }: PostContentProps) {  // Replace mentions in content with custom tags  const processed = mentions.reduce((updated, mention) => {    switch (mention.__typename) {      case "AccountMention":        return updated.replace(          mention.replace.from,          `<AccountMention address="${mention.account}">${mention.replace.to}</AccountMention>`        );      case "GroupMention":        return updated.replace(          mention.replace.from,          `<GroupMention address="${mention.group}">${mention.replace.to}</GroupMention>`        );      default:        return updated;    }  }, content);
  // Render the processed content with Markdown  return (    <Markdown      options={{        overrides: {          AccountMention: {            component: AccountMention,          },          GroupMention: {            component: GroupMention,          },        },      }}    >      {processed}    </Markdown>  );}

Adding Mentions

It's app responsibility to aid users in selecting the correct Account and format mentions correctly in the Post's metadata content.

Account Mentions

When the user types @ followed by a character, the app should open a lookup interface to help the user select the desired Account.

Hey @stan

1

Account Lookup

Use the accounts query to search for Accounts that have a Username matching the search term under the specified namespace.

query {  accounts(    request: {      filter: { searchBy: { localNameQuery: "stan" } }      orderBy: BEST_MATCH    }  ) {    items {      address      username {        value        namespace {          address        }      }      metadata {        name        picture      }    }    pageInfo {      prev      next    }  }}

Make sure to use the BEST_MATCH order for the orderBy field to ensure the most relevant results are returned.

In case of multiple namespaces, you can alias the username field to get an account's username under a specific namespace. It's your app's responsibility to determine which username to display to the user.

2

Display Account Selection

Let's say the previous step returned the following accounts:

lens/stanilens/stanleylens/stanford

On user's selection, use the provided data to render a user-friendly mention. For example you can use the username.value like so:

Hey @<selected.username.value>

3

Populate Mention in Content

Finally, when submitting the post, include the mention in the Post's metadata content field according to the specification above.

For the global Lens Username namespace, the mention format remains unchanged:

Example
import { textOnly } from "@lens-protocol/metadata";
const metadata = textOnly({  content: `Hey @${selected.username.value}, how are you?`,});

For custom Username namespaces, include the namespace and account addresses as specified:

Example
import { textOnly } from "@lens-protocol/metadata";
const metadata = textOnly({  content: `Hey @${selected.username1.namespace.address}/${selected.address}, how are you?`,});

That's it—the Lens indexer will track the mention and notify the mentioned Account.

Group Mentions

When the user types # followed by a character, the app should open a lookup interface to help the user select the desired Group.

To all #build

1

Group Lookup

Use the groups query to search for Groups that have a name matching the search term.

Query
query {  groups(request: { filter: { searchQuery: "build" } }) {    items {      address      metadata {        description        icon        name      }    }    pageInfo {      prev      next    }  }}

2

Display Group Selection

Let's say the previous step returned the following groups:

Response
{  "data": {    "groups": {      "items": [        {          "address": "0x1234…",          "metadata": {            "description": "A group for builders",            "icon": "https://example.com/icon.png",            "name": "Builders"          }        },        {          "address": "0x5678…",          "metadata": {            "description": "A group for building",            "icon": "https://example.com/icon.png",            "name": "Building"          }        }      ],      "pageInfo": {        "prev": null,        "next": null      }    }  }}

On user's selection, use the provided data to render a user-friendly mention.

To all #<selected.metadata.name>

3

Populate Mention in Content

Finally, when submitting the post, include the mention in the Post's metadata content field according to the specification above.

Example
import { textOnly } from "@lens-protocol/metadata";
const metadata = textOnly({  content: `To all #${selected.address} members, please check the latest update.`,});

That's it—the Lens indexer will track the mention and populate the post.mentions field with the necessary data.