DEV Community

Cover image for Build a Real-time TikTok Analytics Dashboard with Next.js
Olamide Olaniyan
Olamide Olaniyan

Posted on

Build a Real-time TikTok Analytics Dashboard with Next.js

Stop scraping. Start building.

In this tutorial, we're going to build a simple but powerful dashboard that tracks TikTok user stats in real-time.

We'll use:

  • Next.js (App Router)
  • Tailwind CSS (Styling)
  • SociaVault API (Data fetching)
  • Recharts (Visualization)

By the end, you'll have a dashboard that takes a username (e.g., khaby.lame) and displays their follower growth, engagement rates, and top videos.


Prerequisites

  1. Node.js installed.
  2. A SociaVault API Key (Get a free one).

Step 1: Setup the Project

npx create-next-app@latest tiktok-dashboard
cd tiktok-dashboard
npm install recharts lucide-react axios
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the API Client

Create lib/api.ts. We'll use this to fetch data from SociaVault.

import axios from 'axios';

const API_KEY = process.env.NEXT_PUBLIC_SOCIAVAULT_KEY;
const BASE_URL = 'https://api.sociavault.com/v1/scrape/tiktok';

export const getProfile = async (handle: string) => {
  const response = await axios.get(`${BASE_URL}/profile`, {
    headers: { 'x-api-key': API_KEY },
    params: { handle }
  });
  return response.data.data;
};

export const getVideos = async (handle: string) => {
  const response = await axios.get(`${BASE_URL}/videos`, {
    headers: { 'x-api-key': API_KEY },
    params: { handle, amount: 10 }
  });
  return response.data.data.videos;
};
Enter fullscreen mode Exit fullscreen mode

Step 3: Build the Dashboard Component

In app/page.tsx, we'll create a simple search form and display the results.

'use client';

import { useState } from 'react';
import { getProfile, getVideos } from '@/lib/api';
import { Search, Users, Heart, Play } from 'lucide-react';

export default function Dashboard() {
  const [handle, setHandle] = useState('');
  const [data, setData] = useState<any>(null);
  const [loading, setLoading] = useState(false);

  const handleSearch = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    try {
      const [profile, videos] = await Promise.all([
        getProfile(handle),
        getVideos(handle)
      ]);
      setData({ profile, videos });
    } catch (err) {
      alert('Failed to fetch data');
    }
    setLoading(false);
  };

  return (
    <div className="min-h-screen bg-gray-900 text-white p-8">
      <div className="max-w-4xl mx-auto">
        <h1 className="text-3xl font-bold mb-8">TikTok Analytics 📊</h1>

        {/* Search Form */}
        <form onSubmit={handleSearch} className="flex gap-4 mb-12">
          <input
            type="text"
            value={handle}
            onChange={(e) => setHandle(e.target.value)}
            placeholder="Enter username (e.g. khaby.lame)"
            className="flex-1 bg-gray-800 border border-gray-700 rounded-lg px-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-500"
          />
          <button 
            disabled={loading}
            className="bg-blue-600 hover:bg-blue-700 px-6 py-3 rounded-lg font-medium transition-colors"
          >
            {loading ? 'Loading...' : 'Analyze'}
          </button>
        </form>

        {data && (
          <div className="space-y-8">
            {/* Stats Grid */}
            <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
              <StatCard 
                icon={<Users className="text-blue-400" />}
                label="Followers"
                value={data.profile.stats.followerCount}
              />
              <StatCard 
                icon={<Heart className="text-red-400" />}
                label="Total Likes"
                value={data.profile.stats.heartCount}
              />
              <StatCard 
                icon={<Play className="text-green-400" />}
                label="Total Videos"
                value={data.profile.stats.videoCount}
              />
            </div>

            {/* Recent Videos */}
            <h2 className="text-xl font-semibold">Recent Videos</h2>
            <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
              {data.videos.map((video: any) => (
                <div key={video.id} className="bg-gray-800 rounded-xl p-4 flex gap-4">
                  <img 
                    src={video.cover} 
                    alt="Cover" 
                    className="w-24 h-32 object-cover rounded-lg"
                  />
                  <div>
                    <p className="text-sm text-gray-400 mb-2">
                      {new Date(video.createTime * 1000).toLocaleDateString()}
                    </p>
                    <p className="line-clamp-2 mb-4">{video.desc}</p>
                    <div className="flex gap-4 text-sm text-gray-300">
                      <span className="flex items-center gap-1">
                        <Play size={14} /> {video.stats.playCount}
                      </span>
                      <span className="flex items-center gap-1">
                        <Heart size={14} /> {video.stats.diggCount}
                      </span>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function StatCard({ icon, label, value }: any) {
  return (
    <div className="bg-gray-800 p-6 rounded-xl border border-gray-700">
      <div className="flex items-center gap-3 mb-2">
        {icon}
        <span className="text-gray-400">{label}</span>
      </div>
      <div className="text-2xl font-bold">
        {new Intl.NumberFormat('en-US', { notation: "compact" }).format(value)}
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Why this is better than scraping

If you tried to build this by scraping TikTok directly with Puppeteer:

  1. You'd need a backend server (Next.js API routes have timeouts).
  2. You'd need to manage proxies.
  3. You'd get blocked after 5 requests.

By using SociaVault, we offloaded the entire data collection layer. Our Next.js app is just a UI shell.

Next Steps

You can extend this dashboard to:

  1. Calculate engagement rates (Likes / Views).
  2. Track follower growth over time (store data in Supabase).
  3. Compare two creators side-by-side.

Grab your API key here: SociaVault.com

nextjs #react #webdev #tutorial #api

Top comments (0)