Gated Content
Learn how to create and access Gated Publications.
Lens Protocol, utilizing the decentralized capabilities of Lit Protocol, supports gated content.
When creating a new Gated Publication, Lens users can define access conditions. These conditions determine who can decrypt the content and media within the publication. For example, access could be granted to:
Users who have collected your publication
Your followers
Owners of any NFT from a specific collection (e.g., a DAO membership NFT, an NFT of a collected publication posted on Lens, a Nouns DAO NFT, etc.)
Owners of an NFT with a given TokenId, or a range of TokenIds (e.g., your first 100 followers)
The owner of a specific Lens Profile or EOA address, for exclusive content
Users who own a certain balance of an ERC20 token (e.g., people who have more than X stETH or who hold Y amount of a DAO governance token)
You can also combine these conditions using boolean AND and OR operators.
Content is encrypted end-to-end (E2EE), and can only be decrypted by users who meet the access control conditions.
Initial Setup
Create an instance of the gated LensClient class using the constructor from the secondary package entry point @lens-protocol/client/gated. See JavaScript SDK Getting Started) for more information on setting up the base LensClient class.
This constructor accepts the same parameters as the base LensClient class, with few additional parameters:
authentication specifies the domain and URI for the Lit Protocol authentication. This is used to create a SIWE message (Sign-in with Ethereum) that the Lit Protocol uses to authenticate users on their network.
signer is a signer that complies with the ISigner interface. For convenience, this is structurally compatible with the ethers Signer interface. This signer is used to sign the aforementioned SIWE message.
Like the base LensClient class, you can specify an optional storage that complies with the IStorageProvider interface. By default, if not provided, it will fall back to an InMemoryStorage instance (which keeps any stored information in a temporary location in system memory). The gated LensClient uses the same storage to save Lit Protocol credentials so that signing of SIWE messages happens only when needed.
Encrypting content
Familiarity with Referencing Content is required.
To create a Gated Publication, the process is the same as creating a regular publication, with the addition of encrypting the metadata beforehand.
Create publication metadata using the @lens-protocol/metadata helpers. For example, to create an article:
import { article } from "@lens-protocol/metadata";
const metadata = article({ content: "..." });
Define the access conditions using the @lens-protocol/metadata helpers.
import { erc721OwnershipCondition } from "@lens-protocol/metadata";
const condition = erc721OwnershipCondition({ contract: { address: "0x...", chainId: 1 },});
Encrypt the publication metadata using the client.gated.encryptPublicationMetadata method.
const result = await client.gated.encryptPublicationMetadata( metadata, condition);
// handle encryption errorsif (result.isFailure()) { console.error(result.error); return; // bail out}
const encrypted = result.value;
Continue creating the publication as usual, using the encrypted metadata. For example, you can upload the encrypted metadata to IPFS and use the resulting contentURI to create a Lens publication.
const contentURI = await upload(encrypted);
const result = await client.publication.postOnchain({ contentURI });
That's it—you've just learned how to create a Gated Publication in Lens Protocol.
Access Conditions
The @lens-protocol/metadata package provides helper functions for the following access conditions:
collectCondition: Requires the collection of a specified publication.
eoaOwnershipCondition: Requires ownership of a specified EOA.
erc20OwnershipCondition: Requires ownership of a specified amount of an ERC20 token.
erc721OwnershipCondition: Requires ownership of a specified ERC721 token.
erc1155OwnershipCondition: Requires ownership of a specified ERC1155 token.
profileOwnershipCondition: Requires ownership of a specified profile.
followCondition: Requires following a specified profile.
Collect Condition
You can define an access condition that requires the collection of the current publication. However, at the time of encryption, the publication hasn't been created yet. In this case, you can use client.publication.predictNextOnChainPublicationId to predict the publication ID.
const condition = collectCondition({ publicationId: await client.publication.predictNextOnChainPublicationId({ from: profile.id, }), thisPublication: true, // flag to indicate that the current publication is the one to collect});
Compound Conditions
You can combine multiple criteria using the orCondition and andCondition helper functions.
const result = await client.gated.encryptPublicationMetadata( metadata, orCondition([ profileOwnershipCondition({ profileId: profile.id, }), erc721OwnershipCondition({ contract: { address: "0x...", chainId: 1 }, }), ]));
Supported compound conditions are:
andCondition: This allows you to combine up to 5 criteria using the AND operator. Note that you cannot use orCondition and andCondition within this.
orCondition: This allows you to combine up to 5 criteria using the OR operator. Note that you cannot use orCondition and andCondition within this.
Decrypting content
You can decrypt publication metadata using the client.gated.decryptPublicationMetadataFragment method. This method is compatible with publications returned by any LensClient method. Additionally, the LensClient SDK supports the decryption of metadata from previous publication standards, specifically version 2.
import { isEncryptedPublicationMetadata } from "@lens-protocol/client/gated";
// fetch a publication, works with publications returned by any LensClient methodconst post = await client.publication.fetch({ forId: "..." });
// check if the publication metadata is encryptedif (isEncryptedPublicationMetadata(post.metadata)) { // decrypt the metadata const result = await client.gated.decryptPublicationMetadataFragment( post.metadata );
// handle decryption errors if (result.isFailure()) { console.error(result.error); return; // bail out }
// use the decrypted metadata console.log(result.value);}
If you're using this feature with a publication metadata fragment not originating from the LensClient, it's your responsibility to ensure the PublicationMetadata fragment is valid. Specifically, it should:
Have __typename defined at every level of the fragment.
Include ALL fields and sub-fields of the corresponding GQL node in the encryptedWith.
That's it—you've just learned how to decrypt Gated Publications in Lens Protocol.