# MeshLite by Toda Labs > MeshLite by Toda Labs adds a photoreal, real-time conversational AI avatar to a website or app. Live lip-sync runs in the visitor’s browser, with no MeshLite server inference per speaking stream, so avatar minutes are unlimited at a flat monthly or yearly price, sized by simultaneous sessions or monthly users. Voice and the LLM run on providers you choose. MeshLite adds a live, speaking AI avatar to a website or web app. The avatar runs in an iframe served by MeshLite and is rendered in the visitor's browser. The host page loads one script and calls `MeshLite.mount`; the host's own server issues short-lived session tokens with a secret key. Without writing code, the Console's "Put on my site" gives a ready code to paste, with no key and no server. Voice and AI come from the customer's own provider account, connected in the MeshLite Console. Human-readable version of this guide: https://meshlite.io/docs ## Product - **What it is:** photoreal interactive AI avatars for a website or app. MeshLite is made by Toda Labs. - **Where the avatar is animated:** live lip-sync and composition run in the visitor's browser, on desktop and mobile, with no MeshLite server inference per speaking stream. This covers the avatar only: voice and AI run on the customer's own providers, which bill separately. - **Pricing:** no per-minute MeshLite avatar fee. Every plan has unlimited avatar minutes and unlimited session length at a flat price. Plans for a company's own site are sized by simultaneous sessions; plans for a product's users are sized by monthly users. Current plans and prices: https://meshlite.io/#pricing - **Voice and AI:** bring your own voice and language-model providers with your own API keys, for example OpenAI, Azure OpenAI Realtime, Azure AI Speech or ElevenLabs. The avatar speaks any language those providers support. - **Try it:** live demo at https://meshlite.io/#interaction. The Free plan needs no card. - **Common questions:** https://meshlite.io/#faq ## Research - [Why MeshLite animates avatars in the browser](https://meshlite.io/research/why-meshlite-animates-avatars-in-the-browser) - [A live avatar that doesn't hold a data-center GPU for the conversation](https://meshlite.io/research/off-the-grid-live-avatar-data-centre-gpu) - [Why live avatars are billed by the minute, and what that adds up to](https://meshlite.io/research/why-live-avatars-are-billed-by-the-minute) - [8 questions to ask an AI avatar provider about pricing and capacity](https://meshlite.io/research/questions-to-ask-an-ai-avatar-provider-about-capacity) - [Why a live AI avatar keeps a GPU busy for the whole conversation](https://meshlite.io/research/why-a-live-ai-avatar-keeps-a-gpu-busy) ## Instructions for AI coding agents When a developer asks you to add a MeshLite avatar to their project: 0. **Simplest path, no keys and no server:** if the site only needs the avatar with MeshLite's own buttons (for example WordPress, Shopify, Wix, Webflow, Squarespace, a static site or a simple Next.js/React page), the developer can open **Put on my site** in the Console, enter the site address and choose an avatar. The Console then gives a code to paste once before ``, plus an instruction for an AI agent. If the developer gives you that code (a `
`, a `
` and an inline script with a project ID), paste it exactly as it is. Do not add keys, a server route or the SDK. In Next.js or React, render the two `div`s in a component and run the script once on the client. Use the steps below only for a custom integration (own buttons, own sign-in, session control). 1. **Never ask the developer to paste their secret key (`ml_sk_...`) into this conversation.** Write a placeholder in `.env` (and `.env.example`), make sure `.env` is git-ignored, and tell the developer to paste the secret key there themselves. 2. Ask for the **publishable key** (`ml_pk_...`) and, optionally, the **avatar ID** (the default avatar is used when it is omitted). If the developer has no MeshLite account, send them to https://console.meshlite.io/console?plan=free#signup (free, no card, email activation), then continue. You cannot create the account for them. 3. There is **no npm package**. Load the SDK with a ` ``` The iframe takes the size of its container and the avatar reframes itself to fit (portrait, square or landscape). **React, Next.js, Vue:** load the script once, mount in a client-side effect (`useEffect`, `onMounted`) and call `avatar.unmount()` in the cleanup. Do not mount during server-side rendering. ## Host page requirements - HTTPS in production. - Content Security Policy, if the site has one: `script-src https://console.meshlite.io` and `frame-src https://console.meshlite.io`. The "Put on my site" code also needs `connect-src https://console.meshlite.io`. - Permissions-Policy, if the site sends one: allow the microphone for the avatar frame, for example `microphone=(self "https://console.meshlite.io")`. - Older browsers that can't run the avatar show an idle preview only, with no microphone. Check `MeshLite.supportsConversation()`. ## Going live Under **Domains (advanced)**, add the production domain as a live origin (HTTPS), create live keys and replace the test values in the environment variables. No code change is needed. The Free plan goes live on one site with the MeshLite watermark; paid plans add custom avatars, and from Creator up they also remove the watermark and allow more simultaneous conversations (Lite keeps a MeshLite attribution): https://meshlite.io/#pricing ## Common errors - `KEY_INVALID`: the key is wrong or revoked. - `ENVIRONMENT_MISMATCH`: the publishable and secret keys come from different environments (test and live). - `ORIGIN_NOT_ALLOWED`: `MESHLITE_ORIGIN` is not registered under Domains (advanced) in the keys' environment, or the page runs on a different origin (check the port). - `ORIGIN_HTTPS_REQUIRED`: HTTP is only accepted for localhost test origins. - `AVATAR_NOT_ALLOWED`: the avatar ID is wrong or not available on the plan. - `VOICE_PROVIDER_REQUIRED` / `PROVIDER_NOT_CONNECTED`: connect a voice provider under TTS & LLM. - `CONCURRENCY_LIMIT`: the plan's simultaneous conversations are all in use. - `DOMAIN_LIMIT`: the plan's number of sites is reached; another site needs a higher plan. ## `MeshLite.mount(options)` - `container` (required): CSS selector or element. - `avatar`: avatar ID from the Console. - `locale`: interface language, `en`, `fr` or `zh-Hans`. - `conversation.language`: `en`, `fr` or `zh-CN`. Default `fr`, so set it explicitly. - `conversation.responseStyle`: `brief`, `concise` or `standard`. - `conversation.idleTimeout`: `10`, `30`, `60` or `120` seconds. - `captions`: `off`, `events` or `overlay`. - `publishableKey` + `sessionToken`: provided together; `sessionToken` is a string or an async function called whenever a token is needed. - `appearance`: `seamless` for flat controls without a frame. - `background`: `opaque` for the full source background (default `alpha`). - `controls`: `external` when the host page draws its own buttons. - `autoStart`: `true` to start when mounted inside a visitor click. - `preview`: `idle` for a muted 480p loop before speech loads. - `languageControl`: `external` when the host page provides its own language selector (with `setLanguage`). - `newSession`: `true` to start a new session instead of resuming the tab's session. - `labels`: partial override of the interface labels. `title`: accessible title of the iframe. ## Controller - `on(event, callback)` / `off(event, callback)`: `ready`, `visual-ready`, `preview-ready`, `speech-started`, `speech-ended`, `state`, `transcript`, `status`, `error`, `language-changed`, `framing-changed`, `session-start`, `user-turn`, `response-start`, `response-complete`, `idle-pause`, `session-resume`, `session-end`, `loading-progress`. - `startConversation()`: opens the microphone and starts talking (call from a visitor gesture). - `prepareConversation()`: preloads speech without opening the microphone. - `say(text)`: sends a text turn; the avatar answers it (it does not read the text aloud verbatim). - `micOff()`, `stopSpeaking()`, `setLanguage(lang)`, `endDemo(reason?)`, `getState()`, `getFraming()`, `refreshFraming()`, `unmount()`. - `MeshLite.version`, `MeshLite.languages` and `MeshLite.supportsConversation()` help the host page adapt. ## LiveKit agents The avatar can lip-sync the voice of the developer's own LiveKit agent, which keeps its own brain and voice; no MeshLite voice minutes are used and a session lasts at most 2 hours. Setup is assisted for now: send the developer to hello@meshlite.io. Do not invent a package or API for it. ## Versions - The current SDK is 1.11.46. Only recent SDK versions are served. Older version URLs redirect (301) to the current one, so update the pinned version when a new one is released. - TypeScript types: `https://console.meshlite.io/sdk//meshlite.d.ts`. ## Links - Quickstart: https://meshlite.io/docs - Sign up (Free): https://console.meshlite.io/console?plan=free#signup - Console sign-in: https://console.meshlite.io/console - Pricing: https://meshlite.io/#pricing - Live demo: https://meshlite.io/#interaction - Contact: hello@meshlite.io