A comprehensive TypeScript wrapper for Instagram Graph API. Manage posts, stories, comments, DMs, analytics and more with full type safety.
- âś… Full TypeScript support with complete type definitions
- âś… Authentication - OAuth flow, token exchange, refresh tokens
- âś… Post Management - Create, edit, delete posts (images, videos, carousels)
- âś… Stories - Post and manage Instagram Stories
- âś… Comments - Reply, hide, delete, and manage comments
- âś… Direct Messages - Send and receive DMs
- âś… Analytics - Account insights, post metrics, story analytics
- âś… Hashtags - Search and get top/recent media
- âś… Mentions & Tags - Track mentions and tagged posts
- âś… Media Management - Get, update, and delete media
- Meta Business Account - Sign up at business.facebook.com
- Facebook App - Create at developers.facebook.com
- Instagram Business Account - Convert your Instagram account to Business
- Access Token - Generate long-lived access token
- Required Permissions:
instagram_basicinstagram_content_publishinstagram_manage_commentsinstagram_manage_insightsinstagram_manage_messages
npm install instagram-meta-handlerimport InstagramHandler from 'instagram-meta-handler';
const instagram = new InstagramHandler({
accessToken: 'YOUR_ACCESS_TOKEN',
instagramBusinessAccountId: 'YOUR_IG_BUSINESS_ACCOUNT_ID',
version: 'v21.0' // optional, defaults to v21.0
});
// Post an image
const mediaId = await instagram.postImage(
'https://example.com/image.jpg',
'Amazing photo! #instagram'
);// After user authorizes your app, exchange code for token
const authResponse = await InstagramHandler.exchangeCodeForToken(
'YOUR_CLIENT_ID',
'YOUR_CLIENT_SECRET',
'YOUR_REDIRECT_URI',
'AUTHORIZATION_CODE'
);
console.log('Access Token:', authResponse.access_token);const longToken = await InstagramHandler.getLongLivedToken(
'YOUR_CLIENT_SECRET',
'SHORT_LIVED_TOKEN'
);
console.log('Long-lived token:', longToken.access_token);
console.log('Expires in:', longToken.expires_in, 'seconds');const refreshed = await instagram.refreshAccessToken();
console.log('New token:', refreshed.access_token);const mediaId = await instagram.postImage(
'https://example.com/image.jpg',
'Check out this amazing view! #travel #photography',
'LOCATION_ID' // optional
);const videoId = await instagram.postVideo(
'https://example.com/video.mp4',
'My latest adventure! #video #adventure'
);const carouselId = await instagram.postCarousel(
[
'https://example.com/image1.jpg',
'https://example.com/image2.jpg',
'https://example.com/image3.jpg'
],
'Amazing collection! #carousel #photos'
);// Image story
const storyId = await instagram.postStory(
'https://example.com/story.jpg',
'IMAGE'
);
// Video story
const videoStoryId = await instagram.postStory(
'https://example.com/story.mp4',
'VIDEO'
);const containerId = await instagram.createMediaContainer(
'https://example.com/image.jpg',
'Great times with friends!',
'LOCATION_ID',
[
{ username: 'friend1', x: 0.5, y: 0.5 },
{ username: 'friend2', x: 0.3, y: 0.7 }
]
);
const mediaId = await instagram.publishMedia(containerId);await instagram.updateMediaCaption(
'MEDIA_ID',
'Updated caption with new hashtags #updated'
);await instagram.deleteMedia('MEDIA_ID');const media = await instagram.getMedia('MEDIA_ID');
console.log('Likes:', media.like_count);
console.log('Comments:', media.comments_count);
console.log('URL:', media.permalink);const posts = await instagram.getAccountMedia(25);
posts.forEach(post => {
console.log(`${post.caption} - ${post.like_count} likes`);
});// Disable comments
await instagram.setCommentsEnabled('MEDIA_ID', false);
// Enable comments
await instagram.setCommentsEnabled('MEDIA_ID', true);const commentId = await instagram.commentOnMedia(
'MEDIA_ID',
'Great post! 👍'
);const replyId = await instagram.replyToComment(
'COMMENT_ID',
'Thanks for your comment!'
);const comments = await instagram.getMediaComments('MEDIA_ID');
comments.forEach(comment => {
console.log(`${comment.username}: ${comment.text}`);
});const replies = await instagram.getCommentReplies('COMMENT_ID');// Hide comment
await instagram.hideComment('COMMENT_ID');
// Unhide comment
await instagram.unhideComment('COMMENT_ID');await instagram.deleteComment('COMMENT_ID');const conversations = await instagram.getConversations(25);
conversations.forEach(conv => {
console.log('Conversation ID:', conv.id);
console.log('Last updated:', conv.updated_time);
});const messages = await instagram.getConversationMessages('CONVERSATION_ID', 50);
messages.forEach(msg => {
console.log(`${msg.from.username}: ${msg.message}`);
});const messageId = await instagram.sendDirectMessage(
'RECIPIENT_USER_ID',
'Hello! Thanks for reaching out.'
);const replyId = await instagram.replyToMessage(
'CONVERSATION_ID',
'Thanks for your message!'
);const insights = await instagram.getAccountInsights(
['impressions', 'reach', 'profile_views', 'follower_count'],
'day'
);
insights.data.forEach(metric => {
console.log(`${metric.name}: ${metric.values[0].value}`);
});const postInsights = await instagram.getMediaInsights(
'MEDIA_ID',
['impressions', 'reach', 'engagement', 'saved', 'shares']
);
postInsights.forEach(metric => {
console.log(`${metric.name}: ${metric.values[0].value}`);
});const storyInsights = await instagram.getStoryInsights('STORY_MEDIA_ID');
storyInsights.forEach(metric => {
console.log(`${metric.name}: ${metric.values[0].value}`);
});const hashtagId = await instagram.searchHashtag('travel');
console.log('Hashtag ID:', hashtagId);const topPosts = await instagram.getHashtagTopMedia(hashtagId, 25);
topPosts.forEach(post => {
console.log(post.caption);
});const recentPosts = await instagram.getHashtagRecentMedia(hashtagId, 25);const mentions = await instagram.getMentionedMedia();
mentions.forEach(post => {
console.log(`Mentioned in: ${post.permalink}`);
});const tagged = await instagram.getTaggedMedia();
tagged.forEach(post => {
console.log(`Tagged in: ${post.permalink}`);
});const account = await instagram.getAccountInfo();
console.log('Username:', account.username);
console.log('Followers:', account.followers_count);
console.log('Following:', account.follows_count);
console.log('Posts:', account.media_count);
console.log('Bio:', account.biography);
console.log('Website:', account.website);interface InstagramConfig {
accessToken: string;
instagramBusinessAccountId: string;
version?: string;
}
interface MediaObject {
id: string;
media_type: string;
media_url: string;
permalink: string;
timestamp: string;
caption?: string;
username: string;
like_count?: number;
comments_count?: number;
}
interface Comment {
id: string;
text: string;
username: string;
timestamp: string;
like_count?: number;
replies?: any;
}
interface Conversation {
id: string;
updated_time: string;
messages?: any[];
}| Category | Method | Description |
|---|---|---|
| Auth | exchangeCodeForToken() |
Exchange OAuth code for token |
getLongLivedToken() |
Get 60-day token | |
refreshAccessToken() |
Refresh token | |
| Post | postImage() |
Post single image |
postVideo() |
Post video | |
postCarousel() |
Post carousel (2-10 items) | |
postStory() |
Post Instagram story | |
| Edit | updateMediaCaption() |
Edit post caption |
deleteMedia() |
Delete post | |
setCommentsEnabled() |
Enable/disable comments | |
| Get | getMedia() |
Get post details |
getAccountMedia() |
Get account posts | |
| Comments | commentOnMedia() |
Comment on post |
replyToComment() |
Reply to comment | |
getMediaComments() |
Get post comments | |
getCommentReplies() |
Get comment replies | |
hideComment() |
Hide comment | |
unhideComment() |
Unhide comment | |
deleteComment() |
Delete comment | |
| DMs | getConversations() |
Get DM threads |
getConversationMessages() |
Get messages | |
sendDirectMessage() |
Send DM | |
replyToMessage() |
Reply in thread | |
| Insights | getAccountInsights() |
Account analytics |
getMediaInsights() |
Post analytics | |
getStoryInsights() |
Story analytics | |
| Hashtags | searchHashtag() |
Search hashtag |
getHashtagTopMedia() |
Top posts | |
getHashtagRecentMedia() |
Recent posts | |
| Tags | getMentionedMedia() |
Get mentions |
getTaggedMedia() |
Get tagged posts | |
| Account | getAccountInfo() |
Get account details |
impressions- Total impressionsreach- Total reachprofile_views- Profile viewsfollower_count- Follower countemail_contacts- Email button tapsphone_call_clicks- Call button tapstext_message_clicks- Text button tapsget_directions_clicks- Directions button tapswebsite_clicks- Website link clicks
impressions- Post impressionsreach- Post reachengagement- Total engagementsaved- Saves countshares- Shares countlikes- Likes countcomments- Comments countvideo_views- Video views (for videos)
impressions- Story impressionsreach- Story reachreplies- Story repliesexits- Exitstaps_forward- Forward tapstaps_back- Back taps
try {
const mediaId = await instagram.postImage(url, caption);
console.log('Posted successfully:', mediaId);
} catch (error) {
console.error('Failed to post:', error.message);
// Handle error appropriately
}Instagram Graph API has rate limits:
- 200 API calls per hour per user
- 4800 API calls per hour per app
- Monitor your usage to avoid rate limiting
- Use Long-Lived Tokens - They last 60 days instead of 1 hour
- Refresh Tokens Regularly - Refresh before expiration
- Handle Errors Gracefully - Always wrap API calls in try-catch
- Respect Rate Limits - Implement exponential backoff
- Use Webhooks - Set up webhooks for real-time updates
- Cache Data - Cache insights and media to reduce API calls
- Validate Media URLs - Ensure URLs are publicly accessible
- Test Thoroughly - Test in sandbox mode before production
- Format: JPEG, PNG
- Max size: 8MB
- Min resolution: 320px
- Aspect ratio: 1.91:1 to 4:5
- Format: MP4, MOV
- Max size: 100MB
- Max length: 60 seconds (feed), 15 seconds (stories)
- Frame rate: 30fps max
- Audio: AAC, 128kbps
- Format: JPEG, PNG (image), MP4 (video)
- Max size: 100MB
- Duration: 15 seconds max (video)
- Aspect ratio: 9:16
To receive real-time updates, set up webhooks in your Facebook App:
// Webhook verification (GET)
app.get('/webhook', (req, res) => {
const mode = req.query['hub.mode'];
const token = req.query['hub.verify_token'];
const challenge = req.query['hub.challenge'];
if (mode === 'subscribe' && token === 'YOUR_VERIFY_TOKEN') {
res.status(200).send(challenge);
} else {
res.sendStatus(403);
}
});
// Webhook events (POST)
app.post('/webhook', async (req, res) => {
const data = req.body;
if (data.object === 'instagram') {
data.entry.forEach(entry => {
entry.changes.forEach(async change => {
if (change.field === 'comments') {
// New comment received
const commentId = change.value.id;
const text = change.value.text;
// Auto-reply to comment
await instagram.replyToComment(commentId, 'Thanks for your comment!');
}
});
});
}
res.sendStatus(200);
});Token expired?
// Refresh your token
const newToken = await instagram.refreshAccessToken();Video not publishing?
- Videos take time to process (2-10 seconds)
- The handler automatically waits, but ensure video meets requirements
Comments not appearing?
- Check if comments are enabled on the post
- Verify you have
instagram_manage_commentspermission
DMs not working?
- Ensure you have
instagram_manage_messagespermission - User must have interacted with your account first
Insights not available?
- Insights require Instagram Business or Creator account
- Wait 24 hours for insights on new posts
- Instagram Graph API Documentation
- Meta Business Suite
- API Changelog
- Content Publishing Guidelines
- Webhooks Reference
MIT License - feel free to use this in your projects!
Contributions are welcome! Feel free to submit issues or pull requests.
For API-specific issues, refer to Meta's Instagram Platform Support.
Note: This handler requires an active Facebook Developer account and Instagram Business account. Ensure you comply with Instagram's Platform Policy and Terms of Service.