@extends('layouts.app') @section('title', 'Campaigns – Meta – Ad Manager') @section('content') @php $analysis = is_array($analysis ?? null) ? $analysis : null; $show = $show ?? 'on'; $counts = $counts ?? ['on' => 0, 'off' => 0, 'all' => 0]; $datePreset = $datePreset ?? 'last_30d'; $datePresets = $datePresets ?? \App\Services\MetaAdsGraphService::DATE_PRESETS; $worstId = $analysis['worst_campaign_id'] ?? null; $bestId = $analysis['best_campaign_id'] ?? null; $money = static function ($value): string { if ($value === null || $value === '') { return '—'; } return '$'.number_format((float) $value, 2); }; $qty = static function ($value, int $decimals = 0): string { if ($value === null || $value === '') { return '—'; } $n = (float) $value; if ($decimals === 0) { return number_format($n, 0); } return rtrim(rtrim(number_format($n, $decimals, '.', ','), '0'), '.') ?: '0'; }; $pct = static function ($value): string { if ($value === null || $value === '') { return '—'; } return number_format((float) $value, 2).'%'; }; $fmtDate = static function (?string $d): string { if (! is_string($d) || $d === '') { return ''; } $t = strtotime($d); return $t ? date('M j, Y', $t) : $d; }; $rangeLabel = $datePresets[$datePreset] ?? 'Last 30 days'; $startLabel = $fmtDate($dateStart ?? null); $stopLabel = $fmtDate($dateStop ?? null); $tzLabel = trim((string) ($timezoneName ?? '')); $chatLanguage = ($chatLanguage ?? 'es') === 'en' ? 'en' : 'es'; $monthSpend = is_array($monthSpend ?? null) ? $monthSpend : []; $monthCap = $monthSpend['cap'] ?? null; $monthSpent = $monthSpend['spend'] ?? null; $monthPct = $monthSpend['pct'] ?? null; $monthStatus = (string) ($monthSpend['status'] ?? 'none'); $rangeSpend = is_numeric($rangeSpend ?? null) ? (float) $rangeSpend : 0.0; $statusLabel = $show === 'off' ? 'Off campaigns' : ($show === 'all' ? 'All campaigns' : 'On campaigns'); $info = static function (string $text): string { return ''; }; $adsDisplayTz = trim((string) ($adsDisplayTz ?? 'America/New_York')) ?: 'America/New_York'; $toLocal = static function (mixed $value) use ($adsDisplayTz): string { if ($value instanceof \Carbon\CarbonInterface) { return $value->copy()->timezone($adsDisplayTz)->format('Y-m-d\TH:i'); } if (! is_string($value) || trim($value) === '') { return ''; } try { return \Carbon\Carbon::parse($value)->timezone($adsDisplayTz)->format('Y-m-d\TH:i'); } catch (\Throwable $e) { return ''; } }; $fmtWhen = static function (mixed $value) use ($adsDisplayTz): string { if ($value instanceof \Carbon\CarbonInterface) { return $value->copy()->timezone($adsDisplayTz)->format('M j, Y g:i A').' ('.$adsDisplayTz.')'; } if (! is_string($value) || trim($value) === '') { return ''; } try { return \Carbon\Carbon::parse($value)->timezone($adsDisplayTz)->format('M j, Y g:i A').' ('.$adsDisplayTz.')'; } catch (\Throwable $e) { return (string) $value; } }; $scheduledStarts = $scheduledStarts ?? collect(); $schedulesByCampaign = $schedulesByCampaign ?? collect(); $campaigns = is_array($campaigns ?? null) ? $campaigns : []; $campaignNames = []; foreach ($campaigns as $row) { $campaignNames[(string) ($row['id'] ?? '')] = (string) ($row['name'] ?? ''); } @endphp
@include('ads.partials.nav', ['adsPlatform' => 'meta', 'adsSection' => 'campaigns']) @include('ads.partials.marketer')

Campaigns

Meta On/Off for {{ $meta->ad_account_name ?: 'the selected ad account' }}. Default range is Last 30 days, same window as Ads Manager. Ad platforms

{{ $rangeLabel }} @if($startLabel !== '' && $stopLabel !== '') · {{ $startLabel }} – {{ $stopLabel }} @endif @if($tzLabel !== '') · {{ $tzLabel }} @endif

Total spent {!! $info('Sum of Amount spent on the campaigns below, for the date filter you picked (Today, Last 14 days, Last 30 days, etc.). Change On / Off / All or the dates and this total changes with them. This is not the monthly cap.') !!}

{{ $money($rangeSpend) }}

{{ $rangeLabel }} @if($startLabel !== '' && $stopLabel !== '') · {{ $startLabel }} – {{ $stopLabel }} @endif · {{ $statusLabel }}

Monthly cap {!! $info('A limit you set for this calendar month (1st through the last day, ad account timezone). It does not follow Last 14 / Last 30 days. Reaching it is a warning only: campaigns stay On. AI Marketer will flag it. Nothing pauses unless you confirm Pause.') !!}

{{ $money($monthSpent) }} of {{ $monthCap === null ? 'no cap' : $money($monthCap) }} @if($monthCap !== null) {{ $money($monthSpend['remaining'] ?? null) }} left @endif

{{ $monthSpend['month_label'] ?? 'This month' }} @if(! empty($monthSpend['since'])) · {{ $fmtDate($monthSpend['since'] ?? null) }} – {{ $fmtDate($monthSpend['until'] ?? null) }} @endif · Warning only — does not pause campaigns

@if($monthCap !== null)
@endif
@csrf
@if(! empty($monthSpend['error']))

{{ $monthSpend['error'] }}

@endif
@if(session('status'))
{{ session('status') }}
@endif @if(session('error'))
{{ session('error') }}
@endif @if($loadError)
{{ $loadError }}
@endif @if($analysis && ($analysis['summary'] ?? '') !== '')

AI analysis

OpenAI reading the Meta Insights numbers on this page. This is not Meta Ads Manager Analyze. @if(($analysis['scope'] ?? '') === 'campaign' && ($analysis['campaign_name'] ?? '') !== '') Campaign: {{ $analysis['campaign_name'] }}. @else Running campaigns only. @endif Nothing was paused.

{{ $analysis['summary'] }}

@if(! empty($analysis['recommendations'])) @endif
@endif @if($scheduledStarts->isNotEmpty())

Scheduled starts

Explicit start times. Tools does not check Deal holds. Failed rows stay failed — they are not retried.

@endif @if(empty($campaigns) && ! $loadError)

@if($show === 'on') No campaigns are on. The On filter matches Ads Manager (toggle On + delivering). Off campaigns are in the Off tab. @elseif($show === 'off') No off campaigns. @else No campaigns on this ad account. @endif

@elseif(! empty($campaigns))

@if($show === 'on') {{ count($campaigns) }} on now @elseif($show === 'off') {{ count($campaigns) }} off @else {{ count($campaigns) }} campaigns @endif

@foreach($campaigns as $c) @php $id = (string) ($c['id'] ?? ''); $isOn = ! empty($c['is_on']); $effective = strtoupper((string) ($c['effective_status'] ?? '')); $budget = $c['daily_budget'] ?? null; $budgetKind = 'day'; if ($budget === null && ($c['lifetime_budget'] ?? null) !== null) { $budget = $c['lifetime_budget']; $budgetKind = 'lifetime'; } $cardClass = 'ads-run'; if ($worstId && $id === (string) $worstId) { $cardClass .= ' ads-run--worst'; } elseif ($bestId && $id === (string) $bestId) { $cardClass .= ' ads-run--best'; } @endphp

{{ $c['name'] }}

{{ $c['objective_label'] ?? $c['objective'] }} @if(($c['active_adsets'] ?? 0) > 0) · {{ (int) $c['active_adsets'] }} ad set{{ (int) $c['active_adsets'] === 1 ? '' : 's' }} on @endif

@if($isOn && $effective === 'WITH_ISSUES') Issues @elseif($isOn && $effective === 'PENDING_REVIEW') In review @elseif($isOn) On @else Off @endif
Amount spent {!! $info('What Meta billed for this campaign in the selected date filter (Today, Last 14 days, Last 30 days, etc.). It is not lifetime spend and it is not the monthly cap.') !!}
{{ $money($c['spend'] ?? null) }}
Budget {!! $info('The limit you set in Meta for this campaign: per day or lifetime. If it says “ad sets”, the money is on the ad sets, not the campaign. This is a setting, not how much was already spent.') !!}
@if($budget === null) — @else {{ $money($budget) }}/ {{ $budgetKind }}{{ ($c['budget_source'] ?? '') === 'adsets' ? ' · ad sets' : '' }} @endif
{{ ! empty($c['multiple_conversions']) ? 'Results' : ($c['result_label'] ?? 'Results') }} {!! $info(! empty($c['multiple_conversions']) ? 'Ads Manager Results for the selected dates. This campaign has more than one optimization event on delivering ad sets, so Tools cannot show a single number (same as Ads Manager “Multiple conversions”).' : 'Ads Manager Results for the selected dates: the optimization event of the delivering ad set (for example Messaging conversations started or Website checkouts initiated). Not a guessed pixel event.') !!}
@if(! empty($c['multiple_conversions'])) — Multiple conversions @else {{ $qty($c['results'] ?? null, 1) }} @endif
Cost / result {!! $info('Spend divided by that same Ads Manager result, for the selected dates. Meta reports it from cost_per_action_type. If Results is “Multiple conversions”, this cannot be a single number.') !!}
{{ $money($c['cost_per_result'] ?? null) }} @if(empty($c['multiple_conversions']) && ($c['result_label'] ?? '') !== '' && ($c['result_label'] ?? '') !== 'Results') Per {{ $c['result_label'] }} @elseif(! empty($c['multiple_conversions'])) Multiple conversions @endif
@if(($c['roas'] ?? null) !== null)
ROAS {!! $info('Purchase return on ad spend from Meta for the selected dates (purchase value ÷ amount spent). Only shown when Meta returns it. Not invented.') !!}
{{ number_format((float) $c['roas'], 2) }}x
@endif
Impressions {!! $info('How many times the ads were shown in the selected date filter. One person can create several impressions.') !!}
{{ $qty($c['impressions'] ?? null) }}
Reach {!! $info('How many unique people saw the ads at least once in the selected date filter. Different from impressions: reach counts people, impressions count views.') !!}
{{ $qty($c['reach'] ?? null) }}
Frequency {!! $info('Average times each person saw the ads in the selected date filter (impressions ÷ reach). Example: 3.62 means the typical person saw the ads about 3.6 times.') !!}
{{ $qty($c['frequency'] ?? null, 2) }}
Link clicks {!! $info('Clicks on the ad link in the selected date filter, as Meta reports inline_link_clicks. Not every click on the ad — only the link.') !!}
{{ $qty($c['link_clicks'] ?? null) }}
CTR {!! $info('Click-through rate: link clicks ÷ impressions, as a percent, for the selected date filter. How often a view became a link click.') !!}
{{ $pct($c['link_ctr'] ?? null) }}
CPC {!! $info('Cost per link click for the selected date filter: amount spent ÷ link clicks, as Meta reports it.') !!}
{{ $money($c['cpc'] ?? null) }}
CPM {!! $info('Cost per 1,000 impressions for the selected date filter. What you pay to show the ads one thousand times.') !!}
{{ $money($c['cpm'] ?? null) }}
@if($isOn)
@csrf
@else
@csrf
@endif Verify in Meta
@php $cardSchedules = $schedulesByCampaign->get($id, collect()); $pendingStart = $cardSchedules->firstWhere('status', 'pending'); @endphp
@if($pendingStart)

Scheduled start: {{ $fmtWhen($pendingStart->activate_at) }}@if($pendingStart->end_at) · ends {{ $fmtWhen($pendingStart->end_at) }}@endif

@elseif($isOn)
@csrf

Campaign is already On. This only writes Meta stop_time — it does not create a scheduled start.

@else
@csrf

Times are {{ $adsDisplayTz }}. Scheduling a start is an explicit order and can turn the campaign On even after a Deal Pause.

@endif
@endforeach

Numbers on these cards come from Meta Insights for the selected dates. If Meta does not return a metric, Tools shows —. Tap Verify in Meta on any card to see Meta's raw answer field by field next to what Tools printed. AI Marketer pulls Meta again on every question — it does not read these cards. It never pauses or changes budget unless you tap Confirm.

@endif
@push('styles') @endpush @push('scripts') @endpush @endsection