diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 5b18d3030..2a3ce59b3 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -10,6 +10,7 @@ class DashboardController < ActionController::Base
TERMS_URL
BRAND_URL
BRAND_NAME
+ BRAND_COLOR
PRIVACY_URL
DISPLAY_MANIFEST
CREATE_NEW_ACCOUNT_FROM_DASHBOARD
diff --git a/app/controllers/manifest_controller.rb b/app/controllers/manifest_controller.rb
new file mode 100644
index 000000000..31115a0c9
--- /dev/null
+++ b/app/controllers/manifest_controller.rb
@@ -0,0 +1,35 @@
+class ManifestController < ApplicationController
+ PNG_MIME = 'image/png'.freeze
+ SVG_MIME = 'image/svg+xml'.freeze
+
+ def show
+ config = GlobalConfig.get('INSTALLATION_NAME', 'LOGO_THUMBNAIL', 'BRAND_COLOR')
+ installation_name = config['INSTALLATION_NAME'].presence || 'Chatwoot'
+ logo = config['LOGO_THUMBNAIL'].presence || '/brand-assets/logo_thumbnail.svg'
+ brand_color = config['BRAND_COLOR'].presence || '#1f93ff'
+ icon_type = svg?(logo) ? SVG_MIME : PNG_MIME
+
+ expires_in 1.hour, public: true
+ render json: {
+ name: installation_name,
+ short_name: installation_name,
+ id: '/',
+ start_url: '/',
+ display: 'standalone',
+ background_color: brand_color,
+ theme_color: brand_color,
+ icons: [
+ { src: logo, sizes: '192x192', type: icon_type, purpose: 'any maskable' },
+ { src: logo, sizes: '512x512', type: icon_type, purpose: 'any maskable' }
+ ]
+ }, content_type: 'application/manifest+json'
+ end
+
+ private
+
+ def svg?(url)
+ File.extname(URI.parse(url).path).casecmp('.svg').zero?
+ rescue URI::InvalidURIError
+ false
+ end
+end
diff --git a/app/views/layouts/vueapp.html.erb b/app/views/layouts/vueapp.html.erb
index 12a3bcd51..29ccad9b0 100644
--- a/app/views/layouts/vueapp.html.erb
+++ b/app/views/layouts/vueapp.html.erb
@@ -6,10 +6,15 @@
+
+
+
+
+
+
<% if @global_config['DISPLAY_MANIFEST'] %>
-
+
-
<% if ENV['IOS_APP_IDENTIFIER'].present? %>
'>
@@ -27,7 +32,6 @@
-
<% end %>
<%= csrf_meta_tags %>
diff --git a/config/installation_config.yml b/config/installation_config.yml
index 884dd2e58..72bb866c0 100644
--- a/config/installation_config.yml
+++ b/config/installation_config.yml
@@ -42,6 +42,10 @@
value: 'Chatwoot'
display_title: 'Brand Name'
description: 'The name that would be used in emails and the widget'
+- name: BRAND_COLOR
+ value: '#1f93ff'
+ display_title: 'Brand Color'
+ description: 'Hex color used for PWA theme/tile color (example: #1f93ff). For reliable Android PWA install prompts, pair with a 192x192 and 512x512 PNG logo thumbnail.'
- name: TERMS_URL
value: 'https://www.chatwoot.com/terms-of-service'
display_title: 'Terms URL'
diff --git a/config/routes.rb b/config/routes.rb
index e4d1f5e0b..19dc35708 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -669,6 +669,7 @@ Rails.application.routes.draw do
get 'notion/callback', to: 'notion/callbacks#show'
# ----------------------------------------------------------------------
# Routes for external service verifications
+ get '/manifest.json' => 'manifest#show'
get '.well-known/assetlinks.json' => 'android_app#assetlinks'
get '.well-known/apple-app-site-association' => 'apple_app#site_association'
get '.well-known/microsoft-identity-association.json' => 'microsoft#identity_association'
diff --git a/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb b/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb
index f91f12708..3ca637ac7 100644
--- a/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb
+++ b/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb
@@ -24,6 +24,7 @@ module Enterprise::SuperAdmin::AppConfigsController
LOGO
LOGO_DARK
BRAND_NAME
+ BRAND_COLOR
INSTALLATION_NAME
BRAND_URL
WIDGET_BRAND_URL
diff --git a/public/manifest.json b/public/manifest.json
deleted file mode 100644
index 9f4bfa937..000000000
--- a/public/manifest.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "name": "Chatwoot",
- "short_name": "Chatwoot",
- "icons": [{
- "src": "\/android-icon-36x36.png",
- "sizes": "36x36",
- "type": "image\/png",
- "density": "0.75"
- },
- {
- "src": "\/android-icon-48x48.png",
- "sizes": "48x48",
- "type": "image\/png",
- "density": "1.0"
- },
- {
- "src": "\/android-icon-72x72.png",
- "sizes": "72x72",
- "type": "image\/png",
- "density": "1.5"
- },
- {
- "src": "\/android-icon-96x96.png",
- "sizes": "96x96",
- "type": "image\/png",
- "density": "2.0"
- },
- {
- "src": "\/android-icon-144x144.png",
- "sizes": "144x144",
- "type": "image\/png",
- "density": "3.0"
- },
- {
- "src": "\/android-icon-192x192.png",
- "sizes": "192x192",
- "type": "image\/png",
- "density": "4.0"
- }],
- "start_url": "/",
- "display": "standalone",
- "background_color": "#1f93ff",
- "theme_color": "#1f93fe"
-}