Skip to content

Content Management

Content management allows you to discover, analyze, and control access to content on your pages. The SDK automatically finds content based on configured selectors and provides methods to check access and unlock premium content.

📘 See Also: Content Metadata & Fallback Mechanism for detailed information about meta tags, element attributes, and best practices.

How It Works

  1. Configuration - Define content selectors in your config or via Scripts Host
  2. Discovery - SDK scans the page for matching content elements
  3. Metadata Extraction - Extracts metadata using a multi-layered fallback approach (configured selectors → element attributes → meta tags)
  4. Access Control - Integrates with entitlements to control access
  5. Content Unlocking - Fetches and decrypts premium content when authorized

Methods

content.list()

Discover all content items on the current page.

Returns: ContentItem[]

javascript
const articles = window.sesamy.content.list();

articles.forEach((article) => {
  console.log('Found:', article.title);
  console.log('Price:', article.price);
  console.log('Requires:', article.pass);
});

content.get()

Get a specific content item by selector or element.

Parameters: elementOrSelector (HTMLElement | string)

Returns: ContentItem | null

javascript
const article = window.sesamy.content.get('article.featured');
if (article) {
  console.log('Article:', article.title);
}

content.hasAccess()

Check if user has access to content.

Parameters: elementOrSelector (HTMLElement | string)

Returns: Promise<Entitlement | boolean | null>

javascript
const result = await window.sesamy.content.hasAccess('.premium-article');

if (result) {
  if (typeof result === 'boolean') {
    // User has access (public or logged-in content)
    console.log('Access granted');
  } else {
    // User has access via entitlement
    console.log('Access granted via:', result.type);
  }
} else {
  // User doesn't have access - show paywall
  const article = window.sesamy.content.get('.premium-article');
  showPaywall(article.paywallUrl);
}

The function returns:

  • An Entitlement object if the user has entitlement-based access
  • true if the user has access (public content or authenticated for login-only content)
  • null if the user doesn't have access

content.unlock()

Unlock and retrieve premium content.

Parameters: elementOrSelector (HTMLElement | string)

Returns: Promise<string | null>

javascript
const unlockedHTML = await window.sesamy.content.unlock('#article');

if (unlockedHTML) {
  document.querySelector('#content').innerHTML = unlockedHTML;
} else {
  // User doesn't have access
  showPaywall();
}

Configuration

Configure content selectors to define how the SDK discovers and extracts metadata:

javascript
{
  content: [
    {
      type: 'article',
      path: '/articles', // Optional: only match on this path
      pass: 'premium', // Optional: required pass
      price: {
        amount: 9.99,
        currency: 'USD',
      },
      enablePaywallSettingsUrlFallback: false, // Optional: Fallback to <sesamy-paywall settings-url>
      selectors: {
        article: { selector: 'article.content' },
        title: { selector: 'h1', attribute: 'textContent' },
        image: { selector: 'img', attribute: 'src' },
        author: { selector: '.author', attribute: 'textContent' },
        paywallUrl: { selector: 'a.paywall-link', attribute: 'href' },
        // ... more selectors
      },
    },
  ];
}

Pass Collection

The pass attribute is collected from the article element and all its ancestor elements up to the document root. This allows for flexible, hierarchical access control:

html
<body pass="https://example.com/site-wide">
  <main pass="https://example.com/members">
    <section pass="https://example.com/premium">
      <sesamy-article pass="https://example.com/article-123">
        <!-- All four passes are collected and checked -->
      </sesamy-article>
    </section>
  </main>
</body>

How It Works

When retrieving content with content.get() or content.list(), the SDK:

  1. Starts at the article element
  2. Collects any pass attributes
  3. Traverses up through parent elements
  4. Collects all pass attributes from ancestors
  5. Splits comma-separated values
  6. Removes duplicates
  7. Combines into a single comma-separated string

Use Cases

Section-based access:

html
<section class="members-only" pass="https://example.com/members">
  <sesamy-article>Article 1</sesamy-article>
  <sesamy-article>Article 2</sesamy-article>
  <!-- Both articles inherit the members pass -->
</section>

Dynamic passes from CMS:

html
<!-- Lab plugin adds passes dynamically based on tags -->
<section class="article" pass="https://example.com/tag1,https://example.com/tag2">
  <sesamy-article>
    <!-- Inherits tag-based passes -->
  </sesamy-article>
</section>

Multiple access levels:

html
<article pass="https://example.com/basic">
  <div pass="https://example.com/premium">
    <sesamy-article>
      <!-- Requires either basic OR premium pass -->
    </sesamy-article>
  </div>
</article>

Best Practices

  • Place site-wide passes on <body> or high-level containers
  • Use section/category passes on section elements
  • Use article-specific passes on <sesamy-article> elements
  • Let plugins like Labrador Tags handle dynamic passes

Common Patterns

Content List with Access Check

javascript
window.addEventListener('sesamyJsReady', async () => {
  const articles = window.sesamy.content.list();

  for (const article of articles) {
    const entitlement = await window.sesamy.content.hasAccess(article.element);

    if (!entitlement) {
      // Add paywall overlay
      const overlay = document.createElement('div');
      overlay.className = 'paywall-overlay';
      overlay.innerHTML = `
        <h3>Premium Content</h3>
        <p>Subscribe to read this article</p>
        <button onclick="location.href='${article.paywallUrl}'">
          Subscribe Now
        </button>
      `;
      article.element.appendChild(overlay);
    }
  }
});

Dynamic Content Unlocking

javascript
async function unlockArticle(selector) {
  const entitlement = await window.sesamy.content.hasAccess(selector);

  if (entitlement) {
    const content = await window.sesamy.content.unlock(selector);
    if (content) {
      document.querySelector('.article-body').innerHTML = content;
      document.querySelector('.paywall').remove();

      // Track unlock event
      await window.sesamy.analytics.track('content_unlocked', {
        contentId: entitlement.publisherContentId,
      });
    }
  } else {
    // Show paywall with article info
    const article = window.sesamy.content.get(selector);
    showPaywall({
      title: article.title,
      price: article.price,
      paywallUrl: article.paywallUrl,
    });
  }
}

Paywall with Purchase Flow

javascript
window.addEventListener('sesamyJsReady', async () => {
  const article = window.sesamy.content.get('article.main');
  const access = await window.sesamy.content.hasAccess(article.element);

  if (!access) {
    document.querySelector('#purchase-btn').addEventListener('click', async () => {
      const checkout = await window.sesamy.checkouts.create({
        items: [
          {
            url: article.url,
            price: article.price.amount,
            currency: article.price.currency,
          },
        ],
        redirectUrl: window.location.href,
      });

      window.location.href = checkout.checkoutUrl;
    });
  }
});

Next Steps

Released under the MIT License.