Skip to main content
Glama

Facebook Ads Management Control Panel

by codprocess
recommendations.js10.7 kB
/** * Recommendations routes * Handles operations related to Facebook ad recommendations */ const express = require('express'); const router = express.Router(); const { protect } = require('../middleware/auth'); const { validate, schemas } = require('../middleware/validator'); const { sendSuccess, sendError } = require('../utils/responseFormatter'); const { NotFoundError } = require('../utils/errorTypes'); const AdAccount = require('../models/adAccount'); const recommendationService = require('../services/recommendationService'); const logger = require('../utils/logger'); /** * @route GET /api/recommendations/budget * @desc Get budget optimization recommendations * @access Private */ router.get('/budget', protect, async (req, res, next) => { try { // Get ad account ID from query params const { adAccountId } = req.query; if (!adAccountId) { return next(new NotFoundError('Ad account ID is required')); } // Check if ad account exists const adAccount = await AdAccount.findOne({ accountId: adAccountId, userId: req.user._id }); if (!adAccount) { return next(new NotFoundError('Ad account not found')); } // Create recommendation service const recommendations = recommendationService.createForUser(req.user); // Get budget recommendations const budgetRecommendations = await recommendations.getBudgetRecommendations(adAccountId); return sendSuccess(res, budgetRecommendations, 'Budget recommendations retrieved successfully'); } catch (error) { logger.error(`Error retrieving budget recommendations: ${error.message}`); return next(error); } }); /** * @route GET /api/recommendations/targeting * @desc Get targeting recommendations for an ad set * @access Private */ router.get('/targeting', protect, async (req, res, next) => { try { // Get ad set ID from query params const { adSetId } = req.query; if (!adSetId) { return next(new NotFoundError('Ad set ID is required')); } // Create recommendation service const recommendations = recommendationService.createForUser(req.user); // Get targeting recommendations const targetingRecommendations = await recommendations.getTargetingRecommendations(adSetId); return sendSuccess(res, targetingRecommendations, 'Targeting recommendations retrieved successfully'); } catch (error) { logger.error(`Error retrieving targeting recommendations: ${error.message}`); return next(error); } }); /** * @route GET /api/recommendations/creative * @desc Get creative performance recommendations * @access Private */ router.get('/creative', protect, async (req, res, next) => { try { // Get ad account ID from query params const { adAccountId } = req.query; if (!adAccountId) { return next(new NotFoundError('Ad account ID is required')); } // Check if ad account exists const adAccount = await AdAccount.findOne({ accountId: adAccountId, userId: req.user._id }); if (!adAccount) { return next(new NotFoundError('Ad account not found')); } // Create recommendation service const recommendations = recommendationService.createForUser(req.user); // Get creative recommendations const creativeRecommendations = await recommendations.getCreativeRecommendations(adAccountId); return sendSuccess(res, creativeRecommendations, 'Creative recommendations retrieved successfully'); } catch (error) { logger.error(`Error retrieving creative recommendations: ${error.message}`); return next(error); } }); /** * @route GET /api/recommendations/all * @desc Get all recommendations for an ad account * @access Private */ router.get('/all', protect, async (req, res, next) => { try { // Get ad account ID from query params const { adAccountId } = req.query; if (!adAccountId) { return next(new NotFoundError('Ad account ID is required')); } // Check if ad account exists const adAccount = await AdAccount.findOne({ accountId: adAccountId, userId: req.user._id }); if (!adAccount) { return next(new NotFoundError('Ad account not found')); } // Create recommendation service const recommendations = recommendationService.createForUser(req.user); // Get all recommendations const [budgetRecommendations, creativeRecommendations] = await Promise.all([ recommendations.getBudgetRecommendations(adAccountId), recommendations.getCreativeRecommendations(adAccountId) ]); // Combine recommendations const allRecommendations = { budget: budgetRecommendations, creative: creativeRecommendations }; return sendSuccess(res, allRecommendations, 'All recommendations retrieved successfully'); } catch (error) { logger.error(`Error retrieving all recommendations: ${error.message}`); return next(error); } }); /** * @route GET /api/recommendations/summary * @desc Get recommendations summary for an ad account * @access Private */ router.get('/summary', protect, async (req, res, next) => { try { // Get ad account ID from query params const { adAccountId } = req.query; if (!adAccountId) { return next(new NotFoundError('Ad account ID is required')); } // Check if ad account exists const adAccount = await AdAccount.findOne({ accountId: adAccountId, userId: req.user._id }); if (!adAccount) { return next(new NotFoundError('Ad account not found')); } // Create recommendation service const recommendations = recommendationService.createForUser(req.user); // Get all recommendations const [budgetRecommendations, creativeRecommendations] = await Promise.all([ recommendations.getBudgetRecommendations(adAccountId), recommendations.getCreativeRecommendations(adAccountId) ]); // Create summary const summary = { totalRecommendations: 0, budgetRecommendations: { count: budgetRecommendations.length, increaseBudget: 0, decreaseBudget: 0, other: 0 }, creativeRecommendations: { count: creativeRecommendations.length, lowCtr: 0, lowConversionRate: 0, other: 0 } }; // Count budget recommendations by type budgetRecommendations.forEach(campaign => { campaign.recommendations.forEach(rec => { summary.totalRecommendations++; if (rec.type === 'increase_budget') { summary.budgetRecommendations.increaseBudget++; } else if (rec.type === 'decrease_budget') { summary.budgetRecommendations.decreaseBudget++; } else { summary.budgetRecommendations.other++; } }); }); // Count creative recommendations by type creativeRecommendations.forEach(ad => { ad.recommendations.forEach(rec => { summary.totalRecommendations++; if (rec.type === 'low_ctr') { summary.creativeRecommendations.lowCtr++; } else if (rec.type === 'low_conversion_rate') { summary.creativeRecommendations.lowConversionRate++; } else { summary.creativeRecommendations.other++; } }); }); return sendSuccess(res, summary, 'Recommendations summary retrieved successfully'); } catch (error) { logger.error(`Error retrieving recommendations summary: ${error.message}`); return next(error); } }); /** * @route GET /api/recommendations/best-practices * @desc Get best practices recommendations * @access Private */ router.get('/best-practices', protect, (req, res) => { const bestPractices = [ { category: 'Campaign Structure', recommendations: [ { title: 'Use campaign budget optimization', description: 'Let Facebook automatically distribute your budget across ad sets to get more results', impact: 'high' }, { title: 'Group similar ad sets in the same campaign', description: 'Organize ad sets with similar objectives and target audiences in the same campaign', impact: 'medium' }, { title: 'Use different campaigns for different objectives', description: 'Separate campaigns by objective (e.g., awareness, consideration, conversion)', impact: 'high' } ] }, { category: 'Targeting', recommendations: [ { title: 'Use lookalike audiences', description: 'Create lookalike audiences based on your existing customers or high-value users', impact: 'high' }, { title: 'Test different audience sizes', description: 'Experiment with both broad and narrow audiences to find what works best', impact: 'medium' }, { title: 'Use detailed targeting expansion', description: 'Allow Facebook to reach people beyond your defined targeting when it\'s likely to improve performance', impact: 'medium' } ] }, { category: 'Creative', recommendations: [ { title: 'Test multiple ad formats', description: 'Use a mix of image, video, carousel, and collection ads to see what performs best', impact: 'high' }, { title: 'Keep ad copy concise', description: 'Use short, compelling headlines and clear calls to action', impact: 'medium' }, { title: 'Refresh creative regularly', description: 'Update your creative every few weeks to prevent ad fatigue', impact: 'high' } ] }, { category: 'Optimization', recommendations: [ { title: 'Use automatic placements', description: 'Let Facebook show your ads across all placements to reach more people at a lower cost', impact: 'high' }, { title: 'Optimize for the right event', description: 'Choose an optimization event that aligns with your campaign objective', impact: 'high' }, { title: 'Use A/B testing', description: 'Regularly test different elements of your ads to improve performance', impact: 'medium' } ] } ]; return sendSuccess(res, bestPractices, 'Best practices recommendations retrieved successfully'); }); module.exports = router;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/codprocess/facebook-ads-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server