Skip to main content
Advanced! Developers with backend access to your LMS/Website is required for this method to work

Getting Started

Before you begin the integration, you’ll need to gather some information from your Replay account:

1. Get Your Secret Key

  1. Navigate to Company Settings (may be labeled as “Manager Portal” in newer versions)
  2. Copy your Secret Key - this is what you’ll use to sign your JWT tokens
  3. Store this securely in your environment variables
Keep your secret key secure and never expose it in client-side code

2. Choose Your Activity Type

Replay supports embedding different types of activities. You can get the iframe code for each from different locations:
Location: Use the Share menu on your main roleplays pageWhat it includes: Gives users access to all folders and roleplays you’ve set upActivity Type: all-roleplaysBest for: When you want users to browse and select from multiple roleplays
Location: Build Roleplay → Export → Iframe tabWhat it includes: Direct access to one specific roleplayActivity Type: premade-roleplayBest for: When you want users to complete a specific roleplay exercise
Location: Script Memorization activity → Export → Iframe tabWhat it includes: Direct access to a script memorization exerciseActivity Type: scriptBest for: When you want users to practice memorizing specific scripts or content
1

Copy the Iframe

Each activity requires a specific iframe configuration. Here’s the base template:
<iframe
  id="550e8400-e29b-41d4-a716-446655440000"
  data-ai-activity-locator="ai-activity-iframe"
  src="https://app.replay.sale/api/iframe/launch?activityId=403dded8-6a20-410d-a234-75c0f35f44f0&activityType=premade-roleplay&integrationJwt=<INPUT_INTEGRATION_JWT>"
  width="100%"
  height="100%"
  frameborder="0"
  border="none"
  allow="microphone; camera; clipboard-write; downloads; display-capture"
  style="position: absolute; left: 0; right: 0; bottom: 0; top: 0;"
>    </iframe>
Important: The id attribute should be a unique UUID (as shown in the example above). If you need to select or reference the iframe in your JavaScript code, use the data-ai-activity-locator="ai-activity-iframe" attribute instead of relying on the id, as this provides a more reliable selector that won’t change.
You do not need to copy the iframe every time. You are free to make it more dynamic by generating the iframe on your side, but in order to get the user into the correct activity, we will need the following:src attributes:
  • a base url (typically https://yourcompany.replay.sale)
  • activityId (the unique id of the activity you want to load)
  • activityType (the type of activity you want to load)
  • integrationJwt (a signed JWT that has the required claims. See step 2 for more details)
iframe attributes:
  • allow="microphone; camera; clipboard-write; downloads; display-capture"
    • microphone and camera allow us to record the user
    • clipboard-write allows the user to copy a link to their roleplay analysis
    • downloads allows the user to download their audio / video recording
2

Generate a Signed JWT

You must generate a unique JWT for each user using your secret key. The JWT requires these claims:
  • learnerName - User’s name (first, last, or both) - used for personalization in the roleplay
  • uniqueIdentifier - Your database’s unique identifier for this user (UUID, email, etc.)
  • originDomain - Your company’s domain identifier (see details below)
User Creation/Linking Logic:Replay uses the combination of originDomain + uniqueIdentifier to either:
  • Create a new user if this combination doesn’t exist in our database
  • Link to an existing user if this exact combination already exists
Why both fields are needed:
  • uniqueIdentifier alone isn’t enough because different companies might use simple IDs like “1”, “2”, “3”
  • originDomain prevents collisions between different companies using the same simple identifiers
  • Together, they create a unique namespace for each company’s users
The originDomain is used to namespace users and prevent collisions between different companies or systems. Here’s what you need to know:Purpose: If you use simple identifiers like 1, 2, 3 for users, and another company also uses 1, 2, 3, we need a way to distinguish between “User 1 from Company A” and “User 1 from Company B”.How to set it:
  • Use your main company domain (e.g., mycompany.com, microsoft.com, google.com)
  • It does NOT need to match the actual domain where the iframe is hosted
  • Use the same value consistently for all users within your organization
  • For multi-tenant systems, you can use the same domain for all your customers
  • Can be your company’s landing page, documentation site, or main application domain
Examples:
  • Single company: "originDomain": "mycompany.com"
  • Multi-tenant SaaS: "originDomain": "mycompany.com" (same for all customers)
If you manage multiple separate companies/clients:Each company should have its own secret key for security. This ensures that:
  • Company A cannot access Company B’s activities, even if they somehow obtain an iframe URL
  • Users are properly isolated between companies
  • Activity access is controlled at the company level
How it works:
  • Each activity belongs to a specific company in Replay
  • The secret key you use to sign the JWT determines which company the user belongs to
  • When a user accesses an activity, we use the activity ID to look up which company owns it
  • We then validate the JWT signature against that company’s secret key
  • Users can only access activities if their JWT was signed with the correct company’s secret key
Setup Process:
  1. Create separate child companies in Replay for each of your clients
  2. Get a unique secret key for each company
  3. Store and use the appropriate secret key when generating JWTs for each company’s users
Contact us at [email protected] to set up multiple companies and get separate secret keys.
Need a secret key or lost yours? Contact us through email ([email protected]) or Slack
3

Implement the Integration

  1. Generate the signed JWT for your user
  2. Replace <INPUT_INTEGRATION_JWT> in the iframe src with your signed JWT
  3. Load the iframe
Best practice: Create a function that handles JWT generation and iframe src updates before loading. When selecting the iframe in your JavaScript code, always use document.querySelector('[data-ai-activity-locator="ai-activity-iframe"]') instead of getElementById() since the id is a unique UUID that will vary.
4

Test Your Integration

Load your page and verify that:
  • The iframe loads successfully
  • User information is correct
  • Recording permissions work
  • Downloads function properly
Need help? Contact us at [email protected]

Code Examples

// Your backend route should use a function like this to sign the JWT
const signReplayJwt = () => {
  const uniqueIdentifier = "asdf1234"; // Replace with the actual unique identifier of your user
  const learnerName = "John Doe"; // Replace with your actual learner name
  const originDomain = "example.com"; // Replace with your domain (used for namespacing users)

  const payload = {
    uniqueIdentifier,
    learnerName,
    originDomain,
  };

  const secret = process.env.REPLAY_SECRET; // Replace with your actual secret that you got from Replay

  const integrationToken = jwt.sign(payload, secret, { expiresIn: "1h" });

  return integrationToken;
};

Frequently Asked Questions

Each company should be set up as a separate entity in Replay with its own secret key.Setup process:
  1. Contact us to create child companies for each of your clients
  2. Get a unique secret key for each company
  3. Store the appropriate secret key for each company in your system
  4. Use the correct secret key when generating JWTs for users belonging to that company
Security: This ensures that users from Company A cannot access Company B’s activities, even if they somehow obtain an iframe URL from Company B.
Use the same domain for all your customers (e.g., "mycompany.com").The originDomain is for namespacing users between different systems, not between customers. Since all your customers’ users are coming through your system, they should all use the same originDomain.Company separation is handled by:
  • Using different secret keys for each company
  • Each activity belonging to a specific company in Replay
No, if set up correctly.Here’s exactly how the security validation works:
  1. When a user accesses an activity, we use the activity ID from the iframe URL to look up which company owns that activity
  2. We then validate the JWT signature against that specific company’s secret key
  3. If the JWT wasn’t signed with the correct company’s secret key, access is denied
This means even if a user somehow gets an iframe URL for a different company’s activity, they won’t be able to access it because their JWT was signed with their own company’s secret key, not the target company’s secret key.
No. The originDomain is used to distinguish between different integration systems (e.g., “Microsoft vs Google”), not between customers within the same system.If you’re managing multiple customers through your platform, use the same originDomain for all of them. Company separation is handled through different secret keys and the activity ownership system.

Message Passing

After the user completes the roleplay, the iframe will send messages to the parent window containing information about the user’s performance and progress. To receive these messages, you’ll need to set up an event listener in your parent window.

Setting Up the Listener

Add this code to your parent window to receive messages from the Replay iframe:
window.addEventListener('message', function(event) {
    // Only accept messages from your Replay domain
    if (event.origin !== 'https://app.replay.sale') return;

    console.log('Received message from iframe:', event.data);

    if (event.data.type === 'roleplay_result') {
        console.log('Score:', event.data.score);
        console.log('Full result:', event.data.result);
    }
});

When do we pass the message?

The message will be passed when the “Analysis” page is loaded for a roleplay that has been completed within the past 1 minute.

Message Interface

The message type will always be “roleplay_result” and will contain both the overall score and the complete result object.
interface IframeRoleplayResultMessageData {
  type: "roleplay_result";
  data: RoleplayResult;  // Uses the RoleplayResult interface defined in the Data Model documentation
}
Link to RoleplayResult Data Model