Skip to main content

Chatwoot live chat (marketing pages)

The public marketing pages carry a Chatwoot Cloud live-chat bubble — the "Contact Us" channel for visitors, pricing questions, and careers applicants. Everything the repo owns is already wired; this doc gets the Chatwoot side to a professional setup on the free (Hacker) tier, with most of it automated by scripts/chatwoot-setup.sh.

Split of responsibilities

The repo owns: the widget loader (chatwoot-widget.tsx, mounted in public-layout.tsx so only marketing pages get it), the public config endpoint (GET /api/public/chatwootPublicChatwootController), the CSP whitelist in frontend/nginx.conf, and the provisioning script.

The Chatwoot dashboard owns: the inbox, greeting, pre-chat form, out-of-office, labels, canned responses, automation. Replies come from humans in the dashboard or the mobile app; there is no bot answering on its own.

The widget is off by default everywhere: with no CHATWOOT_WEBSITE_TOKEN the endpoint answers 204 and the frontend injects nothing — no script, no iframe, no connection to Chatwoot. CI and e2e therefore never see the widget.

Setup

Chatwoot Cloud gates API access tokens behind paid plans (Profile Settings → Access Token says so outright on the free tier). So there are two paths:

  • Path A — manual dashboard checklist: the free-tier path. ~20 minutes of clicking; every item below is a standard free feature.
  • Path B — scripts/chatwoot-setup.sh: only if you're on a paid Cloud plan or ever run self-hosted Chatwoot (where the API is free). Same outcome as Path A, idempotent, prints the website token at the end. Credentials (CHATWOOT_API_TOKEN from Profile Settings → Access Token, CHATWOOT_ACCOUNT_ID from the dashboard URL) go in the gitignored repo-root .env or the shell — never in compose files or GitHub Secrets.

Path A — manual checklist (free tier)

Work top to bottom; items marked (if shown) move between plans as Chatwoot reshuffles tiers — skip without guilt if your dashboard doesn't offer them.

1. Website inbox — Settings → Inboxes → Add Inbox → Website:

  • Website name MotorPH Enterprise, URL https://motorphenterprise.com
  • Widget color #1A3470 (brand.800 — matches the site's primary buttons)
  • Welcome heading Questions about MotorPH?, tagline Payroll, pricing, or careers — ask away.
  • After creation, the Configuration tab holds the website token — this is the value for CHATWOOT_WEBSITE_TOKEN (a short alphanumeric string, not a JWT).

2. Inbox settings, on the same inbox:

  • Settings tab: enable the channel greeting: Hi — you've reached MotorPH Enterprise. Ask us anything about payroll, pricing, or careers.
  • Pre Chat Form tab: enable; message Leave your email so we can reply even if you close the tab.; email required, name optional.
  • Business Hours tab (if shown): enable, timezone Asia/Manila, Mon–Fri 09:00–18:00; unavailable message: We're offline right now. Leave your email and your question and we'll reply within one business day.

3. Labels — Settings → Labels → add four:

LabelColorPurpose
marketing#1A3470Load-bearing — the widget calls setLabel('marketing'); the slug must match exactly
careers#2E7D32Load-bearing — same, for /careers* pages
pricing#F4C300Triage: plan/price questions
support#5B80C2Triage: product help

4. Canned responses — Settings → Canned Responses → add these (short code → content), then trigger them by typing / in any reply box:

5. Automation (if shown) — Settings → Automation → new rule "Label pricing questions": when a conversation is created and the message content contains pricing / price / plan / cost → add label pricing.

6. Don't skip these three:

  • Allowed domains (if shown on the inbox)motorphenterprise.com, stage.motorphenterprise.com, localhost:5173.
  • Notifications — Profile Settings → Notifications: enable email + push for conversation created. An unanswered chat is worse than no chat widget.
  • The mobile app — install Chatwoot's iOS/Android app and sign in. On a one-person team this is the single highest-leverage step in this doc: it turns "reply within one business day" into "reply in five minutes", which is what actually converts.

Pro playbook on the free tier

What makes a chat channel feel professional is response behavior, not paid features:

  • Answer with /. Type / in the reply box to insert a canned response, then edit one sentence to make it personal. Fast and accurate beats typing plan prices from memory (and getting them wrong).

  • Resolve aggressively. After the visitor's question is answered, send /thanks and hit Resolve (Cmd/Ctrl+Alt+E). A clean inbox means new chats never drown. Press ? in the dashboard for all shortcuts.

  • Let the labels work for you. The widget auto-labels marketing vs careers; the automation adds pricing. Once a week, open Reports → Overview and filter conversations by the pricing label — that list is your sales-objection backlog and a direct feed into FAQ/pricing-page copy.

  • Keep business hours honest. The out-of-office + required email means off-hours visitors become leads instead of bounces. Don't set 24/7 hours you can't staff.

  • Paid features you can skip, and what covers the gap:

    Paid featureFree-tier substitute
    Captain AI botThe pre-chat form + /-canned responses + the site's FAQ section already answer the common questions
    SLA timersMobile push notifications — you are the SLA
    More than 2 agentsTwo seats: you + one collaborator is plenty at this stage
    Advanced reportsWeekly label-filtered review in Reports → Overview
  • Two seats are free — invite a collaborator (Agents → Add) so vacations don't go unanswered.

Where the token goes

EnvironmentWhereThen
Local devCHATWOOT_WEBSITE_TOKEN=... in the repo-root .envdocker compose up -d motorph_payroll_backend
StagingSTAGE_ENV_FILE GitHub Secretnext deploy rewrites /srv/motorph/.env.stage
ProductionPROD_ENV_FILE GitHub Secretnext deploy rewrites /srv/motorph/.env

The website token is a short alphanumeric string (not a JWT — an invalid token shows up as a 404 on app.chatwoot.com/widget plus an X-Frame-Options refusal in the console). The VPS env files are rewritten from the Secrets on every pipeline run — a hand-edit on the VPS lasts one deploy. Keep the filled master in the password manager (env-vars.md).

Order matters: the CSP whitelist must be deployed to an environment before its token is configured, or the browser blocks the widget with console CSP violations. Roll out stage first, verify, then production.

Verification checklist

  • No token: curl -i localhost:5173/api/public/chatwoot → 204; zero Chatwoot requests in the network tab.
  • Token set (backend restarted; frontend image rebuilt if the CSP change wasn't deployed yet): bubble appears on /, /pricing, /careers after first idle/interaction; absent on /login, /signup, and every authenticated page; console shows no CSP violations.
  • Footer "Contact Us" opens the chat panel (falls back to mailto when the widget is off).
  • Incognito: pre-chat form asks for email; a sent message appears in the dashboard; a /careers conversation carries the careers label; the greeting fires; outside business hours the out-of-office message shows instead.
  • Reply from the dashboard with a / canned response — it renders in the visitor's widget.
  • Attachments: have an agent send an image from the dashboard. Chatwoot Cloud may serve uploads from a storage CDN; if the image breaks with a CSP console error, add that exact origin to img-src in frontend/nginx.conf.

Disabling

Blank the token (Secret or .env), redeploy/restart the backend. The endpoint goes back to 204 and the widget vanishes — no frontend change needed.