From d60ef29835a60d48cba1770fd54fd51ce251782c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 17 Nov 2025 15:01:38 +0000
Subject: [PATCH 1/3] Initial plan
From 7b63e8feac369a058e2db003b2d35423607bc892 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 17 Nov 2025 15:10:03 +0000
Subject: [PATCH 2/3] Add Apify Instagram Profile Scraper integration
Co-authored-by: lukas-bekr <224167845+lukas-bekr@users.noreply.github.com>
---
social-demo/.env.example | 3 +
social-demo/README.md | 169 ++++++++++++++++++
.../app/api/instagram/[username]/route.ts | 86 +++++++++
social-demo/app/page.tsx | 26 ++-
social-demo/lib/apify-transform.ts | 116 ++++++++++++
social-demo/package.json | 1 +
6 files changed, 396 insertions(+), 5 deletions(-)
create mode 100644 social-demo/.env.example
create mode 100644 social-demo/README.md
create mode 100644 social-demo/app/api/instagram/[username]/route.ts
create mode 100644 social-demo/lib/apify-transform.ts
diff --git a/social-demo/.env.example b/social-demo/.env.example
new file mode 100644
index 0000000..07da8d5
--- /dev/null
+++ b/social-demo/.env.example
@@ -0,0 +1,3 @@
+# Apify API Token
+# Get your token from https://console.apify.com/account/integrations
+APIFY_TOKEN=your_apify_token_here
diff --git a/social-demo/README.md b/social-demo/README.md
new file mode 100644
index 0000000..d072c98
--- /dev/null
+++ b/social-demo/README.md
@@ -0,0 +1,169 @@
+# Instagram Analytics Demo
+
+A Next.js demo application that analyzes Instagram profiles using the Apify Instagram Profile Scraper.
+
+## Features
+
+- 📊 Real-time Instagram profile analysis
+- 📈 Engagement metrics and charts
+- #️⃣ Top hashtags visualization
+- 📸 Recent posts grid
+- 🎨 Modern UI with Tailwind CSS and shadcn/ui
+
+## Setup
+
+### Prerequisites
+
+- Node.js 18+ installed
+- An Apify account with an API token
+
+### 1. Get Your Apify Token
+
+1. Sign up for a free account at [https://console.apify.com](https://console.apify.com)
+2. Navigate to **Settings → Integrations**
+3. Copy your API token
+
+### 2. Install Dependencies
+
+```bash
+npm install
+```
+
+### 3. Configure Environment Variables
+
+Create a `.env.local` file in the root directory:
+
+```bash
+cp .env.example .env.local
+```
+
+Edit `.env.local` and add your Apify token:
+
+```
+APIFY_TOKEN=your_actual_apify_token_here
+```
+
+**Important:** Never commit your `.env.local` file to version control.
+
+### 4. Run the Development Server
+
+```bash
+npm run dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) in your browser.
+
+## Usage
+
+1. Enter an Instagram username or profile URL in the search bar
+2. Click "Analyze Profile"
+3. View detailed analytics including:
+ - Profile information (followers, following, posts count)
+ - Engagement metrics
+ - Recent posts with engagement rates
+ - Top hashtags
+ - Engagement history chart
+
+## How It Works
+
+### Architecture
+
+```
+User Input → SearchBar → API Route → Apify Actor → Transform → Display
+```
+
+1. **User enters a username** in the search bar
+2. **Next.js API route** (`/api/instagram/[username]`) receives the request
+3. **Apify Client** calls the Instagram Profile Scraper Actor
+4. **Data transformation** maps Apify's output to our TypeScript types
+5. **UI components** display the transformed data
+
+### Key Files
+
+- `app/page.tsx` - Main page component with search handling
+- `app/api/instagram/[username]/route.ts` - API route that calls Apify
+- `lib/apify-transform.ts` - Transforms Apify data to our format
+- `lib/types.ts` - TypeScript interfaces for Instagram data
+- `components/` - Reusable UI components
+
+## Apify Integration
+
+This app uses the [Instagram Profile Scraper](https://apify.com/apify/instagram-profile-scraper) Actor, which:
+
+- Extracts public profile data (no private accounts)
+- Returns profile info, metrics, and recent posts
+- Uses a pay-per-result pricing model
+- Includes ~2,000 free results with the $5 starter credit
+
+### Cost Considerations
+
+- Free tier: $2.60 per 1,000 profiles (~2,000 free profiles)
+- Paid plans: Discounted rates starting at $2.30/1,000
+
+## Development
+
+### Build
+
+```bash
+npm run build
+```
+
+### Lint
+
+```bash
+npm run lint
+```
+
+## Tech Stack
+
+- **Framework:** Next.js 16 (App Router)
+- **Language:** TypeScript
+- **Styling:** Tailwind CSS
+- **UI Components:** shadcn/ui
+- **Charts:** Recharts
+- **Data Scraping:** Apify (apify-client)
+
+## Limitations
+
+- Only works with **public** Instagram profiles
+- Private accounts will return an error
+- Rate limits apply based on your Apify plan
+- Historical engagement data is limited to recent posts
+
+## Learn More
+
+- [Apify Documentation](https://docs.apify.com)
+- [Instagram Profile Scraper](https://apify.com/apify/instagram-profile-scraper)
+- [Next.js Documentation](https://nextjs.org/docs)
+- [Apify JavaScript SDK](https://docs.apify.com/sdk/js/)
+
+## Troubleshooting
+
+### "APIFY_TOKEN not set" error
+
+Make sure you've created `.env.local` with your token:
+
+```bash
+APIFY_TOKEN=your_token_here
+```
+
+Restart the dev server after adding the token.
+
+### "Profile not found" error
+
+- Verify the username is correct
+- Check if the account is public (private accounts cannot be scraped)
+- Try using just the username without @ or URL
+
+### Actor timeout
+
+If the Actor takes too long, it might be due to:
+- Instagram rate limiting
+- Network issues
+- Heavy traffic on Apify
+
+Try again after a few minutes.
+
+## License
+
+This is a demo application. Check individual package licenses for production use.
diff --git a/social-demo/app/api/instagram/[username]/route.ts b/social-demo/app/api/instagram/[username]/route.ts
new file mode 100644
index 0000000..361e22e
--- /dev/null
+++ b/social-demo/app/api/instagram/[username]/route.ts
@@ -0,0 +1,86 @@
+import { NextRequest, NextResponse } from "next/server";
+import { ApifyClient } from "apify-client";
+import { transformApifyToProfile } from "@/lib/apify-transform";
+
+// Initialize the Apify client
+const getApifyClient = () => {
+ const token = process.env.APIFY_TOKEN;
+
+ if (!token) {
+ throw new Error("APIFY_TOKEN environment variable is not set");
+ }
+
+ return new ApifyClient({ token });
+};
+
+export async function GET(
+ request: NextRequest,
+ context: { params: Promise<{ username: string }> }
+) {
+ try {
+ const { username } = await context.params;
+
+ if (!username) {
+ return NextResponse.json(
+ { error: "Username is required" },
+ { status: 400 }
+ );
+ }
+
+ // Clean the username (remove @ if present)
+ const cleanUsername = username.replace("@", "").trim();
+
+ console.log(`Fetching Instagram profile for: ${cleanUsername}`);
+
+ // Initialize Apify client
+ const client = getApifyClient();
+
+ // Call the Instagram Profile Scraper Actor
+ const run = await client.actor("apify/instagram-profile-scraper").call({
+ usernames: [cleanUsername],
+ includeAboutSection: false, // Set to true if you have a paid plan
+ });
+
+ // Get the results from the dataset
+ const { items } = await client.dataset(run.defaultDatasetId).listItems();
+
+ if (!items || items.length === 0) {
+ return NextResponse.json(
+ { error: "Profile not found or account is private" },
+ { status: 404 }
+ );
+ }
+
+ // Transform the first (and only) result to our format
+ const profileData = items[0] as any; // Type from Apify may vary
+
+ // Check if the account is private
+ if (profileData.private) {
+ return NextResponse.json(
+ { error: "This account is private and cannot be scraped" },
+ { status: 403 }
+ );
+ }
+
+ const transformedProfile = transformApifyToProfile(profileData);
+
+ return NextResponse.json(transformedProfile);
+ } catch (error) {
+ console.error("Error fetching Instagram profile:", error);
+
+ // Handle specific error cases
+ if (error instanceof Error) {
+ if (error.message.includes("APIFY_TOKEN")) {
+ return NextResponse.json(
+ { error: "Apify configuration error. Please check your APIFY_TOKEN environment variable." },
+ { status: 500 }
+ );
+ }
+ }
+
+ return NextResponse.json(
+ { error: "Failed to fetch Instagram profile. Please try again later." },
+ { status: 500 }
+ );
+ }
+}
diff --git a/social-demo/app/page.tsx b/social-demo/app/page.tsx
index 0f586f2..a14dfbf 100644
--- a/social-demo/app/page.tsx
+++ b/social-demo/app/page.tsx
@@ -9,22 +9,31 @@ import { EngagementChart } from "@/components/EngagementChart";
import { PostsGrid } from "@/components/PostsGrid";
import { HashtagCloud } from "@/components/HashtagCloud";
import { InstagramProfile } from "@/lib/types";
-import { fetchInstagramProfile } from "@/data/mock-profile";
+
export default function Home() {
const [profile, setProfile] = useState
{error}
+