Skip to main content

Overview

The Freya Client SDK connects a Freya agent directly from the browser. You build whatever UI you want; the SDK handles WebRTC transport, microphone input, remote audio playback, and the real-time event stream between the page and the agent. The SDK is loaded as a script tag — no build step or package manager required.

How it works

The connection flow has two parts: your backend mints a short-lived token, and the browser uses that token to open a WebRTC session.
  1. The user does something on your page that should start a session (a button click, a page load, etc.)
  2. Your page calls your own backend — never the Freya API directly
  3. Your backend calls POST /api/token/embed with your API key and returns the token to the browser
  4. The browser passes the token to FreyaClient, which connects to the agent over WebRTC
  5. Events fire as the conversation unfolds — transcripts, speaking state, tool calls — and you handle them however your UI needs
The API key never reaches the browser. The token is scoped to a single session and expires on its own.

Minting a token

Token minting must happen server-side. The API key used must have the Issue web call tokens permission (calls:web-token), which allows it to mint tokens for in-browser calls and external embed integrations. You can set this when creating a key from the API Keys button in the sidebar.
import requests

@app.get("/api/assistant-token")
def assistant_token(request: Request):
    resp = requests.post(
        f"{FREYA_BASE_URL}/api/token/embed",
        json={
            "agentId": AGENT_ID,
            "allowedOrigin": f"{request.url.scheme}://{request.headers['host']}",
            "ttlSeconds": 300,
        },
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json()
The response contains token, expiresAt, and baseUrl. Pass all three to FreyaClient.
If your users are behind firewalls or strict NAT, also fetch TURN credentials server-to-server from GET /api/token/webrtc/ice-servers and forward them alongside the token. This saves a round-trip from the browser and keeps TURN credentials off the client.

Installation

Add the script to your page. The SDK is served directly from the Freya dashboard:
<script src="https://app.freyavoice.ai/freya-client.js"></script>
This exposes window.Freya.FreyaClient globally. No build step, bundler, or package manager is needed.

Quick start

<script src="https://app.freyavoice.ai/freya-client.js"></script>
<script>
  const { FreyaClient } = window.Freya;

  async function startSession() {
    const { token, baseUrl, iceServers } = await fetch('/api/assistant-token')
      .then(r => r.json());

    const client = new FreyaClient({ baseUrl, token, iceServers });

    client.on('stateChanged', (state) => {
      console.log('state:', state); // connecting → connected → ready
    });

    client.on('botTranscript', ({ text }) => {
      appendMessage('agent', text);
    });

    client.on('userTranscript', ({ text, final }) => {
      if (final) appendMessage('user', text);
    });

    await client.connect();
  }
</script>

Configuration

OptionTypeRequiredDefaultDescription
baseUrlstringYesFreya API origin returned by the token endpoint
tokenstringYesShort-lived embed JWT
mode"call" | "chat"No"call""call" activates the microphone; "chat" is text-only
metadataRecord<string, unknown>No{}Arbitrary key-value pairs forwarded to the agent session
customerVariablesRecord<string, string>No{}Variables injected into the agent’s system prompt at runtime
iceServersRTCIceServer[]No[]TURN/STUN servers for production deployments

Modes

Call mode

The microphone is activated when connect() resolves. The agent hears the user in real time and responds with voice. This is the default.
const { FreyaClient } = window.Freya;
const client = new FreyaClient({ baseUrl, token }); // mode: "call" by default

Chat mode

The microphone stays off. Send text with sendMessage() and listen to botLlmText or botTranscript for the agent’s response. If the agent has TTS configured, audio is still played.
const { FreyaClient } = window.Freya;
const client = new FreyaClient({ baseUrl, token, mode: 'chat' });
await client.connect();
await client.sendMessage('What are your opening hours?');

Token lifecycle

  • Tokens expire after ttlSeconds (default 300 seconds). Mint a fresh one each time the user starts a new session rather than caching across page loads.
  • Set allowedOrigin on the server to the exact origin of the embedding page. The Freya backend rejects WebRTC connection attempts from other origins.
  • Tokens are single-use for establishing a session. Once a session is open the token is consumed.

Next steps

Client Reference

Full reference for all FreyaClient methods, events, and their payloads.

Agents

Configure the agent your embed session connects to — voice, system prompt, and tools.