AITWIN.ME

Integration Docs

Step-by-step guide to embed @streamoji/aitwin (^0.2.3) — a React component that renders an AI twin face with TTS lipsync.

1

Prerequisites

You need a React 18 or 19 project with Node.js and npm (or pnpm/yarn). The package renders a canvas-based AI twin face with TTS lipsync — it runs in the browser only.

Peer dependencies: react and react-dom. If you use Next.js or enforce a strict Content Security Policy, see Integration notes below.

2

Install the package

Add @streamoji/aitwin and its peer dependencies to your project:

bash
npm install @streamoji/aitwin
3

Render your twin

Provide id (cloud twin slug, e.g. olivia). Use stable useCallback handlers for onReady and onError:

tsx
function TwinDemo() {
  const twinRef = useRef<AiTwinHandle>(null);

  return (
    <AiTwin
      ref={twinRef}
      id="olivia"
      onReady={() => console.log("face ready")}
      onStatusChange={(status) => console.log("status", status)}
      onError={(message) => console.error(message)}
    />
  );
}
4

Speak on demand

Control speech imperatively via the ref handle. Call speakText with any string; use stop() to interrupt playback:

tsx
<button
  type="button"
  onClick={() => void twinRef.current?.speakText("Hi, how are you?")}
>
  Speak
</button>

<button
  type="button"
  onClick={() => twinRef.current?.stop()}
>
  Stop
</button>
5

Production auth (Proxy)

For production TTS and encrypted twin assets, authenticate each session with an authToken — a short-lived Bearer credential you pass via the authToken prop. It authorizes the twin to stream TTS without ever exposing your long-lived secret in the browser.

Generate tokens from your backend by calling getAiTwinAuthToken with your Client-Id and Client-Secret in request headers (not the body). Create and view these credentials on the API Keys page in your aitwin dashboard. Pass userId and userName so usage is attributed to the right end customer in your account.

Your backend calls getAiTwinAuthToken, then your frontend receives only the returned authToken — never the Client Secret.

Never expose your Client Secret in the frontend. Store it exclusively on your server and only pass the generated authToken to <AiTwin />.
bash
curl -X POST "https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwinAuthToken" \
  -H "Content-Type: application/json" \
  -H "Client-Id: YOUR_CLIENT_ID" \
  -H "Client-Secret: YOUR_64_CHAR_API_KEY" \
  -d '{
    "userId": "end-user-123",
    "userName": "Jane Doe"
  }'
javascript
// Backend only — never run this in the browser
const CLIENT_ID = process.env.AITWIN_CLIENT_ID;
const CLIENT_SECRET = process.env.AITWIN_CLIENT_SECRET;

async function getAiTwinAuthToken({
  userId,
  userName,
  maxAvatarCreations,
  maxCreditsUtilization,
  expiresIn,
}) {
  const body = { userId, userName };
  if (typeof maxAvatarCreations === "number") {
    body.maxAvatarCreations = maxAvatarCreations;
  }
  if (typeof maxCreditsUtilization === "number") {
    body.maxCreditsUtilization = maxCreditsUtilization;
  }
  if (typeof expiresIn === "number") {
    body.expiresIn = expiresIn; // seconds; -1 = no expiry; omit = 30 min default
  }

  const response = await fetch(
    "https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwinAuthToken",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Client-Id": CLIENT_ID,
        "Client-Secret": CLIENT_SECRET,
      },
      body: JSON.stringify(body),
    },
  );

  const data = await response.json();
  if (!response.ok || !data.success) {
    throw new Error(data.error ?? "Auth token generation failed");
  }

  return data.authToken; // e.g. "client_eyJ..."
}
tsx
// Frontend — pass the token from your backend API
<AiTwin
  ref={twinRef}
  id="olivia"
  authToken={authToken}
/>

Integration notes

Framework and deployment guidance that is not part of the core install flow.

Next.js

Skip this if you are not using Next.js. AiTwin is browser-only (canvas and related APIs) and must not be server-rendered.

Add the package to transpilePackages in next.config.ts, then import AiTwin with next/dynamic and ssr: false in a client component. The viseme worker is loaded from the Streamoji CDN at runtime — you do not need to copy worker files into your app.

typescript
// next.config.ts
const nextConfig = {
  transpilePackages: ["@streamoji/aitwin"],
};

export default nextConfig;
tsx
"use client";

import dynamic from "next/dynamic";
import { useRef } from "react";
import type { AiTwinHandle } from "@streamoji/aitwin";

const AiTwin = dynamic(
  () => import("@streamoji/aitwin").then((m) => m.AiTwin),
  { ssr: false },
);

Content Security Policy (CSP)

If your site sends a Content-Security-Policy header (or meta tag), allow the AiTwin API, CDN, and WebSocket endpoints below. The SDK fetches encrypted face assets and the lipsync worker from the CDN, streams TTS from the API, and uses blob: URLs for the worker script.

Voice sessions (connect()) also require wss:// on the API host. Backend-only calls such as getAiTwinAuthToken run on your server and are not part of the browser CSP.

API (connect-src, media-src)

  • https://ai.streamoji.com
  • wss://ai.streamoji.com

CDN — face assets, thumbnails, worker script (connect-src, img-src, worker-src)

  • https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev

Dashboard & docs (optional — links only, not required for embed)

  • https://aitwin.me
Worker scripts are fetched from the CDN and instantiated via blob: URLs. If connect-src or worker-src blocks either the CDN or blob:, lipsync will fail silently or log a worker init error in the console.
text
# Example CSP additions (merge with your existing policy)
connect-src 'self' https://ai.streamoji.com wss://ai.streamoji.com https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev;
img-src 'self' https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev data: blob:;
media-src 'self' blob: https://ai.streamoji.com;
worker-src blob: https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev;
script-src 'self' blob:;

Props reference

NameDescription
idTwin slug for cloud lookup (e.g. olivia).
authTokenShort-lived Bearer auth token for TTS and encrypted assets. Generate via getAiTwinAuthToken on your backend.
ttsEngineIdTTS engine override (default Cartesia).
voiceIdOverride the default TTS voice.
speakingRateDefault speaking rate (default 0.85).
onReadyCalled when face assets are loaded and canvas is ready.
onStatusChangeTTS status: idle, loading, speaking, done, error.
onErrorLoad or runtime errors.

Ref methods

NameDescription
speakText(text, options?)Run TTS + lipsync. Optional per-call tts / voiceId overrides.
stop()Stop playback and return toward idle.
isReady()Whether face assets are loaded.