Skip to content

Sesamy JS

The official Sesamy browser JavaScript library (@sesamy/sesamy-js) for handling authentication, analytics, content access, and communication with the Sesamy API.

Difference from Sesamy SDK

This is the browser-focused library for content access control and user experience features. For direct API access in Node.js or server environments, use the Sesamy SDK instead.

Installation

Easiest Setup: Scripts Host

For the simplest integration with automatic configuration and updates, use the Scripts Host service instead of manual installation.

bash
npm install @sesamy/sesamy-js
bash
yarn add @sesamy/sesamy-js
bash
pnpm add @sesamy/sesamy-js

Requirements

  • Modern browser with JavaScript enabled
  • TypeScript 4.5+ (for TypeScript projects)

Quick Start

Recommended: Scripts Host

For production use, we recommend using the Scripts Host for automatic configuration and CDN delivery. The examples below show manual integration.

Script Tag Initialization

The simplest way to use the SDK is via a script tag with JSON configuration:

html
<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.sesamy.com/sesamy-js/latest/sesamy-js.min.js"></script>
    <script type="application/json" id="sesamy-js">
      {
        "clientId": "your-client-id"
      }
    </script>
  </head>
  <body>
    <script>
      // Wait for the SDK to be ready
      window.addEventListener('sesamyJsReady', async () => {
        // Check if user is authenticated
        const isAuth = await window.sesamy.auth.isAuthenticated();
        console.log('User authenticated:', isAuth);

        // Get user profile
        if (isAuth) {
          const profile = await window.sesamy.profile.get();
          console.log('User profile:', profile);
        }
      });
    </script>
  </body>
</html>

Programmatic Initialization

You can also initialize the SDK programmatically:

typescript
import { init } from '@sesamy/sesamy-js';

const sesamy = await init({
  clientId: 'your-client-id',
});

// Check authentication
const isAuth = await sesamy.auth.isAuthenticated();

// Get user profile
if (isAuth) {
  const profile = await sesamy.profile.get();
}

Configuration

Basic Configuration

The only required configuration is the clientId:

javascript
{
  "clientId": "your-client-id"
}

Advanced Configuration

javascript
{
  clientId: "your-client-id",
  organization: "org_123",  // Optional: Auth0 organization ID

  // API configuration
  api: {
    namespace: "sesamy",  // Window object namespace (default: "sesamy")
    endpoint: "https://api2.sesamy.com"  // API endpoint
  },

  // Analytics configuration
  analytics: {
    enabled: true,
    endpoint: "https://logs.sesamy.com/events"
  },

  // Authentication configuration
  auth: {
    clientId: "your-client-id",
    organization: "org_123",
    enabled: true,
    domain: "auth.example.com",  // Optional: Custom Auth0 domain
    domains: []  // Optional: Array of auth domains for multi-domain setups
  },

  // Content configuration
  content: [
    {
      type: "article",
      path: "/articles",  // Optional: URL path filter
      pass: "premium",    // Optional: Pass requirement
      price: {
        amount: 9.99,
        currency: "USD"
      },
      paywallUrl: "https://example.com/paywall",
      selectors: {
        article: { selector: "article" },
        title: { selector: "h1", attribute: "textContent" },
        image: { selector: "img", attribute: "src" },
        // ... other selectors
      }
    }
  ],

  // Transform configuration
  transforms: {
    enabled: false,
    rules: []
  }
}

Multi-Domain Authentication

For applications across multiple domains (white-label, multi-region):

javascript
{
  auth: {
    clientId: "your-client-id",
    domains: [
      "auth.brand1.com",
      "auth.brand2.com",
      "auth.example.co.uk"
    ],
    domain: "default-auth.example.com"  // Fallback domain
  }
}

The SDK automatically selects the appropriate auth domain based on the current page's top-level domain.

Core API

Checking SDK Readiness

javascript
// Check if SDK is ready
if (window.sesamy.isReady()) {
  console.log('SDK is ready');
}

// Or listen for the ready event
window.addEventListener('sesamyJsReady', () => {
  console.log('SDK is ready');
});

Authentication

The SDK provides comprehensive authentication methods with support for both redirect and popup-based flows.

login()

Smart login that automatically chooses the best authentication method based on browser context.

Parameters:

  • options (optional):
    • appState: State to preserve during redirect
    • authorizationParams:
      • audience: API audience
      • scope: OAuth scopes
      • login_hint: Pre-fill email
      • organization: Auth0 organization
      • redirect_uri: Post-login redirect URL

Returns: Promise&lt;void&gt;

Example:

javascript
await window.sesamy.auth.login({
  authorizationParams: {
    login_hint: 'user@example.com',
  },
});

loginWithRedirect()

Redirects user to Auth0 hosted login page. Best for desktop browsers.

Parameters:

  • Same as login()

Returns: Promise&lt;void&gt;

Example:

javascript
await window.sesamy.auth.loginWithRedirect({
  authorizationParams: {
    redirect_uri: window.location.origin + '/callback',
  },
});

loginWithPopup()

Opens login in a popup window. Better for maintaining page state and works better in incognito mode.

Note: To prevent automatic page refresh after authentication, listen for sesamyJsAuthenticated event and call preventDefault().

Parameters:

  • Same as login()

Returns: Promise&lt;void&gt;

Example:

javascript
// Prevent auto-refresh after login
window.addEventListener('sesamyJsAuthenticated', (event) => {
  event.preventDefault();
  console.log('User authenticated!');
});

await window.sesamy.auth.loginWithPopup({
  authorizationParams: {
    login_hint: 'user@example.com',
  },
});

logout()

Logs out the user and optionally redirects.

Parameters:

  • options (optional):
    • returnTo: URL to redirect after logout

Returns: Promise&lt;void&gt;

Example:

javascript
await window.sesamy.auth.logout({
  returnTo: 'https://yoursite.com',
});

isAuthenticated()

Checks if user is currently authenticated.

Returns: Promise&lt;boolean&gt;

Example:

javascript
const isAuth = await window.sesamy.auth.isAuthenticated();
if (isAuth) {
  console.log('User is logged in');
}

getTokenSilently()

Retrieves access token without user interaction.

Parameters:

  • throwOnUnauthorized (boolean, default: true): Throw error if not authenticated
  • forceRefresh (boolean, default: false): Force token refresh

Returns: Promise&lt;string | null&gt;

Example:

javascript
const token = await window.sesamy.auth.getTokenSilently();
// Use token for API calls

setToken()

Manually set an access token.

Parameters:

  • accessToken (string): The access token
  • expiresIn (number, optional): Token expiration in seconds

Returns: Promise&lt;void&gt;

Example:

javascript
await window.sesamy.auth.setToken('your.jwt.token', 3600);

Profile Management

profile.get()

Fetches the user's profile information.

Returns: Promise&lt;Profile | null&gt;

Profile Type:

typescript
type Profile = {
  userId: string;
  firstName?: string;
  lastName?: string;
  emailVerified: boolean;
  email: string;
  name?: string;
  locale?: string;
  picture?: string;
  createdAt: string;
  updatedAt: string;
  mobilePhone?: string;
  tags: string[];
  user_metadata?: { [id: string]: string | number };
  billingAddress?: Address;
  deliveryAddress?: Address;
};

Example:

javascript
const profile = await window.sesamy.profile.get();
if (profile) {
  console.log(profile.email);
}

profile.update()

Updates the user's profile information.

Parameters:

  • profile (Partial<Profile>): Fields to update

Returns: Promise&lt;boolean&gt;

Example:

javascript
const success = await window.sesamy.profile.update({
  firstName: 'John',
  lastName: 'Doe',
  mobilePhone: '+1234567890',
  billingAddress: {
    street: '123 Main St',
    city: 'New York',
    state: 'NY',
    postalCode: '10001',
    country: 'US',
  },
});

profile.openHostedAccountPage()

Opens the Sesamy hosted account management page.

Example:

javascript
window.sesamy.profile.openHostedAccountPage();

profile.isSpotifyLinked()

Checks if user has linked their Spotify account.

Returns: Promise&lt;boolean&gt;

Example:

javascript
const isLinked = await window.sesamy.profile.isSpotifyLinked();

profile.unlinkSpotify()

Unlinks the user's Spotify account.

Returns: Promise&lt;void&gt;

Entitlements

entitlements.list()

Fetches the list of user's entitlements.

Parameters:

  • params (optional):
    • includeSignedLinks (boolean, default: true)
    • waitForEntitlementAfter (Date, optional)

Returns: Promise&lt;Entitlement[]&gt;

Example:

javascript
const entitlements = await window.sesamy.entitlements.list({
  includeSignedLinks: true,
});

entitlements.forEach((ent) => {
  console.log(`${ent.id}: ${ent.type}`);
});

entitlements.get()

Fetches a specific entitlement by ID.

Parameters:

  • entitlementId (string)

Returns: Promise&lt;Entitlement | undefined&gt;

Example:

javascript
const entitlement = await window.sesamy.entitlements.get('ent_123');
if (entitlement) {
  console.log('Access granted:', entitlement);
}

entitlements.hasAccess()

Checks if user has access to specific content.

Parameters:

  • itemSrc (string): Content identifier

Returns: Promise&lt;boolean&gt;

Example:

javascript
const hasAccess = await window.sesamy.entitlements.hasAccess('article_123');
if (hasAccess) {
  // Show premium content
} else {
  // Show paywall
}

entitlements.access()

Fetches access details for a specific entitlement.

Parameters:

  • entitlementId (string)

Returns: Promise&lt;Access&gt;

Example:

javascript
const access = await window.sesamy.entitlements.access('ent_123');
console.log('Access URL:', access.url);

Returns signed links from the current session.

Returns: SignedLink[]

Example:

javascript
const signedLinks = window.sesamy.entitlements.signedLinks();
console.log('Signed links:', signedLinks);

Contracts (Subscriptions)

contracts.list()

Lists all user's contracts (subscriptions).

Returns: Promise&lt;Contract[]&gt;

Example:

javascript
const contracts = await window.sesamy.contracts.list();
contracts.forEach((contract) => {
  console.log(`${contract.id}: ${contract.status}`);
});

contracts.get()

Gets a specific contract by ID.

Parameters:

  • contractId (string)

Returns: Promise&lt;Contract&gt;

Example:

javascript
const contract = await window.sesamy.contracts.get('con_123');
console.log('Contract status:', contract.status);

contracts.cancel()

Cancels a contract by ID.

Parameters:

  • contractId (string)

Returns: Promise&lt;void&gt;

Example:

javascript
await window.sesamy.contracts.cancel('con_123');
console.log('Contract cancelled');

Checkouts

The checkouts API allows you to create and manage checkout sessions for purchasing products or subscriptions.

checkouts.create()

Creates a new checkout session.

Parameters:

typescript
{
  // Required
  items: Item[],              // Array of items to purchase
  redirectUrl: string,        // URL to redirect after checkout completion

  // Customer information (optional)
  email?: string,
  givenName?: string,
  familyName?: string,
  phoneNumber?: string,
  birthDate?: string,
  country?: string,

  // Gift mode settings (optional)
  giftMode?: boolean,         // When true, enables gift purchase mode where payer differs from recipient
  payerEmail?: string,        // Email of the person paying (used when giftMode is true)

  // Billing address (optional)
  address?: {
    street?: string,
    city?: string,
    zip?: string,
    country?: string,
  },

  // Business information (optional)
  isBusiness?: boolean,
  businessAddress?: Address,

  // Pricing (optional - overrides item pricing)
  price?: number,
  currency?: string,

  // Payment options (optional)
  paymentMethodsFilter?: Array<{
    provider: string,
    methods?: string[]
  }>,

  // Discount codes
  requestedDiscountCodes?: string[],

  // Language
  language?: string,

  // Attribution/Tracking (optional)
  attribution?: {
    utmSource?: string,
    utmMedium?: string,
    utmCampaign?: string,
    utmTerm?: string,
    utmContent?: string,
    ref?: string,
    referrer?: string,
    itemSrc?: string,
    publisherContentId?: string,
    // Tracking cookies
    _ga?: string,
    _gid?: string,
    _fbp?: string,
    _fbc?: string,
  },

  referralEmail?: string,
}

Where Item is:

typescript
{
  sku?: string,                           // Product SKU
  url?: string,                           // Item URL
  purchaseOptionId?: string,              // Purchase option ID
  price?: number,                         // Item price
  currency?: string,                      // Currency code (e.g., 'USD')
  geoRestrictions?: {
    type: 'ALLOW' | 'BLOCK',
    countries: string[]
  }
}

Returns: Promise<Checkout>

The Checkout response includes:

typescript
{
  id: string,                          // Checkout session ID
  checkoutUrl: string,                 // URL to redirect user to for checkout
  status: 'PENDING' | 'PAID',
  type: 'RECURRING' | 'SINGLE',
  giftMode?: boolean,                   // Whether this is a gift purchase
  itemsOwned: Array<{
    sku: string,
    purchaseOptionId: string,
    title: string,
  }>,
  appliedDiscountCodes: Array<{
    name: string,
    description: string,
    id: string,
    code: string,
    status: 'APPLIED' | 'UNAPPLICABLE',
  }>,
  availablePaymentMethods: Array<{
    provider: string,
    methods?: string[]
  }>,
  createdAt: string,
  updatedAt: string,
  // ... plus all the submitted parameters (including email and payerEmail if provided)
}

Example - Simple purchase:

javascript
const checkout = await window.sesamy.checkouts.create({
  items: [
    {
      sku: 'premium_monthly',
      purchaseOptionId: 'po_123',
      price: 9.99,
      currency: 'USD',
    },
  ],
  email: 'user@example.com',
  redirectUrl: 'https://yoursite.com/checkout-complete',
});

// Redirect user to checkout page
window.location.href = checkout.checkoutUrl;

Example - Multiple items with attribution:

javascript
const checkout = await window.sesamy.checkouts.create({
  items: [
    {
      sku: 'premium_annual',
      purchaseOptionId: 'po_456',
      price: 99.99,
      currency: 'USD',
    },
    {
      sku: 'addon_feature',
      price: 9.99,
      currency: 'USD',
    },
  ],
  email: 'user@example.com',
  givenName: 'John',
  familyName: 'Doe',
  phoneNumber: '+1234567890',
  address: {
    street: '123 Main St',
    city: 'San Francisco',
    zip: '94102',
    country: 'US',
  },
  redirectUrl: 'https://yoursite.com/checkout-complete',
  language: 'en',
  attribution: {
    utmSource: 'email',
    utmMedium: 'newsletter',
    utmCampaign: 'black_friday_2024',
  },
  requestedDiscountCodes: ['WELCOME10', 'EARLYBIRD'],
});

window.location.href = checkout.checkoutUrl;

Example - Gift mode purchase:

javascript
// When someone wants to buy a subscription as a gift for someone else
const checkout = await window.sesamy.checkouts.create({
  items: [
    {
      sku: 'premium_annual',
      purchaseOptionId: 'po_456',
      price: 99.99,
      currency: 'USD',
    },
  ],
  giftMode: true,
  payerEmail: 'buyer@example.com', // Person making the purchase
  email: 'recipient@example.com', // Person receiving the subscription
  givenName: 'Jane',
  familyName: 'Doe',
  redirectUrl: 'https://yoursite.com/gift-complete',
  language: 'en',
});

window.location.href = checkout.checkoutUrl;

Gift Mode

When giftMode is enabled, the checkout treats the email field as the recipient's email address, and the payerEmail field as the purchaser's email. This is useful for gift subscriptions where the person paying is different from the person who will receive access to the content.

checkouts.get()

Gets an existing checkout session by ID.

Parameters:

  • checkoutId (string): The ID of the checkout session

Returns: Promise<Checkout>

Example:

javascript
const checkout = await window.sesamy.checkouts.get('checkout_123');
console.log('Status:', checkout.status);
console.log('Checkout URL:', checkout.checkoutUrl);
console.log('Applied discounts:', checkout.appliedDiscountCodes);

checkouts.update()

Updates an existing checkout session. You can update customer information, items, or other checkout details.

Parameters:

  • checkoutId (string): The ID of the checkout session
  • params (object): Partial checkout parameters to update

Returns: Promise<Checkout>

Example:

javascript
const updated = await window.sesamy.checkouts.update('checkout_123', {
  email: 'newemail@example.com',
  givenName: 'Jane',
  requestedDiscountCodes: ['NEWCODE'],
});

console.log('Updated checkout:', updated);

Example - Update with gift mode:

javascript
// Update a checkout to add payer information for a gift purchase
const updated = await window.sesamy.checkouts.update('checkout_123', {
  email: 'recipient@example.com', // Recipient of the gift
  payerEmail: 'buyer@example.com', // Person paying for the gift
  givenName: 'Jane',
  familyName: 'Doe',
});

console.log('Updated checkout for gift:', updated);

Content Management

The content management API provides methods to discover, analyze, and unlock content on your page. It works by analyzing DOM elements based on configured selectors and extracting metadata through intelligent DOM traversal with fallback mechanisms.

Configuration

Content configuration can be provided in two ways:

  1. Manual initialization - Via the init() config
  2. Script Host injection - Automatically injected when using the Scripts Host

Example Configuration

javascript
{
  content: [
    {
      type: 'article',
      path: '/articles', // Optional: Only match articles on this path
      pass: 'premium', // Optional: Required pass for access
      price: {
        amount: 9.99,
        currency: 'USD',
      },
      paywallUrl: 'https://example.com/paywall',
      selectors: {
        // Container selector - identifies content on page
        article: {
          selector: 'article.content',
        },

        // Content metadata selectors
        title: {
          selector: 'h1.article-title',
          attribute: 'textContent',
        },
        description: {
          selector: "meta[name='description']",
          attribute: 'content',
        },
        image: {
          selector: "meta[property='og:image']",
          attribute: 'content',
        },
        author: {
          selector: '.author-name',
          attribute: 'textContent',
        },
        publishedTime: {
          selector: "meta[property='article:published_time']",
          attribute: 'content',
        },
        paywallUrl: {
          selector: 'a.paywall-link',
          attribute: 'href',
        },

        // Custom metadata
        category: {
          selector: '.article-category',
          attribute: 'textContent',
        },
        tags: {
          selector: '.article-tags .tag',
          attribute: 'textContent',
          multiple: true, // Extract multiple values
        },
      },
    },
  ];
}

Selector Resolution Strategy

When extracting metadata, the SDK uses a hierarchical resolution strategy:

  1. Element-level selectors - Search within the content container
  2. DOM traversal upwards - Walk up the DOM tree to find parent elements
  3. Page-level meta tags - Fallback to <head> meta tags
  4. Configuration defaults - Use values from init config or script host settings

Example DOM traversal:

html
<article class="content" data-item-id="article_123">
  <div class="article-header">
    <h1 class="article-title">Breaking News</h1>
    <span class="author-name">John Doe</span>
  </div>
  <div class="article-body">
    <!-- Content here -->
  </div>
  <a class="paywall-link" href="https://example.com/paywall?item=article_123">Read Full Article</a>
</article>

<head>
  <meta property="og:image" content="https://example.com/image.jpg" />
  <meta name="description" content="Article description" />
</head>

With this structure:

  • title is found within the article container
  • author is found by traversing up from content
  • image falls back to page-level meta tag
  • description uses the meta tag fallback
  • paywallUrl is extracted from the paywall link, with fallback to config

PaywallUrl Resolution

The paywallUrl property is resolved using the same hierarchical strategy as other metadata properties:

  1. Element-level selector - Look for a link element with the configured selector (e.g., a.paywall-link) and extract its href attribute
  2. DOM traversal - Walk up the DOM tree if not found in the container
  3. Content configuration - Use the paywallUrl defined in the content node configuration if not found in HTML

Example:

javascript
// In configuration
{
  type: 'article',
  paywallUrl: 'https://example.com/paywall', // Fallback URL from config
  selectors: {
    paywallUrl: {
      selector: 'a.paywall-link',
      attribute: 'href'
    },
    // ... other selectors
  }
}

// In HTML - this will be used first
<article class="content">
  <h1>Article Title</h1>
  <a class="paywall-link" href="https://example.com/paywall?item=article_123">
    Read Full Article
  </a>
</article>

// Result: paywallUrl = 'https://example.com/paywall?item=article_123'
// If HTML link was missing, result would be: 'https://example.com/paywall'

content.list()

Lists all content items discovered on the current page based on configured selectors.

Returns: Array<ContentItem>

ContentItem Type:

typescript
type ContentItem = {
  // Core identifiers
  id: string; // Unique content identifier
  type: string; // Content type (e.g., "article", "video")
  url: string; // Content URL

  // Metadata
  title?: string; // Content title
  description?: string; // Content description
  image?: string; // Featured image URL
  author?: string; // Content author
  publishedTime?: string; // ISO 8601 timestamp
  modifiedTime?: string; // ISO 8601 timestamp

  // Access control
  pass?: string; // Required pass/subscription
  price?: {
    amount: number;
    currency: string;
  };
  paywallUrl?: string; // Custom paywall URL

  // Custom properties
  [key: string]: any; // Additional configured properties

  // DOM reference
  element: HTMLElement; // The DOM element
};

Example:

javascript
// Wait for SDK ready
window.addEventListener('sesamyJsReady', () => {
  const contentItems = window.sesamy.content.list();

  console.log(`Found ${contentItems.length} content items`);

  contentItems.forEach((item) => {
    console.log('Content:', {
      id: item.id,
      title: item.title,
      author: item.author,
      requiresPass: item.pass,
      price: item.price,
    });
  });
});

Example Response:

javascript
[
  {
    id: 'article_123',
    type: 'article',
    url: 'https://example.com/articles/breaking-news',
    title: 'Breaking News: Major Development',
    description: "A detailed look at today's major development...",
    image: 'https://example.com/images/breaking-news.jpg',
    author: 'John Doe',
    publishedTime: '2024-11-07T10:30:00Z',
    pass: 'premium',
    price: {
      amount: 4.99,
      currency: 'USD',
    },
    paywallUrl: 'https://example.com/paywall?item=article_123',
    category: 'News',
    tags: ['breaking', 'politics', 'international'],
    element: HTMLElement, // DOM reference
  },
  {
    id: 'article_456',
    type: 'article',
    url: 'https://example.com/articles/tech-review',
    title: 'Tech Review: Latest Gadgets',
    description: 'Our comprehensive review of the latest tech...',
    image: 'https://example.com/images/tech-review.jpg',
    author: 'Jane Smith',
    publishedTime: '2024-11-06T14:20:00Z',
    pass: 'premium',
    category: 'Technology',
    tags: ['review', 'gadgets', 'tech'],
    element: HTMLElement,
  },
];

content.get()

Gets a specific content item by DOM element or CSS selector.

Parameters:

  • elementOrSelector (HTMLElement | string): DOM element or CSS selector

Returns: ContentItem | null

Example:

javascript
// Get by selector
const article = window.sesamy.content.get('article.featured');
if (article) {
  console.log('Featured article:', article.title);
  console.log('Requires:', article.pass);
  console.log('Price:', article.price);
}

// Get by element
const element = document.querySelector('.main-article');
const content = window.sesamy.content.get(element);

Example Response:

javascript
{
  id: "article_789",
  type: "article",
  url: "https://example.com/articles/featured",
  title: "Featured: The Future of Technology",
  description: "An in-depth analysis of emerging technologies...",
  image: "https://example.com/images/future-tech.jpg",
  author: "Sarah Johnson",
  publishedTime: "2024-11-07T08:00:00Z",
  pass: "premium",
  price: {
    amount: 9.99,
    currency: "USD"
  },
  paywallUrl: "https://example.com/paywall?item=article_789",
  category: "Technology",
  tags: ["featured", "analysis", "future"],
  element: HTMLElement
}

content.unlock()

Unlocks and retrieves locked content. This method integrates with the Content Proxy to fetch and decrypt premium content.

Parameters:

  • elementOrSelector (HTMLElement | string): DOM element or CSS selector

Returns: Promise<string | null>

How it works:

  1. Identifies the content item
  2. Checks user's entitlements via entitlements.hasAccess()
  3. If authorized, fetches content via Content Proxy
  4. Decrypts and returns the content HTML
  5. Returns null if unauthorized or content not found

Example:

javascript
// Unlock specific article
const unlockedContent = await window.sesamy.content.unlock('#premium-article');

if (unlockedContent) {
  // User has access - display content
  const contentDiv = document.querySelector('#article-body');
  contentDiv.innerHTML = unlockedContent;

  console.log('Content unlocked successfully');
} else {
  // User doesn't have access - show paywall
  window.location.href = '/paywall?item=article_123';
}

Example with error handling:

javascript
try {
  const content = await window.sesamy.content.unlock('.locked-content');

  if (content) {
    // Replace locked content with unlocked version
    document.querySelector('.content-container').innerHTML = content;

    // Track unlock event
    await window.sesamy.analytics.track('content_unlocked', {
      contentId: 'article_123',
      contentType: 'article',
    });
  } else {
    // Show paywall
    showPaywall();
  }
} catch (error) {
  console.error('Failed to unlock content:', error);
  showErrorMessage();
}

Integration with Content Proxy:

The unlock() method uses the Content Proxy endpoint to fetch encrypted content. See the Scripts Host documentation for more details on content encryption and delivery.

content.getLanguage()

Gets the current page language from the HTML element's lang attribute.

Returns: string

Example:

javascript
const language = window.sesamy.content.getLanguage();
console.log('Current language:', language); // "en", "sv", etc.

// Use language for localized content
const checkoutLanguage = language === 'sv' ? 'sv' : 'en';

content.getPropertyFromHTML()

Extracts a property from HTML content using a selector and attribute.

Parameters:

  • html (string): HTML content to parse
  • selector (string): CSS selector
  • attribute (string): Attribute to extract (e.g., "textContent", "src", "href")

Returns: string | null

Example:

javascript
const htmlContent = `
  <article>
    <h1 class="title">Article Title</h1>
    <img src="https://example.com/image.jpg" alt="Article Image">
    <p class="description">Article description here...</p>
  </article>
`;

// Extract title
const title = window.sesamy.content.getPropertyFromHTML(htmlContent, 'h1.title', 'textContent');
console.log('Title:', title); // "Article Title"

// Extract image URL
const imageUrl = window.sesamy.content.getPropertyFromHTML(htmlContent, 'img', 'src');
console.log('Image:', imageUrl); // "https://example.com/image.jpg"

// Extract description
const description = window.sesamy.content.getPropertyFromHTML(
  htmlContent,
  '.description',
  'textContent'
);
console.log('Description:', description); // "Article description here..."

Use case - Processing unlocked content:

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

if (unlockedHtml) {
  // Extract specific elements from unlocked content
  const headline = window.sesamy.content.getPropertyFromHTML(unlockedHtml, 'h1', 'textContent');

  const authorByline = window.sesamy.content.getPropertyFromHTML(
    unlockedHtml,
    '.author',
    'textContent'
  );

  console.log(`"${headline}" by ${authorByline}`);

  // Insert into page
  document.querySelector('#content').innerHTML = unlockedHtml;
}

Integration Examples

Using with Scripts Host

The Scripts Host automatically injects content configuration based on your publisher settings:

html
<script src="https://scripts.sesamy.com/loader.js?clientId=your-client-id"></script>

The Scripts Host will:

  1. Load the Sesamy JS SDK
  2. Inject content selectors from your publisher configuration
  3. Initialize the SDK with optimal settings
  4. Enable automatic content discovery

Example with Scripts Host:

javascript
// SDK is automatically configured via Scripts Host
window.addEventListener('sesamyJsReady', async () => {
  // Content selectors already configured
  const articles = window.sesamy.content.list();

  // Check access for each article
  for (const article of articles) {
    const hasAccess = await window.sesamy.entitlements.hasAccess(article.id);

    if (!hasAccess) {
      // Show paywall overlay
      showPaywallOverlay(article);
    }
  }
});

Dynamic Content Loading

javascript
// Handle dynamically loaded content
const observer = new MutationObserver(() => {
  const newContent = window.sesamy.content.list();
  console.log('Content updated, found:', newContent.length);

  // Process new content items
  processContentItems(newContent);
});

observer.observe(document.body, {
  childList: true,
  subtree: true,
});

async function processContentItems(items) {
  for (const item of items) {
    const hasAccess = await window.sesamy.entitlements.hasAccess(item.id);

    if (hasAccess) {
      // Unlock and display
      const content = await window.sesamy.content.unlock(item.element);
      if (content) {
        item.element.innerHTML = content;
      }
    } else {
      // Show paywall
      showPaywallButton(item);
    }
  }
}

Content with Paywall Integration

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

  for (const article of articles) {
    const hasAccess = await window.sesamy.entitlements.hasAccess(article.id);

    if (!hasAccess && article.paywallUrl) {
      // Create paywall overlay
      const paywall = document.createElement('div');
      paywall.className = 'paywall-overlay';
      paywall.innerHTML = `
        <div class="paywall-content">
          <h3>Premium Content</h3>
          <p>${article.title}</p>
          <p>Price: ${article.price.amount} ${article.price.currency}</p>
          <button onclick="location.href='${article.paywallUrl}'">
            Subscribe to Read
          </button>
        </div>
      `;

      article.element.appendChild(paywall);
    } else if (hasAccess) {
      // Unlock premium content
      const content = await window.sesamy.content.unlock(article.element);
      if (content) {
        article.element.querySelector('.locked-content').innerHTML = content;
      }
    }
  }
});

Products

products.get()

Gets a product by SKU.

Parameters:

  • sku (string)

Returns: Promise&lt;Product&gt;

Example:

javascript
const product = await window.sesamy.products.get('premium-pass');
console.log(product.name, product.price);

products.autoOnboard()

Triggers auto-onboarding for a product.

Parameters:

  • sku (string)

Returns: Promise&lt;void&gt;

Example:

javascript
await window.sesamy.products.autoOnboard('premium-pass');

products.linkSpotify()

Links a Spotify account to a product.

Parameters:

  • sku (string)

Returns: Promise&lt;void&gt;

Utility Methods

Generates a link to Sesamy hosted services with optional authentication.

Parameters:

  • params: Link generation parameters
    • target: 'account' | 'change-payment' | 'change-plan' | 'consume' | 'checkout'
    • shorten: (boolean, optional) Shorten the URL
    • ttl: (number, optional) Time-to-live in seconds
    • redirectUrl: (string, optional) Post-action redirect
    • language: (string, optional) Language code

Returns: Promise&lt;string&gt;

Example:

javascript
// Generate link to account page
const accountLink = await window.sesamy.generateLink({
  target: 'account',
  shorten: true,
});

// Generate consume link
const consumeLink = await window.sesamy.generateLink({
  target: 'consume',
  sku: 'premium-article',
  redirectUrl: 'https://yoursite.com/article',
});

getPaymentIssues()

Returns failed payments and expiring cards.

Returns: Promise&lt;PaymentIssue[]&gt;

Example:

javascript
const issues = await window.sesamy.getPaymentIssues();
if (issues.length > 0) {
  console.log('Payment attention required:', issues);
}

getVersion()

Returns the SDK version.

Returns: string

Example:

javascript
const version = window.sesamy.getVersion();
console.log('SDK version:', version);

clearCache()

Clears the SDK cache.

Example:

javascript
window.sesamy.clearCache();

log()

Logs messages to console (only when debug mode is enabled).

Parameters:

  • message (string)

Example:

javascript
window.sesamy.log('Testing checkout process');

Debug mode can be enabled via:

  • URL parameter: ?sesamy-debug=true
  • Local storage: localStorage.debug = true

Analytics

analytics.track()

Tracks custom events.

Parameters:

  • eventName (string)
  • properties (object, optional)

Returns: Promise&lt;void&gt;

Example:

javascript
await window.sesamy.analytics.track('article_read', {
  articleId: 'article_123',
  category: 'technology',
  readTime: 120,
});

Browser Detection

browser.detectAdblock()

Detects if an ad blocker is enabled.

Returns: Promise&lt;boolean&gt;

Example:

javascript
const hasAdblock = await window.sesamy.browser.detectAdblock();
if (hasAdblock) {
  console.log('Ad blocker detected');
}

browser.isInAppBrowser()

Detects if running in an in-app browser.

Returns: boolean

Example:

javascript
const isInApp = window.sesamy.browser.isInAppBrowser();

browser.isIncognito()

Detects if browser is in incognito/private mode.

Returns: Promise&lt;boolean&gt;

Example:

javascript
const isIncognito = await window.sesamy.browser.isIncognito();

Events

The SDK emits several events that you can listen to:

sesamyJsReady

Emitted when the SDK is initialized and ready.

javascript
window.addEventListener('sesamyJsReady', () => {
  console.log('Sesamy SDK is ready');
});

sesamyJsAuthenticated

Emitted when user authenticates. Call preventDefault() to prevent auto-refresh.

javascript
window.addEventListener('sesamyJsAuthenticated', (event) => {
  event.preventDefault();
  console.log('User authenticated');
});

sesamyJsLogout

Emitted when user logs out.

javascript
window.addEventListener('sesamyJsLogout', () => {
  console.log('User logged out');
});

sesamyJsClearCache

Emitted when cache is cleared.

javascript
window.addEventListener('sesamyJsClearCache', () => {
  console.log('Cache cleared');
});

sesamyJsPurchase

Emitted after a purchase is completed.

javascript
window.addEventListener('sesamyJsPurchase', (event) => {
  console.log('Purchase completed:', event.detail.itemSrc);
});

URL Triggers

The SDK can respond to query parameters:

?sesamy-refresh

Clears cache and emits sesamyJsClearCache event.

?sesamy-user=email@example.com

Validates user email, logs out and re-authenticates if mismatch.

?sesamy-login

Validates user is authenticated, initiates login if not.

?sesamy-purchase

Triggers sesamyJsPurchase event.

?sesamy-token=<token>

Parses token and adds content permissions.

?sesamy-debug=true

Enables debug logging.

Custom HTML Attributes

sesamy-visibility

Controls element visibility based on authentication state.

html
<div sesamy-visibility="logged-in">Welcome back!</div>
<div sesamy-visibility="not-logged-in">Please log in</div>

Attaches click handlers for common actions.

html
<button sesamy-link="login">Log In</button>
<button sesamy-link="logout">Log Out</button>
<button sesamy-link="account">My Account</button>

TypeScript Support

The SDK includes comprehensive TypeScript definitions:

typescript
import type {
  SesamyAPI,
  Config,
  Profile,
  Entitlement,
  Contract,
  Checkout,
} from '@sesamy/sesamy-js';

// Type-safe API access
const sesamy: SesamyAPI = window.sesamy;
const profile: Profile = await sesamy.profile.get();

Cross-Domain Authentication

When your app domain differs from the auth domain's top-level domain:

  • Mobile browsers (Safari/iOS/Android): Automatically uses popup login
  • Desktop browsers: Uses redirect login

Example:

  • App: app.example.com, Auth: auth.different.com
    • Mobile: Popup login
    • Desktop: Redirect login

Best Practices

  1. Wait for Ready Event: Always wait for sesamyJsReady before using the API
  2. Error Handling: Wrap API calls in try-catch blocks
  3. Token Management: Use getTokenSilently() for API calls
  4. Smart Login: Use login() for best UX across browsers
  5. Event Listeners: Listen to SDK events for reactive UI updates
  6. Debug Mode: Enable during development for detailed logging
  7. Cache Management: Clear cache when needed with URL trigger or API

Resources

Advanced Features

Request Interceptors

typescript
client.interceptors.request.use((config) => {
  console.log('Making request:', config.url);
  return config;
});

Response Interceptors

typescript
client.interceptors.response.use(
  (response) => {
    console.log('Response received:', response.status);
    return response;
  },
  (error) => {
    console.error('Request failed:', error);
    throw error;
  }
);

Token Management

typescript
// Set access token
client.setAccessToken('new_access_token');

// Get current token
const token = client.getAccessToken();

// Clear token
client.clearAccessToken();

Testing

Mocking

typescript
import { SesamyClient } from '@sesamy/client';
import { jest } from '@jest/globals';

jest.mock('@sesamy/client');

const mockClient = new SesamyClient({ ... }) as jest.Mocked&lt;SesamyClient&gt;;
mockClient.getProfile.mockResolvedValue({
  id: 'user_123',
  email: 'test@example.com'
});

Next Steps

Released under the MIT License.