Skip to main content
Drop-in widget for any web application. HTTPS required for microphone access.

Basic Embed

<iframe
  src="https://app.toughtongueai.com/embed/SCENARIO_ID"
  width="100%"
  height="600px"
  allow="microphone"
></iframe>

Embed Variants

VariantURLUse case
Full/embed/SCENARIO_IDComplete UI with login, results
Basic/embed/basic/SCENARIO_IDConversation only
Minimal/embed/minimal/SCENARIO_IDMic button only

URL Parameters

Visual

ParamValuesExample
colorviolet-500, blue-500, green-500?color=violet-500
bgwhite, black, hex?bg=black
showPulsetrue, false?showPulse=false
hidePoweredBytrue, false?hidePoweredBy=true (Pro+)

User

ParamTypeExample
userNamestring?userName=John%20Doe
userEmailstring?userEmail=john@example.com

Behavior

ParamTypeExample
skipPrecheckboolean?skipPrecheck=true
autoStartboolean?autoStart=true
Combined:
/embed/SCENARIO_ID?color=violet-500&bg=black&userName=John&autoStart=true

Event Handling

Listen for session events:
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://app.toughtongueai.com') return;
  
  const { event: type, sessionId } = event.data;
  
  if (type === 'onStart') {
    console.log('Session started:', sessionId);
  }
  
  if (type === 'onStop') {
    console.log('Session ended:', sessionId);
    // Fetch analysis via your backend
    fetchAnalysis(sessionId);
  }
});
Events:
EventWhen
onStartConversation begins
onStopConversation ends normally
onTerminatedUnexpected end
Payload:
interface IframeEvent {
  event: 'onStart' | 'onStop' | 'onTerminated';
  sessionId: string;
  timestamp: number;
}

React Example

import { useEffect, useState } from 'react';

export default function Practice({ scenarioId }) {
  const [sessionId, setSessionId] = useState(null);
  
  useEffect(() => {
    const handler = (event) => {
      if (event.origin !== 'https://app.toughtongueai.com') return;
      
      if (event.data.event === 'onStart') {
        setSessionId(event.data.sessionId);
      }
      if (event.data.event === 'onStop') {
        window.location = `/results/${event.data.sessionId}`;
      }
    };
    
    window.addEventListener('message', handler);
    return () => window.removeEventListener('message', handler);
  }, []);
  
  return (
    <iframe
      src={`https://app.toughtongueai.com/embed/${scenarioId}?bg=black`}
      width="100%"
      height="600px"
      allow="microphone"
    />
  );
}

Responsive Container

.iframe-container {
  position: relative;
  width: 100%;
  padding-bottom: 75%;
  height: 0;
}

.iframe-container iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

Security

Always check event.origin before processing messages.
Content-Security-Policy: frame-src https://app.toughtongueai.com;
Microphone requires HTTPS (localhost works for dev).

Troubleshooting

IssueFix
Mic not workingCheck HTTPS, browser permissions, allow="microphone"
Iframe blankVerify scenario ID, check is_public=true
Events not firingCheck origin filter, ensure listener added before load
Next: REST API →