Static HTML Example

This example shows how to integrate AI Interview into a static HTML website using the CDN-hosted SDK.

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AI Interview Example</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
      background: #0f172a;
      color: #e5e7eb;
      margin: 0;
      padding: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
    }

    .container {
      max-width: 900px;
      width: 100%;
      padding: 20px;
    }

    h1 {
      text-align: center;
      color: #22d3ee;
      margin-bottom: 10px;
    }

    p {
      text-align: center;
      color: #94a3b8;
      margin-bottom: 30px;
    }

    #interview-container {
      width: 100%;
      height: 600px;
      background: #1e293b;
      border-radius: 12px;
      overflow: hidden;
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
    }

    #status {
      margin-top: 20px;
      padding: 15px;
      background: #1e293b;
      border-radius: 8px;
      text-align: center;
      color: #94a3b8;
    }

    #status.completed {
      background: #10b981;
      color: white;
    }

    #status.error {
      background: #ef4444;
      color: white;
    }

    @media (max-width: 768px) {
      #interview-container {
        height: 500px;
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>Customer Feedback Interview</h1>
    <p>Share your thoughts in a quick 5-minute voice interview</p>
    
    <div id="interview-container"></div>
    <div id="status">Loading interview...</div>
  </div>

  <!-- Load SDK from CDN -->
  <script src="https://unpkg.com/@ai-interview/sdk@latest"></script>
  
  <script>
    // Get invite token from URL or config
    const urlParams = new URLSearchParams(window.location.search);
    const inviteToken = urlParams.get('token') || 'YOUR_DEFAULT_INVITE_TOKEN';
    
    // Status element
    const statusEl = document.getElementById('status');
    
    function updateStatus(message, type = 'info') {
      statusEl.textContent = message;
      statusEl.className = type;
    }

    // Check browser support
    if (!InterviewSDK.isSupported()) {
      updateStatus('Your browser is not supported. Please use Chrome, Firefox, Safari, or Edge.', 'error');
    } else {
      try {
        // Mount the interview
        const embed = InterviewSDK.mount('#interview-container', {
          invite: inviteToken,
          theme: {
            primary: '#22d3ee',
            background: '#0f172a',
            text: '#e5e7eb',
          },
        });

        // Event listeners
        embed.on('start', function() {
          updateStatus('Interview in progress...', 'info');
          console.log('Interview started');
        });

        embed.on('pause', function() {
          updateStatus('Interview paused. Click resume to continue.', 'info');
        });

        embed.on('resume', function() {
          updateStatus('Interview resumed...', 'info');
        });

        embed.on('progress', function(payload) {
          updateStatus(`Interview progress: ${payload.percentage}%`, 'info');
        });

        embed.on('completed', function(payload) {
          updateStatus('Thank you! Your interview has been completed.', 'completed');
          console.log('Session ID:', payload.sessionId);
          
          // Optional: Redirect to thank you page
          setTimeout(function() {
            window.location.href = '/thank-you.html';
          }, 2000);
        });

        embed.on('error', function(payload) {
          updateStatus(`Error: ${payload.message}`, 'error');
          console.error('Interview error:', payload);
        });

        updateStatus('Ready to start', 'info');
        
      } catch (error) {
        updateStatus(`Failed to load interview: ${error.message}`, 'error');
        console.error('Mount error:', error);
      }
    }
  </script>
</body>
</html>

Breaking It Down

1. Include the SDK

Load the SDK from CDN in your HTML:

<script src="https://unpkg.com/@ai-interview/sdk@latest"></script>

2. Create a Container

Add a container element for the interview embed:

<div id="interview-container"></div>

Style it to your desired size:

#interview-container {
  width: 100%;
  height: 600px;
  border-radius: 12px;
}

3. Mount the SDK

Initialize the SDK with your invite token:

const embed = InterviewSDK.mount('#interview-container', {
  invite: inviteToken,
  theme: {
    primary: '#22d3ee',
  },
});

4. Handle Events

Listen for interview lifecycle events:

embed.on('completed', function(payload) {
  console.log('Interview completed!');
  // Redirect, show message, etc.
});

Getting the Invite Token

Option 1: URL Parameter

Pass the token via URL query string:

https://yoursite.com/interview.html?token=inv_abc123

Then extract it in JavaScript:

const urlParams = new URLSearchParams(window.location.search);
const inviteToken = urlParams.get('token');

Option 2: Server-Side Rendering

Generate the HTML on the server with the token embedded:

<?php
$inviteToken = $_GET['token'];
?>
<!DOCTYPE html>
<html>
<body>
  <div id="interview-container"></div>
  <script>
    const inviteToken = '<?php echo $inviteToken; ?>';
    // Mount SDK...
  </script>
</body>
</html>

Option 3: API Fetch

Fetch a fresh token from your backend:

async function loadInterview() {
  const response = await fetch('/api/get-interview-token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userId: '123' }),
  });
  
  const { inviteToken } = await response.json();
  
  InterviewSDK.mount('#interview-container', {
    invite: inviteToken,
  });
}

loadInterview();

Customization

Theme Colors

Match your brand:

InterviewSDK.mount('#interview-container', {
  invite: token,
  theme: {
    primary: '#146EF5',      // Brand blue
    background: '#ffffff',   // White background
    text: '#1a1a1a',         // Dark text
    borderRadius: '8px',     // Rounded corners
    fontFamily: 'Arial, sans-serif',
  },
});

Auto-Start

Skip the consent screen (ensure compliance with your region):

InterviewSDK.mount('#interview-container', {
  invite: token,
  autoStart: true, // Immediately start interview
});

Locale

Set the interview language:

InterviewSDK.mount('#interview-container', {
  invite: token,
  locale: 'es', // Spanish
});

Supported locales: en, es, fr, de, it, pt, nl, pl, ja, zh

Mobile Optimization

Responsive Container

Make the interview responsive:

.interview-wrapper {
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  padding: 20px;
}

#interview-container {
  width: 100%;
  aspect-ratio: 16 / 9;
  min-height: 400px;
}

@media (max-width: 768px) {
  #interview-container {
    aspect-ratio: 9 / 16;
    min-height: 500px;
  }
  
  .interview-wrapper {
    padding: 10px;
  }
}

Mobile Meta Tags

Include proper mobile viewport settings:

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="mobile-web-app-capable" content="yes">

Error Handling

Browser Compatibility Check

if (!InterviewSDK.isSupported()) {
  document.getElementById('interview-container').innerHTML = `
    <div style="padding: 40px; text-align: center;">
      <h3>Unsupported Browser</h3>
      <p>Please use one of these browsers:</p>
      <ul>
        <li>Chrome 80+</li>
        <li>Firefox 75+</li>
        <li>Safari 14+</li>
        <li>Edge 80+</li>
      </ul>
    </div>
  `;
}

Network Error Handling

embed.on('error', function(error) {
  if (error.code === 'NETWORK_ERROR') {
    alert('Lost connection. Please check your internet and refresh.');
  } else if (error.code === 'INVALID_TOKEN') {
    alert('This interview link has expired or is invalid.');
  } else {
    alert('An error occurred. Please try again later.');
  }
});

Complete Working Demo

Try It Live

Download the complete example and test it locally. Make sure to replace YOUR_INVITE_TOKEN with an actual invite token from your campaign.

Next Steps