feat: custom branding (#68)

* feat: add custom branding support with environment variables and asset extraction

* chore: wrap brand assets url in quotes
This commit is contained in:
Gabriel Jablonski 2025-06-12 22:11:19 -03:00 committed by GitHub
parent 3cd273d2d0
commit c350ba15ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 208 additions and 4 deletions

73
CUSTOM_BRANDING.md Normal file
View File

@ -0,0 +1,73 @@
# Custom branding
## Brand configuration
Export environment variables and run rake task with `bundle exec rails branding:update`.
> [!IMPORTANT]
> Unset environment variables are reset to default values.
```bash
INSTALLATION_NAME="Chatwoot fazer.ai" \
BRAND_NAME="My Company" \
LOGO_THUMBNAIL="https://fazer.ai/logo-thumbnail.svg" \
LOGO="https://fazer.ai/logo.svg" \
bundle exec rails branding:update
```
| Environment variable | Default Value | Description |
| :--------------------| :------------------------------------------ | :-------------------------------------------------------------------- |
| `INSTALLATION_NAME` | `Chatwoot` | The installation-wide name used in the dashboard, title, etc. |
| `LOGO_THUMBNAIL` | `/brand-assets/logo_thumbnail.svg` | The thumbnail used for favicon (512px X 512px). |
| `LOGO` | `/brand-assets/logo.svg` | The logo used on the dashboard, login page, etc. |
| `LOGO_DARK` | `/brand-assets/logo_dark.svg` | The logo used on the dashboard, login page, etc. for dark mode. |
| `BRAND_URL` | `https://www.chatwoot.com` | The URL used in emails under the section “Powered By”. |
| `WIDGET_BRAND_URL` | `https://www.chatwoot.com` | The URL used in the widget under the section “Powered By”. |
| `BRAND_NAME` | `Chatwoot` | The name used in emails and the widget. |
| `TERMS_URL` | `https://www.chatwoot.com/terms-of-service` | The terms of service URL displayed on the Signup Page. |
| `PRIVACY_URL` | `https://www.chatwoot.com/privacy-policy` | The privacy policy URL displayed in the app. |
| `DISPLAY_MANIFEST` | `true` | Display default Chatwoot metadata like favicons and upgrade warnings. |
## Favicon and other assets
Update the favicon files in the [`public/`](public/) folder.
Can also be done by creating a zip file with relevant files, and running [`deployment/extract_brand_assets.sh`](deployment/extract_brand_assets.sh) to override the existing favicons with your own.
In this case, the zip file should be a flat archive containing the following files:
```
android-icon-36x36.png
android-icon-48x48.png
android-icon-72x72.png
android-icon-96x96.png
android-icon-144x144.png
android-icon-192x192.png
apple-icon-57x57.png
apple-icon-60x60.png
apple-icon-72x72.png
apple-icon-76x76.png
apple-icon-114x114.png
apple-icon-120x120.png
apple-icon-144x144.png
apple-icon-152x152.png
apple-icon-180x180.png
apple-icon.png
apple-icon-precomposed.png
apple-touch-icon.png
apple-touch-icon-precomposed.png
favicon-16x16.png
favicon-32x32.png
favicon-96x96.png
favicon-512x512.png
favicon-badge-16x16.png
favicon-badge-32x32.png
favicon-badge-96x96.png
ms-icon-70x70.png
ms-icon-144x144.png
ms-icon-150x150.png
ms-icon-310x310.png
```
> [!NOTE]
> You can include other assets in the zip file, and use them when running the rake task for `LOGO_THUMBNAIL`, `LOGO`, and `LOGO_DARK`.
> See [Brand configuration](#brand-configuration).

View File

@ -0,0 +1,90 @@
#!/bin/sh
set -e
if [ -z "$1" ]; then
echo "Usage: $0 <url to zip file with favicons>. See https://github.com/fazer-ai/chatwoot/blob/main/CUSTOM_BRANDING.md for more info."
exit 1
fi
URL="$1"
TEMP_DIR=$(mktemp -d)
ZIP_FILE="$TEMP_DIR/downloaded_favicons.zip"
EXTRACT_DIR="$TEMP_DIR/extracted_favicons"
TARGET_DIR="public"
EXPECTED_FILES="
android-icon-36x36.png
android-icon-48x48.png
android-icon-72x72.png
android-icon-96x96.png
android-icon-144x144.png
android-icon-192x192.png
apple-icon-57x57.png
apple-icon-60x60.png
apple-icon-72x72.png
apple-icon-76x76.png
apple-icon-114x114.png
apple-icon-120x120.png
apple-icon-144x144.png
apple-icon-152x152.png
apple-icon-180x180.png
apple-icon.png
apple-icon-precomposed.png
apple-touch-icon.png
apple-touch-icon-precomposed.png
favicon-16x16.png
favicon-32x32.png
favicon-96x96.png
favicon-512x512.png
favicon-badge-16x16.png
favicon-badge-32x32.png
favicon-badge-96x96.png
ms-icon-70x70.png
ms-icon-144x144.png
ms-icon-150x150.png
ms-icon-310x310.png
"
cleanup() {
echo "Cleaning up temporary files..."
rm -rf "$TEMP_DIR"
}
trap cleanup EXIT
echo "Downloading zip file from $URL..."
if wget -q -O "$ZIP_FILE" "$URL"; then
echo "Download successful."
else
echo "Error: Failed to download file from $URL"
exit 1
fi
echo "Creating extraction directory: $EXTRACT_DIR"
mkdir -p "$EXTRACT_DIR"
echo "Unzipping $ZIP_FILE to $EXTRACT_DIR..."
if unzip -q "$ZIP_FILE" -d "$EXTRACT_DIR"; then
echo "Unzip successful."
else
echo "Error: Failed to unzip $ZIP_FILE"
exit 1
fi
echo "Checking for expected files..."
MISSING_FILES=0
for filename in $EXPECTED_FILES; do
if ! find "$EXTRACT_DIR" -name "$filename" -print | grep -q .; then
echo "Warning: Expected file '$filename' not found in the zip archive."
MISSING_FILES=$((MISSING_FILES + 1))
fi
done
if [ "$MISSING_FILES" -gt 0 ]; then
echo "$MISSING_FILES expected file(s) were not found in the zip archive."
fi
echo "Moving extracted files to $TARGET_DIR/..."
mv "$EXTRACT_DIR"/* "$TARGET_DIR/" 2>/dev/null || true
echo "Process completed."

View File

@ -30,6 +30,7 @@ services:
- BAILEYS_PROVIDER_USE_INTERNAL_HOST_URL=true
- MAILER_SENDER_EMAIL=${MAILER_SENDER_EMAIL}
- RESEND_API_KEY=${RESEND_API_KEY}
- BRAND_ASSETS_URL=${BRAND_ASSETS_URL}
entrypoint: docker/entrypoints/rails.sh
command:
- bundle
@ -43,10 +44,9 @@ services:
restart: always
post_start:
- command:
- bundle
- exec
- rails
- db:chatwoot_prepare
- 'bundle exec rails db:chatwoot_prepare &&'
- 'bundle exec rails branding:update &&'
- 'if [ -n "$${BRAND_ASSETS_URL}" ]; then deployment/extract_brand_assets.sh "$${BRAND_ASSETS_URL}"; fi'
healthcheck:
test:
- CMD-SHELL

41
lib/tasks/branding.rake Normal file
View File

@ -0,0 +1,41 @@
# NOTE: See https://github.com/fazer-ai/chatwoot/blob/main/CUSTOM_BRANDING.md for more details.
namespace :branding do
desc 'Updates branding configurations from environment variables or defaults'
task update: :environment do
configurable_items = {
# The installation wide name that would be used in the dashboard, title etc.
'INSTALLATION_NAME' => 'Chatwoot',
# The thumbnail that would be used for favicon (512px X 512px)
'LOGO_THUMBNAIL' => '/brand-assets/logo_thumbnail.svg',
# The logo that would be used on the dashboard, login page etc.
'LOGO' => '/brand-assets/logo.svg',
# The logo that would be used on the dashboard, login page etc. for dark mode
'LOGO_DARK' => '/brand-assets/logo_dark.svg',
# The URL that would be used in emails under the section “Powered By”
'BRAND_URL' => 'https://www.chatwoot.com',
# The URL that would be used in the widget under the section “Powered By”
'WIDGET_BRAND_URL' => 'https://www.chatwoot.com',
# The name that would be used in emails and the widget
'BRAND_NAME' => 'Chatwoot',
# The terms of service URL displayed in Signup Page
'TERMS_URL' => 'https://www.chatwoot.com/terms-of-service',
# The privacy policy URL displayed in the app
'PRIVACY_URL' => 'https://www.chatwoot.com/privacy-policy',
# Display default Chatwoot metadata like favicons and upgrade warnings
'DISPLAY_MANIFEST' => true
}
configurable_items.each do |config_name, default_value|
value = if default_value.in?([true, false])
ENV.fetch(config_name, default_value.to_s) == 'true'
else
ENV.fetch(config_name, default_value)
end
InstallationConfig.find_by!(name: config_name).update!(value: value)
puts "Updated '#{config_name}' to '#{value}'."
end
puts 'Branding configuration update finished.'
end
end