fix: Social IG/FB con métricas Meta vigentes y creatividades Ad Tracker
Quita copy "Paid ads en Ads", migra Page Insights a page_media_view/page_follows y resuelve creatividades Meta a nivel anuncio. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -252,10 +252,13 @@ async function fetchPageBundle(
|
||||
const sinceU = String(toUnix(since));
|
||||
const untilU = String(toUnix(until, true));
|
||||
|
||||
// Meta deprecated page_impressions / page_fans (Nov 2025).
|
||||
// Use page_media_view + page_follows (+ unique views).
|
||||
const metricSets = [
|
||||
'page_impressions,page_impressions_unique,page_post_engagements,page_fans,page_views_total,page_follows,page_daily_follows,page_actions_post_reactions_total',
|
||||
'page_impressions,page_impressions_unique,page_post_engagements,page_fans,page_views_total',
|
||||
'page_impressions,page_impressions_unique,page_post_engagements,page_fans',
|
||||
'page_media_view,page_total_media_view_unique,page_post_engagements,page_follows,page_views_total,page_daily_follows,page_actions_post_reactions_total',
|
||||
'page_media_view,page_total_media_view_unique,page_post_engagements,page_follows,page_views_total',
|
||||
'page_media_view,page_follows,page_views_total',
|
||||
'page_follows,page_views_total',
|
||||
];
|
||||
|
||||
let insightData: {
|
||||
@@ -278,15 +281,50 @@ async function fetchPageBundle(
|
||||
insightsError = formatGraphError(ins.raw);
|
||||
}
|
||||
|
||||
// If bulk failed, try metrics one-by-one so one deprecated name doesn't wipe the rest
|
||||
if (!insightData.length) {
|
||||
const singles = [
|
||||
'page_media_view',
|
||||
'page_total_media_view_unique',
|
||||
'page_post_engagements',
|
||||
'page_follows',
|
||||
'page_views_total',
|
||||
'page_daily_follows',
|
||||
'page_actions_post_reactions_total',
|
||||
];
|
||||
const merged: typeof insightData = [];
|
||||
for (const metric of singles) {
|
||||
const ins = await graphGet(`${encodeURIComponent(pageId)}/insights`, token, {
|
||||
metric,
|
||||
period: 'day',
|
||||
since: sinceU,
|
||||
until: untilU,
|
||||
});
|
||||
if (ins.ok && Array.isArray(ins.json.data)) {
|
||||
merged.push(...(ins.json.data as typeof insightData));
|
||||
}
|
||||
}
|
||||
if (merged.length) {
|
||||
insightData = merged;
|
||||
insightsError = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const series = {
|
||||
impressions: insightSeries(insightData, 'page_impressions'),
|
||||
reach: insightSeries(insightData, 'page_impressions_unique'),
|
||||
impressions: insightSeries(insightData, 'page_media_view').length
|
||||
? insightSeries(insightData, 'page_media_view')
|
||||
: insightSeries(insightData, 'page_impressions'),
|
||||
reach: insightSeries(insightData, 'page_total_media_view_unique').length
|
||||
? insightSeries(insightData, 'page_total_media_view_unique')
|
||||
: insightSeries(insightData, 'page_impressions_unique'),
|
||||
postEngagements: insightSeries(insightData, 'page_post_engagements'),
|
||||
fans: insightSeries(insightData, 'page_fans'),
|
||||
pageViews: insightSeries(insightData, 'page_views_total'),
|
||||
follows: insightSeries(insightData, 'page_follows').length
|
||||
fans: insightSeries(insightData, 'page_follows').length
|
||||
? insightSeries(insightData, 'page_follows')
|
||||
: insightSeries(insightData, 'page_daily_follows'),
|
||||
: insightSeries(insightData, 'page_fans'),
|
||||
pageViews: insightSeries(insightData, 'page_views_total'),
|
||||
follows: insightSeries(insightData, 'page_daily_follows').length
|
||||
? insightSeries(insightData, 'page_daily_follows')
|
||||
: insightSeries(insightData, 'page_follows'),
|
||||
reactions: insightSeries(insightData, 'page_actions_post_reactions_total'),
|
||||
};
|
||||
|
||||
@@ -487,6 +525,58 @@ async function fetchIgBundle(
|
||||
insightsError = formatGraphError(ins.raw);
|
||||
}
|
||||
|
||||
// Partial recovery: one bad metric in a comma-set fails the whole call
|
||||
if (!insightData.length || insightData.length < 3) {
|
||||
const singles = [
|
||||
'reach',
|
||||
'views',
|
||||
'impressions',
|
||||
'profile_views',
|
||||
'website_clicks',
|
||||
'accounts_engaged',
|
||||
'follower_count',
|
||||
'total_interactions',
|
||||
];
|
||||
const byName = new Map<string, (typeof insightData)[0]>();
|
||||
for (const row of insightData) {
|
||||
if (row.name) byName.set(row.name, row);
|
||||
}
|
||||
for (const metric of singles) {
|
||||
if (byName.has(metric)) continue;
|
||||
const ins = await graphGet(`${encodeURIComponent(igId)}/insights`, agencyToken, {
|
||||
metric,
|
||||
period: 'day',
|
||||
since: sinceU,
|
||||
until: untilU,
|
||||
});
|
||||
if (ins.ok && Array.isArray(ins.json.data) && ins.json.data.length) {
|
||||
for (const row of ins.json.data as typeof insightData) {
|
||||
if (row.name) byName.set(row.name, row);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const ins2 = await graphGet(
|
||||
`${encodeURIComponent(igId)}/insights`,
|
||||
agencyToken,
|
||||
{ metric, period: 'day' }
|
||||
);
|
||||
if (ins2.ok && Array.isArray(ins2.json.data)) {
|
||||
for (const row of ins2.json.data as typeof insightData) {
|
||||
const vals = (row.values || []).filter((v) => {
|
||||
const d = (v.end_time || '').slice(0, 10);
|
||||
return d >= since && d <= until;
|
||||
});
|
||||
if (!vals.length || !row.name) continue;
|
||||
byName.set(row.name, { ...row, values: vals });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (byName.size) {
|
||||
insightData = [...byName.values()];
|
||||
insightsError = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const series = {
|
||||
reach: insightSeries(insightData, 'reach'),
|
||||
impressions:
|
||||
|
||||
Reference in New Issue
Block a user