Instagram Integration API
CivicPulse integrates with the Instagram Graph API to fetch recent @mentions of the configured Instagram Business account and convert them into trackable civic issues. The integration is surfaced in the Social Wall Instagram tab.
Demo vs Live Modeβ
| Condition | Mode | Source |
|---|---|---|
IG_ACCESS_TOKEN or IG_USER_ID not set | demo | Returns MOCK_IG_MENTIONS (5 sample civic posts) |
| Token set, API returns 401/403 | demo | Graceful fallback to mock data |
| Token set, API returns data | live | Real mentions from Instagram Graph API |
Environment Variablesβ
| Variable | Required | Default | Description |
|---|---|---|---|
IG_ACCESS_TOKEN | No | β | Long-lived user access token from Meta Developer portal. Without this, the Social Wall Instagram tab runs in demo mode. |
IG_USER_ID | No | β | Instagram Business account user ID. Required alongside IG_ACCESS_TOKEN for live mode. |
IG_HANDLE | No | civicpulse | Display name for the Instagram handle (without @). Used in API responses and the frontend. |
Endpointsβ
GET /api/ig/mentionsβ
Fetch recent mentions of the configured Instagram handle.
Auth: None required
Query params:
| Param | Type | Default | Description |
|---|---|---|---|
count | number | 20 | Max mentions to return (clamped 10β50) |
Response:
{
"mentions": [
{
"id": "ig1",
"text": "@civicpulse Massive pothole on Western Express Highway...",
"user": "@mumbai_civic_watch",
"timestamp": "5 min ago",
"category_hint": "road",
"city_hint": "Mumbai",
"images": [
{ "id": "ig1-img-0", "url": "https://...", "type": "image", "source": "instagram", "caption": "Pothole near flyover" }
],
"videos": [],
"permalink": "https://www.instagram.com/p/abc123/"
}
],
"mode": "demo",
"handle": "civicpulse"
}
Headers: Cache-Control: no-store
POST /api/ig/mentions/:mediaId/convertβ
Convert an Instagram mention into a CivicPulse issue.
Auth: Bearer token required
Path params:
| Param | Type | Description |
|---|---|---|
mediaId | string (1β50) | Instagram media ID to associate with the issue |
Body:
| Field | Type | Required | Description |
|---|---|---|---|
title | string (5β200) | Yes | Issue title |
description | string (10β5000) | Yes | Issue description |
category | string | Yes | One of: traffic, road, infrastructure, hygiene, healthcare, systemic |
city | string (2β100) | Yes | City name |
priority | string | No | low, medium (default), high |
images | array | No | Image media items to attach |
videos | array | No | Video media items to attach |
Response: 201 β created issue object with source: "instagram" and tweetId set to the media ID.
Instagram Graph API Setupβ
Prerequisitesβ
- Instagram Business or Creator account (free to convert from personal)
- Facebook Page linked to the Instagram account
- Meta Developer App with
instagram_basicandinstagram_manage_commentspermissions
Getting Credentialsβ
- Go to Meta Developer Portal
- Create or select your app
- Add the Instagram Graph API product
- Generate a User Access Token with required permissions
- Convert to a long-lived token (60-day expiry, refreshable)
- Find your Instagram User ID via
GET /me?fields=id,username
Token Refreshβ
Long-lived tokens expire after 60 days. Refresh before expiry:
GET https://graph.facebook.com/v18.0/oauth/access_token
?grant_type=ig_exchange_token
&client_secret={app-secret}
&access_token={long-lived-token}
Mention Shapeβ
Each mention (both mock and live) follows this shape:
interface IGMention {
id: string; // Instagram media ID
text: string; // Caption text
user: string; // "@username"
timestamp: string; // Relative time ("5 min ago")
category_hint: string; // Auto-detected from text
city_hint: string; // Auto-detected from text
images: MediaItem[]; // IMAGE or CAROUSEL_ALBUM β images
videos: MediaItem[]; // VIDEO β videos
permalink: string; // "https://www.instagram.com/p/..."
}
Category Detectionβ
The same detectCategory() function from textDetection.js is used across all social integrations (X, WhatsApp, Instagram). It scans the caption text for civic keywords and returns the best-matching category.
City Detectionβ
The same detectCity() function scans for known Indian city names in the caption text.
Backend Serviceβ
File: backend/services/igService.js
Mirrors the structure of xService.js:
| Export | Description |
|---|---|
fetchMentions(count) | Main function β returns { mentions, mode } |
formatIGMedia(media) | Maps Instagram Graph API media object to CivicPulse shape |
IG_HANDLE | Configured Instagram handle |
MOCK_IG_MENTIONS | 5 mock mentions for demo mode |
Frontend Componentsβ
IGFeedβ
File: frontend/src/components/social/IGFeed.jsx
Two-column layout mirroring WAFeed:
- Left column: Pending IG posts with username, caption, media thumbnails, city/category badges, "Convert" button
- Right column: Already-converted issues filtered by
source === 'instagram'
Instagram-branded styling: gradient purple-pink (#833AB4 β #E1306C).
SocialWall Integrationβ
The SocialWall component renders IGFeed when the Instagram tab is selected, replacing the previous "Coming Soon" placeholder. A mode badge shows "Demo" or "Live Instagram" status.