Official Documentation

TrialMoments Documentation

Integrate TrialMoments in 5 minutes and start converting more free trials. Complete API reference, code examples, and troubleshooting guide.

You're here because you need to convert more free trial users into paying customers without building a complex conversion system from scratch.

TrialMoments is a JavaScript library that delivers 5 productized conversion moments at exactly the right time in your users' trial journey. Instead of generic onboarding tools or building custom modals, you get battle-tested conversion patterns that have increased trial-to-paid rates by up to 35% for high-growth SaaS companies.

This documentation covers everything from 5-minute CDN installation to advanced configuration. Whether you're a solo founder shipping fast or an engineering team integrating for scale, you'll find clear API references, copy-paste code examples, and troubleshooting guides.

What makes TrialMoments different:

We sell decisions, not flexibility. The 5 moments and their trigger logic are fixed by design, eliminating analysis paralysis and ensuring you're using proven conversion patterns. You customize the copy and behavior, but the timing and structure are productized best practices.

5-Minute Setup

From installation to first conversion moment in under 5 minutes. Simple CDN installation.

30KB Bundle

Smaller than most product images. Zero dependencies. Minimal impact on page load.

Shadow DOM Isolation

No CSS conflicts with your app. Works with any framework or design system.

Quick Start (5 Minutes)

Get TrialMoments running in your SaaS app in three simple steps.

1Add the CDN Script

Add this script to your HTML <head> tag, right before the closing tag.

<!-- Add to your HTML <head> tag -->
<script src="https://cdn.trialmoments.com/sdk.js"></script>
<script>
  TrialMoments.init({
    projectId: "proj_abc123",
    userId: "user_456",
    trialEndsAt: 1769721600,
    upgradeUrl: "/settings/billing"
  });
</script>

2Initialize with User Data

Replace the placeholder values with your actual project ID and user data. Get your project ID from the TrialMoments dashboard.

TrialMoments.init({
  // Required
  projectId: "proj_abc123",        // Your TrialMoments project ID
  userId: "user_456",              // Current user's unique ID
  trialEndsAt: 1769721600,         // Unix timestamp when trial expires

  // Optional
  upgradeUrl: "/settings/billing", // Default upgrade URL
  isAdmin: false,                  // Is current user an admin?
  debug: false                     // Enable console logging
});

3Trigger Moments

Most moments trigger automatically based on trial status. For premium feature blocking, call blocked() when users attempt to access locked features.

// When user clicks a premium feature
document.querySelector('.premium-feature').addEventListener('click', () => {
  TrialMoments.blocked('advanced-analytics');
});

// Works with any feature name
TrialMoments.blocked('team-collaboration');
TrialMoments.blocked('api-access');

That's it! You're done.

TrialMoments will now display conversion moments automatically based on your trial timeline. Customize copy and behavior in your admin dashboard.

Installation & Setup

CDN Installation (Recommended)

The fastest way to get started. Perfect for most use cases. No build step required.

<!-- Add to your HTML <head> tag -->
<script src="https://cdn.trialmoments.com/sdk.js"></script>
<script>
  TrialMoments.init({
    projectId: "proj_abc123",
    userId: "user_456",
    trialEndsAt: 1769721600,
    upgradeUrl: "/settings/billing"
  });
</script>

The script is served from a global CDN with automatic caching and compression. Bundle size: ~30KB gzipped.

Browser Support

TrialMoments requires modern browsers with Shadow DOM support:

  • Chrome 90+ (May 2021)
  • Safari 14+ (September 2020)
  • Firefox 88+ (April 2021)
  • Edge 90+ (May 2021)

No IE11 support. Covers 95%+ of global web traffic.

API Reference

TrialMoments.init(config)

Initializes TrialMoments with your project configuration and user data. Call this once when a user authenticates and is on a trial.

ParameterTypeRequiredDescription
projectIdstringRequiredYour TrialMoments project ID from the dashboard (e.g., 'proj_abc123')
userIdstringRequiredCurrent user's unique ID from your database
trialEndsAtnumberRequiredUnix timestamp (seconds) when the trial expires
upgradeUrlstringOptionalDefault URL for upgrade CTAs (e.g., '/settings/billing')
isAdminbooleanOptionalWhether the user is an admin (for audience targeting)
debugbooleanOptionalEnable console logging for debugging
TrialMoments.init({
  // Required
  projectId: "proj_abc123",        // Your TrialMoments project ID
  userId: "user_456",              // Current user's unique ID
  trialEndsAt: 1769721600,         // Unix timestamp when trial expires

  // Optional
  upgradeUrl: "/settings/billing", // Default upgrade URL
  isAdmin: false,                  // Is current user an admin?
  debug: false                     // Enable console logging
});

TrialMoments.blocked(featureName)

Displays a blocked feature prompt when users attempt to access premium functionality. Each feature name is tracked separately for analytics.

ParameterTypeRequiredDescription
featureNamestringRequiredUnique identifier for the premium feature (e.g., 'advanced-analytics', 'api-access')
// When user clicks a premium feature
document.querySelector('.premium-feature').addEventListener('click', () => {
  TrialMoments.blocked('advanced-analytics');
});

// Works with any feature name
TrialMoments.blocked('team-collaboration');
TrialMoments.blocked('api-access');

TrialMoments.destroy()

Cleans up TrialMoments, removes all UI elements, and stops tracking. Call this when a user logs out or their trial ends.

// Destroy TrialMoments when user logs out or trial ends
TrialMoments.destroy();

Custom Callbacks

Instead of redirecting to an upgrade URL, you can handle CTA clicks with a custom callback. Useful for showing modals, opening payment forms, or custom flows.

// Define a global callback
window.onTrialMomentsUpgrade = (momentSlug) => {
  console.log('User clicked CTA for:', momentSlug);
  // Show your custom upgrade modal, open payment form, etc.
};

Configure moments to use callbacks in the admin dashboard by setting ctaType: "callback".

The 5 Productized Conversion Moments

Each moment appears at a specific point in the trial journey to maximize conversion. Want to see these moments visually? See the 5 moments in action on our homepage.

1. First Load Trial Message

Shown on first app load during trial. Sets expectations and highlights benefits. Dismissible, shown only once per user.

2. Trial Countdown Indicator

Persistent indicator showing days remaining in trial. Always visible, updates in real-time. Keeps urgency top-of-mind.

3. Trial Ending Soon Warning

Appears when 3 or fewer days remain. Creates urgency without being annoying. Shown once per day maximum.

4. Blocked Feature Prompt

Triggered manually via TrialMoments.blocked(). Shows when users try to access premium features they don't have access to yet.

5. Trial Ended State

Displayed when trial expires. Makes upgrade path obvious and urgent. Cannot be dismissed until user upgrades.

6. Floating Trial Widget

Customizable corner widget with 3 styles: Compact Circle (rotating border), Pill Progress (progress bar), or Card Action (mini card with CTA). Always visible but unobtrusive.

Configuration Options

What You Can Configure

All moment configuration happens in the TrialMoments admin dashboard. The script fetches configuration from your backend and displays moments accordingly.

  • Copy: Titles, body text, benefit bullet points, CTA button text
  • CTA Behavior: Redirect to URL or trigger custom callback
  • Display Rules: Audience targeting (all users vs admins only), frequency (once-per-user/session/day)
  • Visibility: Dismissal settings, remember dismissal preferences
  • Widget Style: Position (4 corners), style (circle/pill/card), colors per style

What You Cannot Configure

These constraints are the product's strength—productized best practice, not a flexible tool.

  • When moments trigger: Fixed logic based on trial timeline (can't change 3-day threshold, timing, etc.)
  • UI layouts: Pixel-perfect components that match design system (can't rearrange elements)
  • Which moments exist: Always 5 moments (can disable individual moments, but can't create new ones)

Integration Examples

TrialMoments is framework-agnostic and works with any JavaScript framework. Here are integration examples for popular frameworks.

React / Next.js Integration

Initialize in a useEffect hook when the user authenticates. Clean up on unmount.

import { useEffect } from 'react';

// Make sure CDN script is loaded in your HTML <head>
// <script src="https://cdn.trialmoments.com/sdk.js"></script>

function App() {
  useEffect(() => {
    if (user?.isTrial) {
      window.TrialMoments.init({
        projectId: process.env.NEXT_PUBLIC_TM_PROJECT_ID,
        userId: user.id,
        trialEndsAt: Math.floor(new Date(user.trialEndsAt).getTime() / 1000),
        upgradeUrl: '/upgrade',
        isAdmin: user.role === 'admin'
      });
    }

    return () => window.TrialMoments.destroy();
  }, [user]);

  return <YourApp />;
}

Vue.js Integration

Use onMounted and onUnmounted lifecycle hooks in your composition API setup.

// In your main App.vue or layout component
// Make sure CDN script is loaded in your HTML <head>
// <script src="https://cdn.trialmoments.com/sdk.js"></script>

<script setup>
import { onMounted, onUnmounted } from 'vue';

const user = inject('user');

onMounted(() => {
  if (user.isTrial) {
    window.TrialMoments.init({
      projectId: import.meta.env.VITE_TM_PROJECT_ID,
      userId: user.id,
      trialEndsAt: Math.floor(new Date(user.trialEndsAt).getTime() / 1000),
      upgradeUrl: '/upgrade'
    });
  }
});

onUnmounted(() => {
  window.TrialMoments.destroy();
});
</script>

Blocking Premium Features

Check trial status before showing premium features. Display blocked prompt if user is still on trial.

// Example: Blocking advanced analytics
const AnalyticsButton = () => {
  const handleClick = () => {
    if (user.isTrial) {
      TrialMoments.blocked('advanced-analytics');
      return;
    }
    // Show analytics for paid users
    showAnalyticsDashboard();
  };

  return <button onClick={handleClick}>View Analytics</button>;
};

Works with any framework

TrialMoments uses Shadow DOM to isolate its UI, preventing conflicts with Angular, Svelte, Ember, or any other framework. The examples above apply to any modern JavaScript environment.

Best Practices

Trigger blocked prompts at the moment of friction

Call blocked() when users click premium features, not preemptively. This creates context and increases conversion.

Keep upgrade URLs consistent across all moments

Use the same upgrade URL in your initialization and dashboard configuration. Inconsistent URLs create confusion and reduce conversion.

Test in staging before enabling in production

Create a separate TrialMoments project for staging. Test all moments, timing, and copy before rolling out to real users.

Use debug mode during development

Enable debug: true to see detailed console logs about moment triggers, dismissals, and analytics events.

Don't show upgrade prompts to paying customers

Only initialize TrialMoments when user.isTrial === true. Showing trial prompts to paid users damages trust.

Don't spam users with too many blocked() calls

Be strategic about which features trigger blocking prompts. Too many interruptions reduce conversion and hurt user experience.

Troubleshooting

Moments Not Showing?

  1. 1
    Check localStorage: Run localStorage.getItem('tm_proj_123_user_456') in console. If present, moment was already shown and dismissed.
  2. 2
    Check frequency rules: Some moments are once-per-user, once-per-session, or once-per-day. Wait or clear localStorage to test again.
  3. 3
    Check audience targeting: If moment is set to "admins only" and isAdmin: false, it won't show.
  4. 4
    Verify enabled moments: Check dashboard configuration that the moment is in the enabledMoments array.

Widget Not Appearing?

  • Check enabledMoments includes "floating-trial-widget"
  • Verify widget config exists on moment configuration
  • Check for z-index conflicts (widget uses z-index: 999997)

Styles Look Wrong?

Shadow DOM should prevent CSS conflicts, but check these if you're seeing style issues:

  • Inspect shadow root in DevTools to verify styles are scoped correctly
  • Check if your site has global !important styles that might pierce Shadow DOM
  • Verify CSS variables are being injected (check for --tm-* custom properties)

Using Debug Mode

Enable detailed console logging to diagnose issues:

TrialMoments.init({
  projectId: "proj_abc123",
  userId: "user_456",
  trialEndsAt: 1769721600,
  debug: true // Enables detailed console logging
});

// Check browser console for:
// [TrialMoments] Initialized successfully
// [TrialMoments] Config fetched: {...}
// [TrialMoments] Moment triggered: trial-ending-soon

Analytics Not Tracking?

  • Check analytics.enabled: true in your project configuration
  • Verify endpoint exists: POST /api/analytics/track
  • Open Network tab to see batched requests (flush every 30 seconds or 10 events)

Frequently Asked Questions

Ready to Get Started?

Create your free TrialMoments account and start converting more trials today.

Need help? Contact support or learn how TrialMoments works.