Claude Skills Guide

Chrome Extension Employee Recognition Tool: Build Your Own

Employee recognition plays a critical role in maintaining workplace morale and productivity. While many teams rely on email chains or Slack messages to acknowledge achievements, a dedicated Chrome extension can streamline this process directly from the browser. This guide walks you through building a custom employee recognition tool as a Chrome extension, tailored for developers and power users who want full control over their workflow.

Why Build a Chrome Extension for Recognition?

Browser-based tools integrate smoothly with daily workflows. Developers, designers, and knowledge workers spend most of their time in Chrome, making it the ideal platform for recognition tools. A custom extension can:

The flexibility of Chrome’s extension API allows you to connect to internal systems, CRMs, or communication tools that your team already uses.

Extension Architecture

A Chrome extension for employee recognition typically consists of three main components:

  1. Popup Interface — A small UI that appears when clicking the extension icon
  2. Background Service Worker — Handles communication between components and external APIs
  3. Content Scripts — Interact with specific web pages when needed

For a recognition tool, you’ll likely need to store data (user preferences, recognition history) using Chrome’s storage API, and potentially make HTTP requests to integrate with external services.

Core Implementation

Manifest V3 Configuration

Modern Chrome extensions use Manifest V3. Here’s a basic configuration for a recognition tool:

{
  "manifest_version": 3,
  "name": "Team Recognizer",
  "version": "1.0",
  "description": "Quickly recognize team members from your browser",
  "permissions": [
    "storage",
    "activeTab",
    "scripting"
  ],
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  },
  "host_permissions": [
    "https://api.yourcompany.com/*"
  ]
}

The popup provides the primary user interface. Keep it lightweight since it loads on each click:

<!DOCTYPE html>
<html>
<head>
  <style>
    body { width: 320px; padding: 16px; font-family: system-ui, sans-serif; }
    select, input, textarea { width: 100%; margin-bottom: 12px; padding: 8px; }
    button { background: #4CAF50; color: white; border: none; padding: 10px 16px; cursor: pointer; width: 100%; }
    button:hover { background: #45a049; }
    .history { margin-top: 16px; border-top: 1px solid #eee; padding-top: 12px; }
  </style>
</head>
<body>
  <h3>Recognize a Teammate</h3>
  <select id="recipient">
    <option value="">Select recipient...</option>
    <option value="alice">Alice Chen</option>
    <option value="bob">Bob Martinez</option>
    <option value="carol">Carol Johnson</option>
  </select>
  <select id="recognitionType">
    <option value="great-work">Great Work</option>
    <option value="team-player">Team Player</option>
    <option value="innovation">Innovation</option>
    <option value="above-and-beyond">Above and Beyond</option>
  </select>
  <textarea id="message" rows="3" placeholder="Describe the achievement..."></textarea>
  <button id="sendBtn">Send Recognition</button>
  <div class="history" id="history"></div>
  <script src="popup.js"></script>
</body>
</html>

Handling Recognition Logic

The popup JavaScript handles form submission and storage:

document.getElementById('sendBtn').addEventListener('click', async () => {
  const recipient = document.getElementById('recipient').value;
  const type = document.getElementById('recognitionType').value;
  const message = document.getElementById('message').value;
  
  if (!recipient || !message) {
    alert('Please select a recipient and write a message');
    return;
  }
  
  const recognition = {
    id: Date.now(),
    recipient,
    type,
    message,
    timestamp: new Date().toISOString(),
    sender: 'current-user'
  };
  
  // Store locally
  const stored = await chrome.storage.local.get('recognitions') || { recognitions: [] };
  stored.recognitions.unshift(recognition);
  await chrome.storage.local.set({ recognitions: stored.recognitions.slice(0, 50) });
  
  // Optionally send to external API
  await sendToExternalAPI(recognition);
  
  updateHistory();
  document.getElementById('message').value = '';
});

async function sendToExternalAPI(recognition) {
  try {
    await fetch('https://api.yourcompany.com/recognitions', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(recognition)
    });
  } catch (error) {
    console.log('API unavailable, stored locally');
  }
}

async function updateHistory() {
  const { recognitions } = await chrome.storage.local.get('recognitions') || { recognitions: [] };
  const historyEl = document.getElementById('history');
  historyEl.innerHTML = recognitions.slice(0, 5).map(r => 
    `<div style="font-size: 12px; margin-bottom: 8px;">
      <strong>${r.recipient}</strong>: ${r.message.substring(0, 50)}...
    </div>`
  ).join('');
}

updateHistory();

Advanced Integrations

Integrating with Slack

Many teams use Slack for daily communication. You can integrate your recognition tool with Slack’s web API:

async function notifySlack(recognition) {
  const webhookUrl = 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL';
  
  const payload = {
    text: `🎉 *${recognition.recipient}* just got recognized!`,
    blocks: [
      {
        type: 'section',
        text: {
          type: 'mrkdwn',
          text: `*${recognition.type.replace('-', ' ').toUpperCase()}* awarded to *${recognition.recipient}*`
        }
      },
      {
        type: 'section',
        text: {
          type: 'mrkdwn',
          text: recognition.message
        }
      }
    ]
  };
  
  await fetch(webhookUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });
}

Context-Aware Recognition

For power users, consider adding context-awareness. Content scripts can detect when someone completes a significant action in web-based tools like GitHub, Jira, or project management platforms:

// content-script.js - Run on specific domains
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'getContext') {
    // Extract relevant context from the current page
    const context = {
      url: window.location.href,
      title: document.title,
      // Add domain-specific extraction logic
      ...extractDomainContext(window.location.hostname)
    };
    sendResponse(context);
  }
});

function extractDomainContext(hostname) {
  if (hostname.includes('github.com')) {
    const prElement = document.querySelector('.gh-header-title');
    return { type: 'pull-request', title: prElement?.textContent?.trim() };
  }
  return {};
}

Storing Data Securely

For extensions that handle sensitive recognition data, use encrypted storage:

import { encrypt, decrypt } from './crypto-utils.js';

const SECURE_STORAGE_KEY = 'secure_recognitions';

export async function storeSecureRecognition(recognition) {
  const encrypted = await encrypt(JSON.stringify(recognition));
  await chrome.storage.session.set({ [SECURE_STORAGE_KEY]: encrypted });
}

export async function getSecureRecognitions() {
  const { [SECURE_STORAGE_KEY]: encrypted } = await chrome.storage.session.get(SECURE_STORAGE_KEY);
  if (!encrypted) return [];
  const decrypted = await decrypt(encrypted);
  return JSON.parse(decrypted);
}

Deployment and Distribution

Once your extension is ready, you have several distribution options:

  1. Chrome Web Store — Submit for public listing after paying a developer fee
  2. Internal Distribution — Load unpacked for team testing, or use enterprise management
  3. Self-Hosted — Host the extension files and have users load them manually

For internal team tools, loading unpacked extensions or using Chrome Enterprise policies keeps distribution simple without store review requirements.

Summary

Building a Chrome extension for employee recognition gives your team a dedicated tool that fits naturally into daily browser workflows. Start with the basic popup interface, then expand with Slack integration, context-aware recognition, and secure storage as needed. The Chrome extension API provides everything you need to create a powerful, customized recognition system that integrates with your existing tools.

The key is starting simple—capture recognitions, store them locally, and gradually add integrations that matter most to your team.

Built by theluckystrike — More at zovo.one