Claude Skills Guide

Chrome Extension TikTok Analytics Tracker: A Developer’s Guide

Building a Chrome extension to track TikTok analytics opens up powerful possibilities for content creators, marketers, and developers who want to automate data collection from the platform. While TikTok provides native analytics for Pro accounts, custom extensions let you aggregate data across multiple accounts, build custom visualizations, and create alerting systems that go beyond what the platform offers.

This guide walks through the architecture, implementation patterns, and practical considerations for building a TikTok analytics tracker as a Chrome extension.

Understanding the Architecture

A Chrome extension for TikTok analytics typically consists of three main components:

  1. Content Script - Runs in the context of TikTok’s web pages, extracting data from the DOM
  2. Background Service Worker - Handles long-running tasks, storage, and cross-tab communication
  3. Popup or Options Page - Provides the user interface for viewing and configuring the extension

The content script is where the real work happens. TikTok’s web application loads analytics data dynamically, so you need to observe DOM changes and extract metrics as they become available.

Extracting TikTok Analytics Data

TikTok’s analytics page exposes data through the page’s JavaScript environment. You can access this data by injecting scripts that interact with the page’s state. Here’s a pattern for extracting video performance metrics:

// content-script.js - Extract video analytics from TikTok Pro analytics page
(function() {
  'use strict';

  const ANALYTICS_SELECTORS = {
    videoContainer: '[data-e2e="video-list-item"]',
    viewCount: '[data-e2e="video-views"]',
    likeCount: '[data-e2e="video-likes"]',
    commentCount: '[data-e2e="video-comments"]',
    shareCount: '[data-e2e="video-shares"]',
    uploadDate: '[data-e2e="video-upload-time"]'
  };

  function extractVideoMetrics(videoElement) {
    return {
      id: videoElement.dataset.videoId || extractVideoId(videoElement),
      views: parseMetric(videoElement.querySelector(ANALYTICS_SELECTORS.viewCount)?.textContent),
      likes: parseMetric(videoElement.querySelector(ANALYTICS_SELECTORS.likeCount)?.textContent),
      comments: parseMetric(videoElement.querySelector(ANALYTICS_SELECTORS.commentCount)?.textContent),
      shares: parseMetric(videoElement.querySelector(ANALYTICS_SELECTORS.shareCount)?.textContent),
      timestamp: videoElement.querySelector(ANALYTICS_SELECTORS.uploadDate)?.textContent
    };
  }

  function parseMetric(text) {
    if (!text) return 0;
    const cleaned = text.replace(/[,KMB]/g, '');
    const multiplier = text.includes('K') ? 1000 : 
                       text.includes('M') ? 1000000 : 
                       text.includes('B') ? 1000000000 : 1;
    return parseFloat(cleaned) * multiplier;
  }

  function extractVideoId(element) {
    const link = element.querySelector('a[href*="/video/"]');
    return link ? link.href.match(/\/video\/(\d+)/)?.[1] : null;
  }

  // Set up MutationObserver to catch dynamically loaded content
  const observer = new MutationObserver((mutations) => {
    const videos = document.querySelectorAll(ANALYTICS_SELECTORS.videoContainer);
    if (videos.length > 0) {
      const metrics = Array.from(videos).map(extractVideoMetrics);
      chrome.runtime.sendMessage({
        type: 'VIDEO_METRICS_UPDATE',
        data: metrics
      });
    }
  });

  observer.observe(document.body, {
    childList: true,
    subtree: true
  });
})();

This content script uses a MutationObserver to detect when TikTok loads new video elements, then extracts metrics and sends them to the background script for storage.

Background Service Worker Architecture

The background service worker acts as the central hub for your extension. It receives data from content scripts, stores it using Chrome’s storage API, and handles communication between different parts of your extension.

// background.js - Service worker for data aggregation and storage
const STORAGE_KEY = 'tiktok_analytics_cache';

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'VIDEO_METRICS_UPDATE') {
    handleVideoMetricsUpdate(message.data, sender.tab?.url);
    return true;
  }
  
  if (message.type === 'GET_ANALYTICS') {
    getAggregatedAnalytics().then(sendResponse);
    return true;
  }
});

async function handleVideoMetricsUpdate(videos, sourceUrl) {
  const existing = await chrome.storage.local.get(STORAGE_KEY);
  const cache = existing[STORAGE_KEY] || { videos: [], lastUpdated: null };
  
  const videoMap = new Map(cache.videos.map(v => [v.id, v]));
  
  videos.forEach(video => {
    const existingVideo = videoMap.get(video.id);
    if (existingVideo) {
      // Update existing video with latest metrics
      videoMap.set(video.id, { ...existingVideo, ...video, lastSeen: Date.now() });
    } else {
      videoMap.set(video.id, { ...video, firstSeen: Date.now(), lastSeen: Date.now() });
    }
  });
  
  cache.videos = Array.from(videoMap.values());
  cache.lastUpdated = Date.now();
  
  await chrome.storage.local.set({ [STORAGE_KEY]: cache });
}

async function getAggregatedAnalytics() {
  const existing = await chrome.storage.local.get(STORAGE_KEY);
  const cache = existing[STORAGE_KEY] || { videos: [] };
  
  const videos = cache.videos;
  
  return {
    totalVideos: videos.length,
    totalViews: videos.reduce((sum, v) => sum + (v.views || 0), 0),
    totalLikes: videos.reduce((sum, v) => sum + (v.likes || 0), 0),
    averageEngagementRate: calculateEngagementRate(videos),
    topPerformingVideos: getTopVideos(videos, 5),
    lastUpdated: cache.lastUpdated
  };
}

function calculateEngagementRate(videos) {
  if (videos.length === 0) return 0;
  const totalEngagement = videos.reduce((sum, v) => 
    sum + (v.likes || 0) + (v.comments || 0) + (v.shares || 0), 0);
  const totalViews = videos.reduce((sum, v) => sum + (v.views || 0), 0);
  return totalViews > 0 ? (totalEngagement / totalViews) * 100 : 0;
}

function getTopVideos(videos, count) {
  return [...videos]
    .sort((a, b) => (b.views || 0) - (a.views || 0))
    .slice(0, count);
}

This background worker maintains a local cache of all video metrics, computes aggregate statistics, and provides an API for the popup interface to query the data.

Building the Popup Interface

The popup provides a quick view of your analytics without needing to navigate to a full dashboard. Here’s a practical implementation:

<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
  <style>
    body { width: 320px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
    .stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 12px; }
    .stat-card { background: #f5f5f5; border-radius: 8px; padding: 12px; text-align: center; }
    .stat-value { font-size: 20px; font-weight: 600; color: #fe2c55; }
    .stat-label { font-size: 11px; color: #666; margin-top: 4px; }
    .video-list { max-height: 300px; overflow-y: auto; }
    .video-item { padding: 8px 12px; border-bottom: 1px solid #eee; }
    .video-item:last-child { border-bottom: none; }
    h3 { margin: 12px; font-size: 14px; color: #333; }
  </style>
</head>
<body>
  <h3>TikTok Analytics Overview</h3>
  <div class="stat-grid">
    <div class="stat-card">
      <div class="stat-value" id="totalViews">-</div>
      <div class="stat-label">Total Views</div>
    </div>
    <div class="stat-card">
      <div class="stat-value" id="totalVideos">-</div>
      <div class="stat-label">Videos Tracked</div>
    </div>
    <div class="stat-card">
      <div class="stat-value" id="engagementRate">-</div>
      <div class="stat-label">Engagement %</div>
    </div>
    <div class="stat-card">
      <div class="stat-value" id="totalLikes">-</div>
      <div class="stat-label">Total Likes</div>
    </div>
  </div>
  
  <h3>Top Performing Videos</h3>
  <div class="video-list" id="topVideos"></div>
  
  <script src="popup.js"></script>
</body>
</html>
// popup.js
document.addEventListener('DOMContentLoaded', async () => {
  const analytics = await chrome.runtime.sendMessage({ type: 'GET_ANALYTICS' });
  
  if (analytics) {
    document.getElementById('totalViews').textContent = formatNumber(analytics.totalViews);
    document.getElementById('totalVideos').textContent = analytics.totalVideos;
    document.getElementById('engagementRate').textContent = analytics.averageEngagementRate.toFixed(1) + '%';
    document.getElementById('totalLikes').textContent = formatNumber(analytics.totalLikes);
    
    const videoList = document.getElementById('topVideos');
    analytics.topPerformingVideos.forEach(video => {
      const item = document.createElement('div');
      item.className = 'video-item';
      item.textContent = `${formatNumber(video.views)} views - ${video.likes} likes`;
      videoList.appendChild(item);
    });
  }
});

function formatNumber(num) {
  if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
  if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
  return num.toString();
}

Important Implementation Considerations

When building TikTok analytics extensions, several practical challenges require attention:

Selector Stability: TikTok frequently updates their DOM structure. Use multiple selector strategies and implement fallback logic to handle selector changes gracefully. Data attributes like data-e2e are generally more stable than class names.

Rate Limiting: Implement throttling to avoid overwhelming TikTok’s servers or triggering anti-bot measures. A reasonable approach is to poll for updates every 30-60 seconds when the analytics page is active.

Authentication State: TikTok requires authentication to access analytics. Your extension needs to handle session expiration gracefully and prompt users to log in if needed.

Data Persistence: Chrome’s chrome.storage.local provides 5MB of storage by default. For larger datasets, consider using chrome.storage.sync with quotas in mind, or implement data export functionality.

Cross-Account Tracking: If you manage multiple TikTok accounts, structure your data storage to separate metrics by account. Include account identification in your data model from the start.

Extending Functionality

Beyond basic metrics, you can enhance your extension with several advanced features:

Building a TikTok analytics Chrome extension gives you complete control over how you collect, analyze, and visualize your content performance data. The patterns shown here provide a solid foundation that you can adapt based on your specific requirements and the metrics that matter most for your content strategy.

Built by theluckystrike — More at zovo.one