feat: add AI traffic source identification
Display proper brand icons and names for AI referrers (ChatGPT, Perplexity, Claude, Gemini, Copilot, DeepSeek, Grok, Meta AI, You.com, Phind) in Top Referrers panel.
This commit is contained in:
@@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
|
||||
## [0.13.0-alpha] - 2026-03-02
|
||||
|
||||
### Added
|
||||
|
||||
- **AI traffic source identification.** Pulse now automatically recognizes visitors coming from AI tools — ChatGPT, Perplexity, Claude, Gemini, Copilot, DeepSeek, Grok, Meta AI, You.com, and Phind. These sources appear in your Top Referrers with proper brand icons and display names instead of raw domain URLs. If someone clicks a link in an AI chat to visit your site, you'll see exactly which AI tool sent them.
|
||||
|
||||
### Improved
|
||||
|
||||
- **Cleaner internal API code.** The analytics data-fetching layer has been streamlined — 13 near-identical endpoint functions were consolidated using a shared pattern, cutting roughly half the code while keeping every feature working exactly as before. This makes it easier to add new analytics endpoints in the future and reduces the chance of inconsistencies between them.
|
||||
|
||||
@@ -30,7 +30,8 @@ import {
|
||||
FaGlobe
|
||||
} from 'react-icons/fa'
|
||||
import { FaXTwitter } from 'react-icons/fa6'
|
||||
import { SiBrave } from 'react-icons/si'
|
||||
import { SiBrave, SiOpenai, SiPerplexity, SiAnthropic, SiGooglegemini } from 'react-icons/si'
|
||||
import { RiRobot2Fill } from 'react-icons/ri'
|
||||
import { MdDeviceUnknown, MdSmartphone, MdTabletMac, MdDesktopWindows } from 'react-icons/md'
|
||||
|
||||
export function getBrowserIcon(browserName: string) {
|
||||
@@ -79,6 +80,16 @@ export function getReferrerIcon(referrerName: string) {
|
||||
if (lower.includes('github')) return <FaGithub className="text-neutral-800 dark:text-neutral-200" />
|
||||
if (lower.includes('youtube')) return <FaYoutube className="text-red-600" />
|
||||
if (lower.includes('reddit')) return <FaReddit className="text-orange-600" />
|
||||
// AI assistants and search tools
|
||||
if (lower.includes('chatgpt') || lower.includes('openai')) return <SiOpenai className="text-neutral-800 dark:text-neutral-200" />
|
||||
if (lower.includes('perplexity')) return <SiPerplexity className="text-teal-600" />
|
||||
if (lower.includes('claude') || lower.includes('anthropic')) return <SiAnthropic className="text-orange-500" />
|
||||
if (lower.includes('gemini')) return <SiGooglegemini className="text-blue-500" />
|
||||
if (lower.includes('copilot')) return <FaGlobe className="text-blue-500" />
|
||||
if (lower.includes('deepseek')) return <RiRobot2Fill className="text-blue-600" />
|
||||
if (lower.includes('grok') || lower.includes('x.ai')) return <FaXTwitter className="text-neutral-800 dark:text-neutral-200" />
|
||||
if (lower.includes('phind')) return <RiRobot2Fill className="text-purple-600" />
|
||||
if (lower.includes('you.com')) return <RiRobot2Fill className="text-indigo-600" />
|
||||
|
||||
// Try to use a generic globe or maybe check if it is a URL
|
||||
return <FaGlobe className="text-neutral-400" />
|
||||
@@ -111,6 +122,17 @@ const REFERRER_DISPLAY_OVERRIDES: Record<string, string> = {
|
||||
quora: 'Quora',
|
||||
't.co': 'X',
|
||||
'x.com': 'X',
|
||||
// AI assistants and search tools
|
||||
openai: 'ChatGPT',
|
||||
perplexity: 'Perplexity',
|
||||
claude: 'Claude',
|
||||
anthropic: 'Claude',
|
||||
gemini: 'Gemini',
|
||||
copilot: 'Copilot',
|
||||
deepseek: 'DeepSeek',
|
||||
grok: 'Grok',
|
||||
'you': 'You.com',
|
||||
phind: 'Phind',
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user