Skip to main content

Facebook Time-Based Breakdowns

The breakdowns endpoints provide monthly aggregated performance data for campaigns, ad sets, and ads, enabling time-series analysis and trend identification.

Endpoints Overview

EndpointMethodPurpose
/v1/e/facebook/breakdowns/:account_id/campaignsGETGet campaign monthly breakdown
/v1/e/facebook/breakdowns/:account_id/adsetsGETGet ad set monthly breakdown
/v1/e/facebook/breakdowns/:account_id/adsGETGet ad monthly breakdown

Campaign Breakdown

Get Campaign Monthly Performance

Retrieves monthly aggregated metrics for all campaigns in an ad account.

Endpoint: GET /v1/e/facebook/breakdowns/:account_id/campaigns

Path Parameters:

ParameterTypeRequiredDescription
account_idStringYesFacebook Ad Account ID (e.g., act_123456789)

Query Parameters:

ParameterTypeRequiredDescription
sinceStringYesStart date (YYYY-MM-DD)
untilStringYesEnd date (YYYY-MM-DD)
statusStringNoFilter by status (e.g., ACTIVE,PAUSED)
searchStringNoSearch campaign name (partial match)
sortStringNoSort field (e.g., spend)
orderStringNoSort order: ascending or descending
account_idStringNoDashClicks sub-account ID

Example Request:

GET /v1/e/facebook/breakdowns/act_123456789/campaigns?since=2024-01-01&until=2024-12-31&status=ACTIVE
Authorization: Bearer eyJhbGc...

Response:

{
"success": true,
"message": "SUCCESS",
"data": {
"23851234567890123": {
"campaign_name": "Summer Sale Campaign",
"January": {
"impressions": 15000,
"cpm": 12.5,
"clicks": 450,
"cpc": 0.42,
"cpa": 15,
"spend": 187.5
},
"February": {
"impressions": 18000,
"cpm": 11.8,
"clicks": 540,
"cpc": 0.39,
"cpa": 22,
"spend": 210.6
},
"March": {
"impressions": 22000,
"cpm": 10.9,
"clicks": 680,
"cpc": 0.35,
"spend": 239.8,
"cpa": 28
},
"April": {
"impressions": 0,
"cpm": 0,
"clicks": 0,
"cpc": 0,
"cpa": 0,
"spend": 0
},
"May": {
"impressions": 0,
"cpm": 0,
"clicks": 0,
"cpc": 0,
"cpa": 0,
"spend": 0
}
},
"23851234567890456": {
"campaign_name": "Spring Collection",
"January": {
"impressions": 8500,
"cpm": 15.2,
"clicks": 220,
"cpc": 0.58,
"cpa": 8,
"spend": 129.2
}
}
}
}

Data Structure:

const breakdownStructure = {
[campaign_id]: {
campaign_name: 'Campaign name',
January: { impressions, cpm, clicks, cpc, cpa, spend },
February: { impressions, cpm, clicks, cpc, cpa, spend },
March: { impressions, cpm, clicks, cpc, cpa, spend },
April: { impressions, cpm, clicks, cpc, cpa, spend },
May: { impressions, cpm, clicks, cpc, cpa, spend },
June: { impressions, cpm, clicks, cpc, cpa, spend },
July: { impressions, cpm, clicks, cpc, cpa, spend },
August: { impressions, cpm, clicks, cpc, cpa, spend },
September: { impressions, cpm, clicks, cpc, cpa, spend },
October: { impressions, cpm, clicks, cpc, cpa, spend },
November: { impressions, cpm, clicks, cpc, cpa, spend },
December: { impressions, cpm, clicks, cpc, cpa, spend },
},
};

Month Metrics Explained:

const monthMetrics = {
impressions: 'Total impressions for the month',
cpm: 'Cost per 1000 impressions',
clicks: 'Total clicks for the month',
cpc: 'Cost per click',
cpa: 'Number of purchase actions',
spend: 'Total spend for the month',
};

Implementation Details:

exports.getCampaignBreakDown = async (req, res, next) => {
try {
let fbAccountId = req.params.account_id;
let filterParams = req.query;
filterParams.level = 'campaign';
filterParams.time_increment = 'monthly';

let accountId = await checkAccountAccess(req);

const existKeys = await facebookModel.find({
accountID: accountId,
source: 'meta-ads',
});

let accessToken = await facebookModel.checkAccessTokenValidity({
req: req,
expirationTime: existKeys.token.expires_in,
accessToken: existKeys.token.access_token,
docId: existKeys.docId,
source: 'meta-ads',
});

// Transform date parameters
if (filterParams.since && filterParams.until) {
filterParams.time_range = {
since: moment(filterParams.since).startOf('day').format('YYYY-MM-DD'),
until: moment(filterParams.until).startOf('day').format('YYYY-MM-DD'),
};
delete filterParams.since;
delete filterParams.until;
}

// Build filtering
filterParams.filtering = [];

if (filterParams.search) {
filterParams.filtering.push({
field: 'campaign.name',
operator: 'CONTAIN',
value: filterParams.search,
});
delete filterParams.search;
}

if (filterParams.status) {
filterParams.filtering.push({
field: 'campaign.effective_status',
operator: 'IN',
value: filterParams.status.split(','),
});
delete filterParams.status;
}

// Fetch insights with monthly breakdown
let accountInsights = await fbProvider.getBreakDown(fbAccountId, accessToken, filterParams);

// Initialize month structure
const monthsArray = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];

let months = {};

// Create structure for each campaign
if (accountInsights) {
for (let dataInsight of accountInsights) {
months[dataInsight.campaign_id] = {};
months[dataInsight.campaign_id]['campaign_name'] = dataInsight.campaign_name;

// Initialize all months to 0
for (let i = 0; i < 12; i++) {
months[dataInsight.campaign_id][monthsArray[i]] = {
impressions: 0,
cpm: 0,
clicks: 0,
cpc: 0,
cpa: 0,
spend: 0,
};
}
}
}

// Aggregate data by month
if (accountInsights) {
for (let dataInsight of accountInsights) {
let month = new Date(dataInsight.date_start).getMonth();
let monthName = monthsArray[month];
let campaign = months[dataInsight.campaign_id];

campaign[monthName]['impressions'] += parseInt(dataInsight.impressions || 0);
campaign[monthName]['cpm'] += parseInt(dataInsight.cpm || 0);
campaign[monthName]['clicks'] += parseInt(dataInsight.clicks || 0);
campaign[monthName]['cpc'] += parseInt(dataInsight.cpc || 0);
campaign[monthName]['spend'] += parseFloat(dataInsight.spend || 0);

// Extract purchase actions for CPA
if (dataInsight.actions) {
const resultPurchase = dataInsight.actions.find(
({ action_type }) => action_type === 'purchase',
);
if (resultPurchase && resultPurchase.value) {
campaign[monthName]['cpa'] += parseInt(resultPurchase.value);
}
}
}
}

return res.status(200).json({
success: true,
message: 'SUCCESS',
data: months,
});
} catch (error) {
next(error);
}
};

Filtering Logic:

// Status filtering
{
field: 'campaign.effective_status',
operator: 'IN',
value: ['ACTIVE', 'PAUSED']
}

// Name search (partial match)
{
field: 'campaign.name',
operator: 'CONTAIN',
value: 'Summer'
}

Ad Set Breakdown

Get Ad Set Monthly Performance

Retrieves monthly aggregated metrics for ad sets.

Endpoint: GET /v1/e/facebook/breakdowns/:account_id/adsets

Query Parameters: Same as campaigns plus:

ParameterTypeRequiredDescription
campaignidsStringNoFilter by campaign IDs (comma-separated)

Example Request:

GET /v1/e/facebook/breakdowns/act_123456789/adsets?since=2024-01-01&until=2024-12-31&campaignids=123,456
Authorization: Bearer eyJhbGc...

Response:

{
"success": true,
"message": "SUCCESS",
"data": {
"23851234567890456": {
"adset_name": "Desktop Users - US",
"January": {
"impressions": 8000,
"cpm": 12.5,
"clicks": 240,
"cpc": 0.42,
"cpa": 8,
"spend": 100.0
},
"February": {
"impressions": 9500,
"cpm": 11.8,
"clicks": 285,
"cpc": 0.39,
"cpa": 11,
"spend": 112.1
}
}
}
}

Implementation Differences:

// Set level to adset
filterParams.level = 'adset';

// Campaign filtering
if (filterParams.campaignids) {
filterParams.filtering.push({
field: 'campaign.id',
operator: 'IN',
value: filterParams.campaignids.split(','),
});
delete filterParams.campaignids;
}

// Name search
if (filterParams.search) {
filterParams.filtering.push({
field: 'adset.name',
operator: 'CONTAIN',
value: filterParams.search,
});
delete filterParams.search;
}

// Status filtering
if (filterParams.status) {
filterParams.filtering.push({
field: 'adset.effective_status',
operator: 'IN',
value: filterParams.status.split(','),
});
delete filterParams.status;
}

Ad Breakdown

Get Ad Monthly Performance

Retrieves monthly aggregated metrics for individual ads.

Endpoint: GET /v1/e/facebook/breakdowns/:account_id/ads

Query Parameters: Same as ad sets plus:

ParameterTypeRequiredDescription
adsetidsStringNoFilter by ad set IDs (comma-separated)

Example Request:

GET /v1/e/facebook/breakdowns/act_123456789/ads?since=2024-01-01&until=2024-12-31&campaignids=123&adsetids=456,789
Authorization: Bearer eyJhbGc...

Response:

{
"success": true,
"message": "SUCCESS",
"data": {
"23851234567890789": {
"ad_name": "Summer Sale - Image Ad 1",
"January": {
"impressions": 4000,
"cpm": 12.5,
"clicks": 120,
"cpc": 0.42,
"cpa": 4,
"spend": 50.0
},
"February": {
"impressions": 4750,
"cpm": 11.8,
"clicks": 143,
"cpc": 0.39,
"cpa": 6,
"spend": 56.1
}
}
}
}

Implementation Differences:

// Set level to ad
filterParams.level = 'ad';

// Ad set filtering
if (filterParams.adsetids) {
filterParams.filtering.push({
field: 'adset.id',
operator: 'IN',
value: filterParams.adsetids.split(','),
});
delete filterParams.adsetids;
}

// Name search
if (filterParams.search) {
filterParams.filtering.push({
field: 'ad.name',
operator: 'CONTAIN',
value: filterParams.search,
});
delete filterParams.search;
}

// Status filtering
if (filterParams.status) {
filterParams.filtering.push({
field: 'ad.effective_status',
operator: 'IN',
value: filterParams.status.split(','),
});
delete filterParams.status;
}

Time Increment

All breakdown endpoints use time_increment: 'monthly' which groups data by calendar month:

filterParams.time_increment = 'monthly';

Available Time Increments:

const timeIncrements = {
1: 'Daily breakdown',
7: 'Weekly breakdown',
monthly: 'Monthly breakdown (used by breakdowns)',
all_days: 'Total for entire range',
};

Data Aggregation

Month Initialization

All 12 months are initialized to zero values, even if no data exists:

const monthsArray = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];

for (let i = 0; i < 12; i++) {
months[id][monthsArray[i]] = {
impressions: 0,
cpm: 0,
clicks: 0,
cpc: 0,
cpa: 0,
spend: 0,
};
}

Metric Aggregation

Metrics are summed across all days within each month:

let month = new Date(dataInsight.date_start).getMonth();
let monthName = monthsArray[month];

// Aggregate metrics
campaign[monthName]['impressions'] += parseInt(dataInsight.impressions || 0);
campaign[monthName]['cpm'] += parseInt(dataInsight.cpm || 0);
campaign[monthName]['clicks'] += parseInt(dataInsight.clicks || 0);
campaign[monthName]['cpc'] += parseInt(dataInsight.cpc || 0);
campaign[monthName]['spend'] += parseFloat(dataInsight.spend || 0);

Purchase Action Extraction

The cpa metric specifically tracks purchase actions:

if (dataInsight.actions) {
const resultPurchase = dataInsight.actions.find(({ action_type }) => action_type === 'purchase');
if (resultPurchase && resultPurchase.value) {
campaign[monthName]['cpa'] += parseInt(resultPurchase.value);
}
}

Use Cases

Year-over-Year Comparison

Compare performance across months for trend analysis:

// Request full year
GET /breakdowns/act_123/campaigns?since=2024-01-01&until=2024-12-31

// Response includes all 12 months
{
"23851234567890123": {
"campaign_name": "Brand Campaign",
"January": { "spend": 1000, "impressions": 50000 },
"February": { "spend": 1200, "impressions": 60000 },
// ... rest of months
}
}

Seasonal Analysis

Identify seasonal trends by comparing months:

// Q1 (Jan-Mar) vs Q2 (Apr-Jun) vs Q3 (Jul-Sep) vs Q4 (Oct-Dec)
const q1Spend = data.January.spend + data.February.spend + data.March.spend;
const q2Spend = data.April.spend + data.May.spend + data.June.spend;

Campaign Lifecycle

Track campaign performance from launch to completion:

// Campaign launched in March, ended in August
// Response shows:
// - Zeros for Jan-Feb (before launch)
// - Performance data for Mar-Aug
// - Zeros for Sep-Dec (after end)

Performance Considerations

Date Range Limits

  • Recommended: Up to 12 months (1 year)
  • Maximum: No hard limit, but larger ranges impact performance

Data Volume

Breakdown endpoints aggregate at the monthly level, reducing data volume compared to daily breakdowns:

// Daily breakdown: 365 data points per campaign
// Monthly breakdown: 12 data points per campaign

Caching Strategy

const cachingStrategy = {
'Historical months': "Cache indefinitely (won't change)",
'Current month': 'Cache for 1 hour (updates frequently)',
'Future months': 'Always return zeros (no caching needed)',
};

Error Handling

Common Errors

// No token found
{
"success": false,
"errno": 400,
"message": "Record Not found!"
}

// Invalid account
{
"success": false,
"errno": 400,
"message": "Invalid Account Id"
}

// No data in date range (still returns structure)
{
"success": true,
"data": {
"23851234567890123": {
"campaign_name": "Campaign",
"January": { "impressions": 0, "clicks": 0, "spend": 0, ... },
// All months with zero values
}
}
}

Integration Checklist

Breakdown Implementation

  • Connect Facebook with meta-ads source
  • Test campaign monthly breakdown
  • Test ad set monthly breakdown
  • Test ad monthly breakdown
  • Verify date range handling
  • Test filtering (status, search, IDs)
  • Verify month initialization (all 12 months)
  • Test zero-value months
  • Verify purchase action extraction

Data Visualization

  • Create month-over-month comparison charts
  • Build seasonal trend analysis
  • Implement year-over-year comparison
  • Add quarter aggregation
  • Create performance heatmaps

Additional Resources

💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:30 AM