Skip to content

Repository files navigation

Echo

An AI-powered customer support platform that lets you embed a real-time chat widget on any website. Organizations manage conversations, configure AI behavior, and integrate voice support — all from a single dashboard.

Live Demo: https://echo-web-eight-umber.vercel.app


Features

  • Embeddable widget — drop a single <script> tag on any site to add a floating chat button
  • AI chat — powered by Google Gemini with RAG for context-aware responses
  • Voice calls — integrated Vapi AI voice assistant for phone-style support
  • Real-time conversations — live inbox with unresolved / escalated / resolved status tracking
  • Widget customization — configure greeting messages, quick-reply suggestions, primary color, and button position
  • Domain allowlisting — restrict which domains can embed your widget
  • Multi-tenant — organization-based access control via Clerk
  • Contact sessions — capture visitor metadata (timezone, browser, screen size, referrer) automatically
  • Plugin system — connect third-party services (Vapi credentials stored securely in AWS Secrets Manager)
  • Billing — subscription management per organization

Tech Stack

Layer Technology
Monorepo Turborepo + pnpm
Dashboard Next.js 15 (Turbopack)
Widget Next.js 15 (Turbopack)
Embed script Vite + TypeScript
Backend Convex (real-time DB + serverless functions)
Auth Clerk (organizations + webhooks)
AI Google Gemini via Vercel AI SDK + @convex-dev/agent
RAG @convex-dev/rag
Voice Vapi AI
Secrets AWS Secrets Manager
Styling Tailwind CSS + shadcn/ui
Error tracking Sentry

Monorepo Structure

echo/
├── apps/
│   ├── web/        # Dashboard (port 3000)
│   ├── widget/     # Embeddable chat UI (port 3001)
│   └── embed/      # Vanilla JS embed script (port 3002)
└── packages/
    ├── backend/    # Convex schema, functions, and AI agents
    ├── ui/         # Shared shadcn/ui component library
    ├── math/       # Shared utilities
    ├── eslint-config/
    └── typescript-config/

Getting Started

Prerequisites

Installation

  1. Clone the repository:
git clone https://github.com/Rabinagurung/echo.git
cd echo
  1. Install dependencies:
pnpm install
  1. Set up environment variables for each workspace (see Environment Variables).

  2. Initialize the Convex backend:

cd packages/backend
pnpm setup
  1. Run the full development stack from the root:
pnpm dev

This starts all apps in parallel via Turborepo:


Environment Variables

apps/web/.env.local

NEXT_PUBLIC_CONVEX_URL=
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
NEXT_PUBLIC_CLERK_FRONTEND_API_URL=
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/conversations
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/conversations
SENTRY_AUTH_TOKEN=
Variable Description Where to get it
NEXT_PUBLIC_CONVEX_URL Your Convex deployment URL Convex dashboard → project settings
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY Clerk publishable key Clerk dashboard → API Keys
CLERK_SECRET_KEY Clerk secret key Clerk dashboard → API Keys
NEXT_PUBLIC_CLERK_FRONTEND_API_URL Clerk frontend API URL Clerk dashboard → API Keys
SENTRY_AUTH_TOKEN Sentry auth token for source maps Sentry → Settings → Auth Tokens

apps/widget/.env.local

NEXT_PUBLIC_CONVEX_URL=
Variable Description Where to get it
NEXT_PUBLIC_CONVEX_URL Same Convex deployment URL as the dashboard Convex dashboard

packages/backend/.env.local

CONVEX_DEPLOYMENT=
CONVEX_URL=
CLERK_JWT_ISSUER_DOMAIN=
CLERK_SECRET_KEY=
CLERK_WEBHOOK_SECRET=
GOOGLE_GENERATIVE_AI_API_KEY=
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
Variable Description Where to get it
CONVEX_DEPLOYMENT Convex deployment identifier (e.g. dev:my-project-123) Generated by convex dev
CONVEX_URL Convex deployment URL Convex dashboard
CLERK_JWT_ISSUER_DOMAIN Clerk JWT issuer domain Clerk dashboard → JWT Templates
CLERK_SECRET_KEY Clerk secret key Clerk dashboard → API Keys
CLERK_WEBHOOK_SECRET Clerk webhook signing secret Clerk dashboard → Webhooks → your endpoint
GOOGLE_GENERATIVE_AI_API_KEY Google Gemini API key Google AI Studio
AWS_REGION AWS region for Secrets Manager AWS console
AWS_ACCESS_KEY_ID AWS IAM access key AWS IAM → Security credentials
AWS_SECRET_ACCESS_KEY AWS IAM secret key AWS IAM → Security credentials
CLERK_GUEST_USER_ID Clerk user ID of the pre-provisioned demo account used by "Continue as Guest" See Guest Sign-In below

apps/embed (build-time only)

VITE_WIDGET_URL=http://localhost:3001
Variable Description
VITE_WIDGET_URL URL of the deployed widget app, baked into the embed script at build time

Guest Sign-In (Recruiter Demo)

The dashboard sign-in page has a "Continue as Guest" button so people evaluating the project (e.g. recruiters) can explore it without creating an account. It signs the visitor into a single pre-provisioned demo account whose write access is disabled at the API layer, so it's safe to share — guests can view everything but can't send messages, change settings, disconnect plugins, upload/delete files, or overwrite secrets.

One-time setup in the Clerk Dashboard:

  1. Users → Create user — make a dedicated demo account (e.g. guest-demo@yourdomain.com), no password required.
  2. Sign in as that user once and create/join an Organization for it — this becomes the shared demo workspace. Populate it from the dashboard with a few example conversations, widget settings, etc. so guests see a populated demo instead of an empty one.
  3. Organizations → Roles — create a custom role with the key org:guest (name/permissions don't matter; the app enforces read-only access itself, not Clerk's built-in permission checks).
  4. Open that organization → Members, and set the demo user's role to org:guest.
  5. Copy the demo user's ID from Users → (the demo user) — it's shown at the top and starts with user_.
  6. Set it as a Convex environment variable:
cd packages/backend
npx convex env set CLERK_GUEST_USER_ID user_xxxxxxxxxxxx

Notes:

  • If your Clerk plan doesn't support custom organization roles, swap the org:guest role check in packages/backend/convex/private/checkUserIdentityAndGetOrgId.ts for a check on the user's publicMetadata (e.g. { isGuest: true }) exposed via a custom claim in your Clerk JWT template instead.
  • The write guard runs server-side on every mutation, so even a guest calling a mutation directly from devtools gets rejected with a GUEST_READ_ONLY error — the button is just the convenient path in.
  • Until CLERK_GUEST_USER_ID is set, clicking "Continue as Guest" fails with "Guest sign-in is unavailable right now."

Embedding the Widget

Once deployed, add the following snippet to any website:

<script
  src="https://your-domain.com/embed.js"
  data-organization-id="YOUR_ORG_ID"
  data-position="bottom-right"
  data-primary-color="#3b82f6"
  async
></script>
Attribute Required Default Description
data-organization-id Yes Your Clerk organization ID
data-position No bottom-right bottom-right or bottom-left
data-primary-color No #3b82f6 Any valid CSS color value

Deploy

Vercel (recommended)

  1. Push the repo to GitHub.
  2. Import each app (apps/web, apps/widget) as separate Vercel projects.
  3. Set the root directory for each project accordingly.
  4. Add the environment variables under Project Settings → Environment Variables.
  5. Build and deploy.

Convex backend

cd packages/backend
npx convex deploy

Embed script

cd apps/embed
pnpm build

Upload dist/embed.js to a CDN or your static hosting provider.


License

MIT

About

AI-powered customer support platform with an embeddable chat widget, real-time conversations, and voice call support.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages