This guide will show you how to start a session and connect to it. At a high level, here’s how this process works:

  1. Your backend starts a session by calling an authenticated API endpoint and returning session credentials to your frontend.
  2. Your frontend connects to the session using the session credentials.

1. Start a session from your backend

In this section, you’ll set up your backend so that it can start sessions by calling Jay’s startSession API endpoint.

1a. Define your Jay API key as an environment variable

Create a JAY_API_KEY environment variable in your local environment (e.g., a .env file) and/or in your production environment (e.g., Vercel, AWS, etc.). In a .env file, you might include:

JAY_API_KEY=<YOUR_API_KEY>

You can retrieve your API key from Jay’s dashboard.

1b. Create an API endpoint

Create an API endpoint in your backend for starting the session. We strongly recommend using authentication in your endpoint to protect your Jay API key and prevent unauthorized users from starting sessions.

Copy and paste the code below into the API endpoint:

import os
import requests

# Your authentication logic goes here:
# ...

agent_id = <YOUR_AGENT_ID>
jay_api_key = os.getenv("JAY_API_KEY")

url = "https://jay.so/api/startSession"
headers = {
    "Content-Type": "application/json",
    "X-API-Key": jay_api_key
}
payload = {
    "agent_id": agent_id,
    "environment": "production"
}

response = requests.post(url, headers=headers, json=payload)

if not response.ok:
    raise Exception(f"Request failed with status {response.status_code}. {response.text}")

data = response.json()
return data

In the code above, make sure to replace <YOUR_AGENT_ID> with your agent ID, which you can either retrieve from the file containing your agent (e.g. agent/main.py) or from Jay’s dashboard.

Optional: You can include custom data in the payload, which will be available when the session is configured:

payload = {
    "agent_id": agent_id,
    "environment": "production",
    "custom_data": {
      "my_user_timezone": "America/New_York",
    }
}

The custom data will be available in the custom_data input parameter of the configure_session function.

Note: The custom_data field must be JSON serializable.

2. Connect to the session from your frontend

In your frontend, you’ll fetch the session credentials from the backend endpoint that you defined in step 1. Then, you’ll connect to the session using these credentials. We’ll use LiveKit to handle the WebRTC connection.

2a. Install LiveKit dependencies

Install the following dependencies:

npm install @livekit/components-react

2b. Connect to the session

The code snippet below is a simple React example that shows how to fetch the session credentials from your backend, connect to the session using these credentials, and display basic loading and connection states.

import React, { useEffect, useState } from "react";
import {
  LiveKitRoom,
  RoomAudioRenderer,
} from "@livekit/components-react";

export default function MyLiveKitExample() {
  const [sessionCredentials, setSessionCredentials] = useState<{
    token: string;
    url: string;
  } | null>(null);
  const [isFetchingSession, setIsFetchingSession] = useState<boolean>(false);

  useEffect(() => {
    // Fetch the session credentials from your backend
    setIsFetchingSession(true);
    fetch(
      <YOUR_BACKEND_ENDPOINT>, // <-- update this to your real endpoint from step 1
      { method: "POST" }
    )
      .then((res) => res.json())
      .then((data) => {
        setSessionCredentials(data)
      })
      .catch((err) => {
        console.error("Error fetching session:", err);
      })
      .finally(() => {
        setIsFetchingSession(false);
      });
  }, []);

  // Show a loading indicator while we're fetching the session
  if (isFetchingSession) {
    return <div>Fetching session...</div>;
  }

  // If we have no session credentials, let the user know
  if (!sessionCredentials) {
    return <div>Missing session credentials</div>;
  }

  // Once connected, render the LiveKitRoom
  return (
    <LiveKitRoom
      token={sessionCredentials.token}
      serverUrl={sessionCredentials.url}
      audio={true}
      onConnected={() => console.log("Connected!")}
      onDisconnected={() => {
        console.log("Disconnected from LiveKit");
      }}
    >
      <div>Connected! Start speaking to the agent.</div>
      {/* Renders audio for participants in the room */}
      <RoomAudioRenderer />
    </LiveKitRoom>
  );
}

In the code above, make sure to replace <YOUR_BACKEND_ENDPOINT> with your backend endpoint URL from step 1.

Here are a couple relevant references from LiveKit’s documentation:

  • LiveKitRoom: Provides the LiveKit room context to all its child components. It provides the room state as a React context to all child components, so you don’t have to pass it yourself.
  • RoomAudioRenderer: A drop-in solution for adding audio to your app. It takes care of handling audio tracks and makes sure that microphones and screen share are audible.