Instagram's native insights are... okay. But if you manage multiple accounts or want to track competitors, they're useless. You can't export data, you can't track other people's engagement rates, and you definitely can't build custom reports.
In this tutorial, we're going to build a Custom Instagram Reels Dashboard that lets you:
- Track any public Instagram account (no login required).
- Visualize views, likes, and comments over time.
- Calculate "Viral Score" for every Reel.
We'll use Next.js 14, Tailwind CSS, Recharts, and the SociaVault API to fetch the data.
The Stack
- Framework: Next.js 14 (App Router)
- Styling: Tailwind CSS
- Charts: Recharts
- Data: SociaVault API (Instagram Scraper)
Step 1: Project Setup
First, create a new Next.js project:
npx create-next-app@latest instagram-dashboard
cd instagram-dashboard
npm install recharts lucide-react
Step 2: The API Client
We need a way to fetch data from Instagram. Since Instagram's official Graph API is a nightmare of permissions and approvals, we'll use SociaVault's API, which works out of the box for public data.
Create lib/api.ts:
const API_KEY = process.env.SOCIAVAULT_API_KEY;
const BASE_URL = "https://api.sociavault.com/api/v1";
export async function getProfileReels(username: string) {
const response = await fetch(
`${BASE_URL}/instagram/user/${username}/reels?limit=50`,
{
headers: {
"x-api-key": API_KEY!,
"Content-Type": "application/json",
},
next: { revalidate: 3600 }, // Cache for 1 hour
}
);
if (!response.ok) throw new Error("Failed to fetch reels");
return response.json();
}
Step 3: Calculating Metrics
Raw data is boring. We want insights. Let's create a utility to calculate engagement rates and viral scores.
Create lib/metrics.ts:
export function calculateMetrics(reels: any[]) {
return reels.map((reel) => {
const engagement = reel.like_count + reel.comment_count;
const engagementRate = (engagement / reel.view_count) * 100;
// Simple viral score: High views + High engagement
const viralScore = (reel.view_count / 1000) + (engagementRate * 10);
return {
...reel,
engagement,
engagementRate: engagementRate.toFixed(2),
viralScore: Math.round(viralScore),
};
});
}
Step 4: Building the Dashboard Component
Now for the UI. We'll create a dashboard that shows a performance chart and a list of top Reels.
components/Dashboard.tsx:
"use client";
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';
import { Play, Heart, MessageCircle } from 'lucide-react';
export default function Dashboard({ data }: { data: any[] }) {
return (
<div className="p-6 space-y-8">
{/* Performance Chart */}
<div className="bg-white p-6 rounded-xl shadow-sm border">
<h2 className="text-lg font-semibold mb-4">Views vs. Engagement</h2>
<div className="h-[300px]">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={data.slice(0, 10).reverse()}>
<XAxis dataKey="taken_at" tickFormatter={(val) => new Date(val).toLocaleDateString()} />
<YAxis />
<Tooltip />
<Bar dataKey="view_count" fill="#3b82f6" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
</div>
</div>
{/* Top Reels Grid */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{data.map((reel) => (
<div key={reel.id} className="bg-white p-4 rounded-xl border hover:shadow-md transition">
<div className="relative aspect-[9/16] bg-gray-100 rounded-lg mb-3 overflow-hidden">
<img src={reel.thumbnail_url} alt="Reel cover" className="object-cover w-full h-full" />
<div className="absolute bottom-2 right-2 bg-black/50 text-white px-2 py-1 rounded text-xs flex items-center">
<Play className="w-3 h-3 mr-1" />
{(reel.view_count / 1000).toFixed(1)}k
</div>
</div>
<div className="flex justify-between text-sm text-gray-600">
<span className="flex items-center">
<Heart className="w-4 h-4 mr-1" /> {reel.like_count}
</span>
<span className="flex items-center">
<MessageCircle className="w-4 h-4 mr-1" /> {reel.comment_count}
</span>
<span className="font-medium text-blue-600">
{reel.engagementRate}% ER
</span>
</div>
</div>
))}
</div>
</div>
);
}
Step 5: Putting It Together
Finally, let's connect it all in our page.
app/dashboard/[username]/page.tsx:
import { getProfileReels } from "@/lib/api";
import { calculateMetrics } from "@/lib/metrics";
import Dashboard from "@/components/Dashboard";
export default async function Page({ params }: { params: { username: string } }) {
const rawData = await getProfileReels(params.username);
const metrics = calculateMetrics(rawData.items);
return (
<main className="min-h-screen bg-gray-50">
<div className="max-w-7xl mx-auto py-12">
<h1 className="text-3xl font-bold px-6 mb-2">@{params.username}</h1>
<p className="text-gray-500 px-6 mb-8">Reels Performance Analytics</p>
<Dashboard data={metrics} />
</div>
</main>
);
}
Conclusion
In about 15 minutes, we built a tool that gives us more insight than Instagram's native app. You can extend this by:
- Adding a "Download CSV" button.
- Tracking follower growth over time.
- Comparing two accounts side-by-side.
The best part? You own the data.
Resources:
Top comments (0)