Public
After-hours AI chat widget for tribecabeverage.com
aichatwebsite
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

After-hours chat — tribecabeverage.com

A Claude-powered chat widget that answers on the website only when the office is closed. tawk.to keeps business hours; this takes the night shift, captures a lead, and emails it to the office.

Why this exists instead of a tawk.to bot

tawk.to has no supported API for pushing an agent message into a live chat — its REST API is beta, gated behind an access request, and shaped for admin and reporting (properties, tickets, stats), not conversation. So an AI answering inside the tawk widget isn't buildable. Rather than migrate the whole live-chat setup off a tool that works, this covers the hours tawk.to isn't staffed and leaves the daytime alone.

How it fits together

visitor  ->  widget.js (shadow DOM, on tribecabeverage.com)
              |  GET /api/status   -- renders only if the office is closed
              |  POST /api/chat    -- SSE stream of reply deltas
              v
           index.ts (Hono)
              |-- agent.ts   Gemini reply + lead extraction
              |-- store.ts   blob-backed transcripts and leads
              +-- config.ts  hours, model, business profile, guardrails

The two chat widgets can never appear at the same time: widget.js asks /api/status before it renders anything, and /api/chat refuses to answer during business hours even if something calls it directly.

Install

<script src="https://tribeca_rep--01a039bce9a870efb2b97ddecd13d603.web.val.run/widget.js" defer></script>

Drop that in the site footer. Nothing about the tawk.to embed changes.

Environment variables

KeyRequiredWhat it does
GEMINI_API_KEYyesFrom aistudio.google.com/apikey. Without it every chat returns the fallback message with the office phone number.
LEADS_KEYto view leadsAny random string. /leads?key=... then shows captured leads. The page stays closed until this is set — it holds customer PII.
NOTIFY_EMAILnoWhere lead emails go. Unset means the val owner.
FORCE_BOTno"true" makes the bot answer around the clock. Testing only — the home page shows a warning banner while it's on.

Business profile

config.ts holds the products, pricing, service areas, and guardrails, copied from Tribeca_Rep/tribeca-sms-sales-rep so both bots say the same things. Change pricing in both places. The guardrails are the important part: no invented prices, no promised delivery dates, no orders taken, escalate to 973-913-4568.

Not built yet

  • Salesforce lookups. tribeca-salesforce-agent could let the bot answer "when is my next delivery" for existing customers. Needs SALESFORCE_AGENT_URL and SALESFORCE_AGENT_KEY copied over and a tool wired into agent.ts.
  • Live handoff. There is none by design — if someone needs a human, the bot gives them the office number and the office follows up in the morning.