Customization Guide
Audience: developers and resellers white-labelling or extending WaDesk — themes, branding, the asset build, languages, and the environment settings that change behaviour without touching code.
What You Can Customize
Most white-label changes are no-code: logos, colours, app name, and message footers are admin settings. Deeper changes — restyling, new pages, new translations — touch the front-end build. This page covers both, in roughly increasing order of effort:
- Themes — the four built-in looks and how the theme switch works.
- Branding — logos, favicon, app name, and outbound footers.
- Front-end build — Vite + Tailwind v4, when and how to rebuild.
- Languages — the translation files and adding a new one.
- Environment settings — behaviour you change in the
.envfile.
Themes
The dashboard ships four themes: paper (default), bright, dark, and doodle. The active theme is applied by setting a data-theme attribute on the page; the CSS then styles each theme off it:
html[data-theme="dark"] .ts-control { ... }
html[data-theme="bright"] .ts-dropdown { ... }
/* paper is the default — no attribute set */
The user's choice is remembered in their browser (a wa-theme cookie) and applied on the very first paint so the page never flashes the wrong theme on reload. The server reads the same cookie so server-rendered parts (notably the logo) match the active theme straight away — the cookie, not a saved profile setting, is the source of truth.
Adding a theme: register the new theme key, add itshtml[data-theme="..."]rules in the CSS, and add it to the theme switcher. An unknown saved value safely falls back topaper.
Branding & White-Label
Brand assets come from admin settings — no code edits needed:
| Asset | Configured at |
|---|---|
| Per-theme logo (one per theme) | Admin → Settings → General |
| Favicon | Admin → Settings → General |
| App name | Admin settings (falls back to the app's configured name) |
| Billing identity (company, address, tax ID…) | Admin → Checkout Settings (printed on invoices) |
Logos fall back gracefully: a missing per-theme logo uses the default paper logo, and if no logo is set at all the UI shows a text wordmark instead.
Outbound Message Footers
The footer added to outbound messages is decided per-workspace:
- If the workspace's plan does not include "remove branding" → the platform's default footer (set by the admin) is used.
- If the plan does include "remove branding" → the workspace's own footer is used if set, otherwise no footer at all.
The footer is added to plain-text messages and to the footer line on button/interactive messages. Approved WhatsApp templates are excluded — their content cannot be changed after approval. The bridge is given the final footer along with the rest of a number's settings.
No emojis — SVG only. The product's style is inline SVG icons (16×16, currentColor stroke), never emoji. Keep any custom UI, log lines, and message text emoji-free to match.
Front-End Build (Vite + Tailwind v4)
The front-end is compiled with Vite 7 and Tailwind CSS v4. The build has two style entry points — one for the dashboard/admin and one for the public landing pages — plus the main app script, as declared in vite.config.js:
// vite.config.js
laravel({
input: [
'resources/css/app.css', // dashboard / admin / user shell
'resources/css/frontend.css', // public landing pages
'resources/js/app.js',
],
refresh: true,
})
Tailwind v4 is configured in CSS: the colour palette and fonts are defined in an @theme {} block inside the dashboard stylesheet.
Commands (from the project root):
npm install # install front-end deps (first time) npm run dev # dev server with hot reload (development) npm run build # compile production assets
Rebuild after any front-end change. Editing the stylesheets or scripts, or adding new Tailwind classes, needsnpm run buildfor production (or a runningnpm run devin development). The whole local stack — web server, queue, logs, and the asset build — can be started together withcomposer dev.
Adding Languages
Translations are flat JSON files in the lang/ directory, keyed by the English source string. WaDesk ships en.json plus 20 translated locales:
lang/ ├── en.json (source) ├── ar.json bn.json de.json es.json fr.json he.json hi.json ├── id.json it.json ja.json ko.json nl.json pl.json pt.json └── ru.json th.json tr.json ur.json vi.json zh-CN.json
Each file maps the original string to its translation:
// lang/fr.json
{
"Team Inbox": "Boîte de réception d'équipe",
"Send message": "Envoyer le message"
}
To add a new language:
- Copy
lang/en.jsontolang/<code>.json(e.g.lang/sv.json) and translate the values. - The default and fallback language are set by
APP_LOCALE/APP_FALLBACK_LOCALEin the.envfile (bothenby default); users switch language using the in-app language switcher. - A built-in tool can scan the app for any newly-added text and append it to the translation files, keeping them in sync as you add features.
Right-to-left languages (Arabic, Hebrew, Urdu) are already included, and the UI handles right-to-left layout automatically.
.env Knobs
Behaviour you change without touching code. The most relevant for customization and deployment:
| Variable | Effect |
|---|---|
APP_NAME | Default app name (admin app_name setting overrides it in the UI). |
APP_URL | Public base URL. Must be the real HTTPS domain — used to build media URLs, Twilio StatusCallback, and links Meta must be able to fetch. |
APP_LOCALE / APP_FALLBACK_LOCALE | Default + fallback language (both en out of the box). |
DB_* | MySQL connection (host, port, database, username, password). |
QUEUE_CONNECTION | Queue driver — database by default; switch to redis for higher throughput. |
CACHE_STORE / SESSION_DRIVER | Cache + session backends (both database by default). |
SERVER_URL | The address of the Node bridge, used by the send path and scheduler. |
NODE_WEBHOOK_TOKEN | Shared secret that authenticates the app and the bridge to each other. Must match the value in node/.env. |
MAIL_* | Outbound email for invoices, notifications, and password resets. |
Several of these also have an admin-panel equivalent that takes precedence — for example the default WhatsApp engine, the allowed engines, the Meta API version, and the bridge URL. Prefer the admin UI for those; the .env values act as fallbacks at startup.
After editing.env: clear the config cache (php artisan config:clear, orconfig:cachein production). Changes are not picked up while a stale cached config exists.
Conventions to Respect
- Inline SVG icons only — no emoji anywhere in the UI, scripts, or logs.
- Encrypted credentials — always read and write engine credentials through the provided helpers, never the raw stored value.
- Engine-aware UI — gate engine-specific features behind the active-engine check so operators never hit a dead end.
- Rebuild assets after any front-end change; clear the config cache after any
.envchange.
Related Pages
- Architecture Overview — the layout these files live in.
- WhatsApp Engines — how engine selection and footers reach a send.
- Node Bridge & Realtime — the bridge that the
SERVER_URL/NODE_WEBHOOK_TOKENknobs configure.