diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/source-chip/source-icon.test.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/source-chip/source-icon.test.tsx
new file mode 100644
index 00000000000..f3466aa81f0
--- /dev/null
+++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/source-chip/source-icon.test.tsx
@@ -0,0 +1,34 @@
+/** @vitest-environment jsdom */
+import { renderToStaticMarkup } from 'react-dom/server'
+import { describe, expect, it } from 'vitest'
+import { SourceIcon } from '@/app/workspace/[workspaceId]/home/components/message-content/components/source-chip/source-icon'
+
+describe('source hostname branding', () => {
+ it.each([
+ 'https://example.slack.com/archives/channel/message',
+ 'https://app.slack.com/client/team/channel',
+ 'https://SLACK.COM/help',
+ 'https://www.github.com/example/project',
+ 'https://www.gitlab.com/example/project',
+ 'https://www.notion.so/example',
+ ])('renders a local brand instead of requesting a favicon for a recognized host: %s', (url) => {
+ const container = document.createElement('div')
+ container.innerHTML = renderToStaticMarkup()
+ expect(container.querySelector('img')).toBeNull()
+ expect(container.querySelector('svg')).not.toBeNull()
+ })
+
+ it.each([
+ 'https://notslack.com/channel',
+ 'https://slack.com.example.org/channel',
+ 'https://slack.com@example.org/channel',
+ 'https://example.org/slack.com',
+ 'https://example.org/?url=https://example.slack.com',
+ ])('retains the actual destination favicon for a lookalike URL: %s', (url) => {
+ const container = document.createElement('div')
+ container.innerHTML = renderToStaticMarkup()
+ const image = container.querySelector('img')
+ expect(image).not.toBeNull()
+ expect(new URL(image!.src).searchParams.get('domain')).toBe(new URL(url).hostname)
+ })
+})
diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/source-chip/source-icon.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/source-chip/source-icon.tsx
index bf656dc37fd..d230b9f41c3 100644
--- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/source-chip/source-icon.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/source-chip/source-icon.tsx
@@ -29,6 +29,15 @@ const GOOGLE_DOCUMENT_ICON_BY_PATH: ReadonlyMap = new Map
['presentation', GoogleSlidesIcon],
])
+const BRAND_TYPE_BY_HOSTNAME: ReadonlyMap = new Map([
+ ['github.com', 'github'],
+ ['gitlab.com', 'gitlab'],
+ ['notion.so', 'notion'],
+ ['drive.google.com', 'google_drive'],
+ ['mail.google.com', 'gmail'],
+ ['calendar.google.com', 'google_calendar'],
+])
+
interface SourceIconProps {
source: SourceTagData
size?: 'default' | 'inline'
@@ -45,7 +54,12 @@ export function SourceIcon({ source, size = 'default' }: SourceIconProps) {
hostname === 'docs.google.com'
? GOOGLE_DOCUMENT_ICON_BY_PATH.get(new URL(source.url).pathname.split('/')[1] ?? '')
: undefined
- const Icon = DocumentIcon ?? ConnectorIcon
+ const hostBrandType =
+ hostname === 'slack.com' || hostname?.endsWith('.slack.com')
+ ? 'slack'
+ : BRAND_TYPE_BY_HOSTNAME.get(hostname?.replace(/^www\./, '') ?? '')
+ const HostIcon = hostBrandType ? BRAND_ICON_BY_BASE_TYPE.get(hostBrandType) : undefined
+ const Icon = DocumentIcon ?? ConnectorIcon ?? HostIcon
const className = cn('shrink-0', size === 'inline' ? 'size-[12px]' : 'size-[14px]')
if (Icon) return
if (hostname && failedHostname !== hostname) {