@memberjunction/actions-bizapps-social
Version:
Social Media Actions for MemberJunction - Twitter, LinkedIn, Facebook, Instagram, TikTok, YouTube, HootSuite, Buffer
269 lines • 10.6 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { RegisterClass } from '@memberjunction/global';
import { InstagramBaseAction } from '../instagram-base.action.js';
import { LogError } from '@memberjunction/core';
import { BaseAction } from '@memberjunction/actions';
/**
* Retrieves detailed insights and analytics for a specific Instagram post.
* Available metrics vary by post type (feed, reels, stories).
*/
let InstagramGetPostInsightsAction = class InstagramGetPostInsightsAction extends InstagramBaseAction {
async InternalRunAction(params) {
try {
const companyIntegrationId = this.getParamValue(params.Params, 'CompanyIntegrationID');
const postId = this.getParamValue(params.Params, 'PostID');
const metricTypes = this.getParamValue(params.Params, 'MetricTypes');
const period = this.getParamValue(params.Params, 'Period') || 'lifetime';
// Initialize OAuth
if (!await this.initializeOAuth(companyIntegrationId, params)) {
return {
Success: false,
Message: 'Failed to initialize Instagram authentication',
ResultCode: 'AUTH_FAILED'
};
}
// Validate inputs
if (!postId) {
return {
Success: false,
Message: 'PostID is required',
ResultCode: 'MISSING_PARAMS'
};
}
// First, get the post details to determine its type
const postDetails = await this.getPostDetails(postId);
if (!postDetails) {
return {
Success: false,
Message: 'Post not found or access denied',
ResultCode: 'POST_NOT_FOUND'
};
}
// Determine available metrics based on post type
const availableMetrics = this.getAvailableMetrics(postDetails.media_type);
const requestedMetrics = metricTypes && metricTypes.length > 0
? metricTypes.filter(m => availableMetrics.includes(m))
: availableMetrics;
if (requestedMetrics.length === 0) {
return {
Success: false,
Message: 'No valid metrics specified for this post type',
ResultCode: 'INVALID_METRICS'
};
}
// Get insights
const insights = await this.getInsights(postId, requestedMetrics, period);
// Parse and structure the insights data
const parsedInsights = this.parseInsightsData(insights);
// Calculate engagement rate
const engagementRate = this.calculateEngagementRate(parsedInsights, postDetails);
// Store result in output params
const outputParams = [...params.Params];
outputParams.push({
Name: 'ResultData',
Type: 'Output',
Value: JSON.stringify({
postId,
postType: postDetails.media_type,
permalink: postDetails.permalink,
publishedAt: postDetails.timestamp,
metrics: parsedInsights,
summary: {
engagementRate,
totalEngagements: this.calculateTotalEngagements(parsedInsights),
performanceScore: this.calculatePerformanceScore(parsedInsights)
},
period,
dataCollectedAt: new Date().toISOString()
})
});
return {
Success: true,
Message: 'Successfully retrieved post insights',
ResultCode: 'SUCCESS',
Params: outputParams
};
}
catch (error) {
LogError('Failed to retrieve Instagram post insights', error);
if (error.code === 'RATE_LIMIT') {
return {
Success: false,
Message: 'Instagram API rate limit exceeded. Please try again later.',
ResultCode: 'RATE_LIMIT'
};
}
if (error.code === 'POST_NOT_FOUND') {
return {
Success: false,
Message: 'Instagram post not found or access denied',
ResultCode: 'POST_NOT_FOUND'
};
}
return {
Success: false,
Message: `Failed to retrieve post insights: ${error.message}`,
ResultCode: 'ERROR'
};
}
}
/**
* Get post details including media type
*/
async getPostDetails(postId) {
try {
const response = await this.makeInstagramRequest(postId, 'GET', null, {
fields: 'id,media_type,permalink,timestamp,caption,like_count,comments_count',
access_token: this.getAccessToken()
});
return response;
}
catch (error) {
return null;
}
}
/**
* Get available metrics based on post type
*/
getAvailableMetrics(mediaType) {
const baseMetrics = ['impressions', 'reach', 'engagement'];
switch (mediaType) {
case 'IMAGE':
case 'CAROUSEL_ALBUM':
return [...baseMetrics, 'saved', 'shares'];
case 'VIDEO':
case 'REELS':
return [...baseMetrics, 'saved', 'shares', 'video_views', 'avg_watch_time', 'completion_rate'];
case 'STORY':
return ['impressions', 'reach', 'exits', 'replies', 'taps_forward', 'taps_back'];
default:
return baseMetrics;
}
}
/**
* Parse insights data into a structured format
*/
parseInsightsData(insights) {
const parsed = {};
insights.forEach(metric => {
const name = metric.name;
const values = metric.values || [];
if (values.length > 0) {
// For lifetime metrics, there's usually only one value
const primaryValue = values[0];
parsed[name] = {
value: primaryValue.value || 0,
title: metric.title,
description: metric.description,
period: metric.period
};
// For time series data (like daily metrics)
if (values.length > 1) {
parsed[name].timeSeries = values.map((v) => ({
value: v.value,
endTime: v.end_time
}));
}
}
});
return parsed;
}
/**
* Calculate engagement rate
*/
calculateEngagementRate(insights, postDetails) {
const reach = insights.reach?.value || postDetails.reach || 0;
const engagement = insights.engagement?.value || 0;
if (reach === 0)
return 0;
return Number(((engagement / reach) * 100).toFixed(2));
}
/**
* Calculate total engagements
*/
calculateTotalEngagements(insights) {
const engagement = insights.engagement?.value || 0;
const saves = insights.saved?.value || 0;
const shares = insights.shares?.value || 0;
return engagement + saves + shares;
}
/**
* Calculate a performance score (0-100)
*/
calculatePerformanceScore(insights) {
// Simple scoring algorithm based on key metrics
let score = 0;
let factors = 0;
// Engagement rate factor
const reach = insights.reach?.value || 0;
const engagement = insights.engagement?.value || 0;
if (reach > 0) {
const engagementRate = (engagement / reach) * 100;
score += Math.min(engagementRate * 10, 30); // Max 30 points
factors++;
}
// Reach factor (compared to impressions)
const impressions = insights.impressions?.value || 0;
if (impressions > 0) {
const reachRate = (reach / impressions) * 100;
score += Math.min(reachRate, 20); // Max 20 points
factors++;
}
// Saves factor
const saves = insights.saved?.value || 0;
if (reach > 0) {
const saveRate = (saves / reach) * 100;
score += Math.min(saveRate * 20, 25); // Max 25 points
factors++;
}
// Video completion rate (for videos)
const completionRate = insights.completion_rate?.value || 0;
if (completionRate > 0) {
score += Math.min(completionRate, 25); // Max 25 points
factors++;
}
// Normalize score
if (factors === 0)
return 0;
return Math.round(Math.min(score, 100));
}
/**
* Define the parameters for this action
*/
get Params() {
return [
...this.commonSocialParams,
{
Name: 'PostID',
Type: 'Input',
Value: null
},
{
Name: 'MetricTypes',
Type: 'Input',
Value: null
},
{
Name: 'Period',
Type: 'Input',
Value: 'lifetime'
}
];
}
/**
* Get the description for this action
*/
get Description() {
return 'Retrieves detailed analytics and insights for a specific Instagram post including impressions, reach, engagement, and more.';
}
};
InstagramGetPostInsightsAction = __decorate([
RegisterClass(BaseAction, 'Instagram - Get Post Insights')
], InstagramGetPostInsightsAction);
export { InstagramGetPostInsightsAction };
//# sourceMappingURL=get-post-insights.action.js.map