Follow and Unfollow
Learn how to follow and unfollow Lens Profiles.
The ability to follow and unfollow profiles enables users to customize their social graph, thereby choosing the content they wish to interact with.
Follow Policies
A Follow policy is essentially a set of rules that determine who can follow a Profile.
You can choose from the following built-in options:
Anyone: Any Profile can follow. This is also the default policy.
No one: No Profile can follow.
Charged: Any Profile can follow, but they must pay a one-time fee.
You can also implement custom Follow policies by using an Unknown Follow Module.
Read Follow Policy
The initial step in implementing any Follow functionality is to understand the Follow policy of the target Profile.
These examples primarily deal with built-in Follow policies. For guidance on managing custom Follow policies, please consult the Follow Modules page.
- React SDK
- Others
The resolveFollowPolicy helper function can be used to convert the profile.followModule property into a developer-friendly FollowPolicy object.
Available in @lens-protocol/react-web and @lens-protocol/react-native
When combined with the ProfileSession from the useSession hook, this approach is especially handy for creating a user interface that lets users view and modify their own Follow policy.
MyFollowPolicy.tsx
import { FollowPolicyType, ProfileSession, resolveFollowPolicy,} from '@lens-protocol/react-web';import { formatFollowFee } from './formatFollowFee';
function MyFollowPolicy({ profileSession }: { profileSession: ProfileSession }) { const followPolicy = resolveFollowPolicy(profileSession.profile);
switch (followPolicy.type) { case FollowPolicyType.UNKNOWN: return <p>Custom Follow policy: ${followPolicy.contractAddress}</p>;
case FollowPolicyType.ANYONE: return <p>Anyone can follow you</p>;
case FollowPolicyType.NO_ONE: return <p>No one can follow you</p>;
case FollowPolicyType.CHARGE: return ( <p> You charge {formatFollowFee(followPolicy)} to follow you </p> ); }}
You can also use the resolveFollowPolicy function with any Profile object to display the Follow policy details.
Below, you'll find a reference implementation of the formatFollowFee helper:
formatFollowFee.ts
import { Amount, Asset, ChargeFollowPolicy } from '@lens-protocol/react-web';
function formatAmount(amount: Amount<Asset>) { return `${amount.toSignificantDigits()} ${amount.asset.symbol}`;}
export function formatFollowFee({ amount, rate }: ChargeFollowPolicy) { if (rate) { const fiat = amount.convert(rate); return `${formatAmount(amount)} (${formatAmount(fiat)})`; } return formatAmount(amount);}
You can find more details about the Amount class in the reference documentation.
Update Follow Policy
To modify a Profile's Follow policy, you must update the underlying Follow Module and its configuration.
You must be authenticated with the Profile for which you intend to update the Follow policy. See Profile Login for more information.
Anyone Can Follow
Any profile will be able to follow the authenticated profile.
- React SDK
- JavaScript SDK
- API
You can use the useUpdateFollowPolicy hook to update the Follow policy of the authenticated profile.
Available in @lens-protocol/react-web and @lens-protocol/react-native
AnyoneCanFollow.tsx
import { FollowPolicyType, useUpdateFollowPolicy,} from '@lens-protocol/react-web';
export function AnyoneCanFollow() { const { execute, loading } = useUpdateFollowPolicy();
const update = async () => { const result = await execute({ followPolicy: { type: FollowPolicyType.ANYONE, }, });
// detect if occurred if (result.isFailure()) { window.alert(result.error.message); return; }
window.alert('Follow policy updated!'); };
return ( <button onClick={update} disabled={loading}> Allow anyone to follow me </button> );}
The execute function will not return until the operation is fully completed, which includes being mined and indexed by the Lens API.
No One Can Follow
This setting prevents any profile from following the authenticated profile. It's useful for temporarily disabling the follow functionality for a profile.
- React SDK
- JavaScript SDK
- API
DisableFollowing.tsx
import { FollowPolicyType, useUpdateFollowPolicy,} from '@lens-protocol/react-web';
export function DisableFollowing() { const { execute, loading } = useUpdateFollowPolicy();
const update = async () => { const result = await execute({ followPolicy: { type: FollowPolicyType.NO_ONE, }, });
if (result.isFailure()) { window.alert(result.error.message); return; }
window.alert('Follow policy updated!'); };
return ( <button onClick={update} disabled={loading}> Disable following </button> );}
Charge to Follow
Any profile wishing to follow the authenticated profile will be required to pay a one-time fee.
- React SDK
- JavaScript SDK
- API
The Amount.erc20 method can be used to create an Amount object for the given currency and value.
ChargedFollow.tsx
import { Amount, FollowPolicyType, useUpdateFollowPolicy,} from '@lens-protocol/react-web';
// assuming `amount` is the current follow fee amount from the Profile's Follow policyexport function ChargeToFollow({ amount }: { amount: Amount }) { const { execute, loading } = useUpdateFollowPolicy();
const update = async (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault();
const formData = new FormData(event.currentTarget); const value = formData.get('value') as string;
const result = await execute({ followPolicy: { type: FollowPolicyType.CHARGE, amount: Amount.erc20(amount.asset, value),
// you can also specify a different recipient, defaults to the Profile owner address // recipient: '0xDB6501ef5892CcB7531389c5A5aF720C9e0041Af', }, });
if (result.isFailure()) { window.alert(result.error.message); return; }
window.alert('Follow policy updated!'); };
return ( <form onSubmit={update}> <label>Fee Amount</label> <input defaultValue={amount.toSignificantDigits(4)} name="value" type="number" />
{amount.asset.symbol} </label>
<button type='submit' disabled={loading}> Save </button> </form> );}
You can also combine this with currency objects selected from the useCurrencies hook (for example, through a dropdown menu) to choose a different currency.
Follow a Profile
In this section, you'll learn how to follow a Profile, assuming that the target Profile's Follow policy is set to either FollowPolicyType.ANYONE or FollowPolicyType.CHARGE. For information on handling custom Follow policies, refer to the Follow Modules page.
You must be authenticated with a Profile to follow another Profile. See Profile Login for more information.
- React SDK
- JavaScript SDK
- API
The examples provided use @lens-protocol/react-web to create a follow functionality in a React web application. This process can also be implemented in React Native using the @lens-protocol/react-native package.
Begin by checking if the logged-in Profile is already following the target Profile using the profile.operations.isFollowedByMe property. This property returns an OptimisticStatusResult object, which is optimistically updated when a follow or unfollow operation is performed.
type OptimisticStatusResult = { value: boolean; isFinalisedOnchain: boolean;};
In this context,
value indicates whether the logged-in Profile is following the target Profile.
isFinalisedOnchain specifies whether the value has been finalized on-chain or it's still in an optimistic state.
This value can be used, for instance, in a <FollowToggle> component to decide whether to render a <FollowButton> or an <UnfollowButton>.
FollowToggle.tsx
import { Profile } from "@lens-protocol/react-web";
function FollowToggle({ profile }: { profile: Profile }) {
if (profile.operations.isFollowedByMe.value) { return <UnfollowButton profile={profile} />; }
return <FollowButton profile={profile} />;}
Next, determine if it's possible to follow the target Profile at any given time using the profile.operations.canFollow property. This property can have one of the following tri-state values:
TriStateValue.No: The Profile cannot be followed either because their Follow policy does not permit it, or because a pending operation would cause any follow operation to fail if executed.
TriStateValue.Yes: The Profile can be followed.
TriStateValue.Unknown: It cannot be determined whether the Profile can be followed. This can occur if the Profile uses a custom Follow policy.
FollowButton.tsx
import { Profile, TriStateValue } from "@lens-protocol/react-web";
export function FollowButton({ profile }: { profile: Profile }) { return ( <button disabled={profile.operations.canFollow !== TriStateValue.Yes}> Follow </button> );}
Then, use the useFollow hook to follow the target Profile, provided that the Profile's Follow policy is not set to FollowPolicyType.NO_ONE.
The hook prioritizes the Signless Experience when available; if not, it resorts to a signed experience.
import { Profile, useFollow } from "@lens-protocol/react-web";
// ...
const { execute } = useFollow();
// ...
const result = await execute({ profile });
if (result.isFailure()) {
// error handling return;}
// continue ...
Next, the Result<T, E> object returned by the execute callback can be used to differentiate between successful requests and potential failures.
In addition to the standard error handling, the useFollow hook can yield two additional errors:
InsufficientAllowanceError: This error occurs when the user's wallet hasn't approved the Follow Module contract to access the required follow fee amount.
InsufficientFundsError: This error occurs when the user's wallet doesn't have sufficient funds to pay the follow fee.
if (result.isFailure()) { switch (result.error.name) { case 'InsufficientAllowanceError': window.alert( 'You must approve the contract to spend at least: +' formatFollowFee(result.error.requestedAmount) ); break;
case 'InsufficientFundsError': window.alert( 'You do not have enough funds to pay for this follow fee: '+ formatFollowFee(result.error.requestedAmount) ); break;
// handle other errors }
// eager return return;}
// success ...
To enhance the user experience, you can manage the InsufficientAllowanceError by prompting the user to approve the underlying Follow Module contract to spend the necessary amount.
On the other hand, when the result is successful, the follow operation optimistically updates the target profile object, affecting the following properties:
profile.operations.canFollow: This value is set to TriStateValue.No.
profile.operations.isFollowedByMe.value: This value is set to true.
profile.operations.isFollowedByMe.isFinalisedOnchain: This value is set to false.
profile.stats.followers: This counter is incremented by one.
Optionally, you can monitor the transaction's status for the full completion of the follow operation using the result.value object.
const completion = await result.value.waitForCompletion();
// handle mining/indexing errorsif (completion.isFailure()) { window.alert(completion.error.message); return;}
window.alert("Follow operation finalized on-chain");
Regardless of whether you wait for completion, the profile object will be updated at the end of the process as follows:
profile.operations.isFollowedByMe.isFinalisedOnchain: This value will be set to true.
profile.operations.canUnfollow: This value will be set to true. This is particularly useful if you're planning to implement an unfollow functionality.
However, if the follow operation fails, these changes will be reverted.
In summary, the <FollowButton> implementation would appear like this:
FollowButton.tsx
import { Profile, useFollow } from "@lens-protocol/react-web";
function FollowButton({ profile }: { profile: Profile }) { const followPolicy = resolveFollowPolicy(profile); const { execute, loading } = useFollow();
const follow = async () => { const result = await execute({ profile });
// handle relaying errors if (result.isFailure()) { window.alert(result.error.message); return; }
window.alert("Success! You have followed this profile"); };
if (!isSupportedFollowPolicy(followPolicy)) { return null; }
return ( <button onClick={follow} disabled={loading || profile.operations.canFollow !== TriStateValue.Yes} > {followButtonLabel(policy)} </button> );}
// followButtonLabel and isSupportedFollowPolicy omitted for brevity
That's it—you've successfully followed a Lens Profile.
Unfollow a Profile
In this section, you'll learn how to unfollow a Lens Profile.
You must be authenticated with a Profile to unfollow another Profile. See Profile Login for more information.
- React SDK
- JavaScript SDK
- API
You can utilize the useUnfollow hook to stop following a Lens Profile.
The hook prioritizes the Signless Experience when available; if not, it resorts to a signed experience.
Available in @lens-protocol/react-web and @lens-protocol/react-native
import { Profile, useUnfollow } from "@lens-protocol/react-web";
function UnfollowButton({ profile }: { profile: Profile }) { const { execute, loading } = useUnfollow();
const unfollow = async () => { const result = await execute({ profile });
// handle relaying errors if (result.isFailure()) { window.alert(result.error.message); return; }
// optional: wait for the tx to be mined and indexed const completion = await result.value.waitForCompletion();
// handle mining/indexing errors if (completion.isFailure()) { window.alert(completion.error.message); return; }
window.alert("Success! You have unfollowed this profile"); };
return ( <button onClick={unfollow} disabled={loading || !profile.operations.canUnfollow} > Unfollow </button> );}
The profile.operations.canUnfollow property should be used to determine if it's possible to unfollow the target Profile at any given time. This property is a boolean.
That's it—you've successfully unfollowed a Lens Profile.
Additional Options
ERC-20 Approvals
When following a Profile that has a follow fee, an ERC-20 Approval might be necessary for the operation to succeed.
An ERC-20 Approval transaction doesn't affect the user's ERC20 balance. Instead, it authorizes the approved address (in this case, a Follow Module contract) to withdraw the specified amount at a later time through an additional transaction.
- React SDK
- Others
You can perform an ERC-20 Approval for a Profile with a follow fee either upfront or in response to an InsufficientAllowanceError when attempting to follow the Profile.
Start by using the useApproveModule hook on the target profile object.
import { useApproveModule } from "@lens-protocol/react-web";
// ...
const approve = useApproveModule();
// ...
const result = await approve.execute({ on: profile });
Next, you can use the Result<T, E> object returned by the function to distinguish between successful requests and potential failures.
if (result.isFailure()) { switch (result.error.name) { case 'InsufficientGasError': window.alert( `The user's wallet does not have enough MATIC to pay for the transaction` ); break;
case 'TransactionError': window.alert('There was an processing the transaction', result.error.message); break;
case 'PendingSigningRequestError': window.alert( 'There is a pending signing request in your wallet. ' + 'Approve it or discard it and try again.' ); break;
case 'WalletConnectionError': window.alert('There was an error connecting to your wallet', result.error.message); break;
case 'UserRejectedError': // the user decided to not sign, usually this is silently ignored by UIs break; }
// eager return return;}
// continue with the follow operation
Upon a successful result, the ERC-20 Approval transaction is completed, and you can proceed with the follow operation, as shown in the following recap example.
import { useApproveModule, useFollow } from "@lens-protocol/react-web";
// ...
const { execute: approve } = useApproveModule();const { execute: follow } = useFollow();
// ...
const approveFollowModuleFor = async (profile: Profile) => { const result = await approve({ on: profile });
if (result.isFailure()) { window.alert(result.error.message); return; }
// try again the follow operation return followProfile(profile);};
const followProfile = async (profile: Profile) => { const result = await follow({ profile });
if (result.isFailure()) { switch (result.error.name) { case 'InsufficientAllowanceError': return approveFollowModuleFor(profile);
// other errors handling }
return }
// successful follow window.alert('You have followed this profile');};
// ...
That's it—you now have a comprehensive flow for following a Profile that requires a follow fee.
By default, the useApproveModule hook executes an ERC-20 Approval for the exact amount required. However, you can pre-approve an unlimited amount by passing the limit argument:
Infinite Approval
import { useApproveModule, TokenAllowanceLimit } from "@lens-protocol/react-web";
// ...
const { execute, error, loading } = useApproveModule({ limit: TokenAllowanceLimit.INFINITE,});