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.

import { development, LensClient } from "@lens-protocol/client/gated";
const client = new LensClient({  environment: development,
  authentication: {    domain: process.env.DOMAIN,    uri: process.env.URI,  },
  signer,});

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.

1

Create Metadata

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: "..." });

2

Access Conditions

Define the access conditions using the @lens-protocol/metadata helpers.

import { erc721OwnershipCondition } from "@lens-protocol/metadata";
const condition = erc721OwnershipCondition({  contract: { address: "0x...", chainId: 1 },});

3

Encrypt Metadata

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;

4

Continue as Usual

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:

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.