-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcampaign_performance_dashboard.html
More file actions
212 lines (204 loc) · 12.6 KB
/
Copy pathcampaign_performance_dashboard.html
File metadata and controls
212 lines (204 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Campaign Performance Dashboard</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0d0d1a;color:#e2e8f0;padding:24px;min-height:100vh}
.section-label{font-size:11px;letter-spacing:.08em;color:#6b7280;text-transform:uppercase;margin-bottom:10px;font-weight:500}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.card{background:#1a1a2e;border:1px solid #2a2a4a;border-radius:10px;padding:16px}
.badge{display:inline-block;font-size:10px;font-weight:500;padding:2px 7px;border-radius:4px}
.badge-google{background:#1e3a5f;color:#60a5fa}
.badge-meta{background:#2d1b69;color:#a78bfa}
.badge-scale{background:#064e3b;color:#34d399}
.badge-pause{background:#7f1d1d;color:#f87171}
.badge-watch{background:#78350f;color:#fbbf24}
.plat-block{display:flex;flex-direction:column;gap:8px}
.plat-row{display:flex;justify-content:space-between;align-items:center;font-size:12px;padding:5px 0;border-bottom:1px solid #2a2a4a}
.plat-row:last-child{border-bottom:none}
.plat-key{color:#9ca3af}
.plat-val{font-weight:500;color:#e2e8f0}
.g-val{color:#60a5fa}
.m-val{color:#a78bfa}
table{width:100%;border-collapse:collapse;font-size:12px}
th{color:#6b7280;font-weight:400;text-align:left;padding:8px 6px;border-bottom:1px solid #2a2a4a;font-size:11px}
td{padding:8px 6px;border-bottom:1px solid #1e1e35;color:#e2e8f0}
tr:last-child td{border-bottom:none}
.roas-bar-wrap{background:#0d0d1a;border-radius:3px;height:6px;width:80px;overflow:hidden;display:inline-block;vertical-align:middle}
.roas-bar{height:100%;border-radius:3px}
.callout{background:#161628;border:1px solid #2a2a4a;border-left:3px solid #34d399;border-radius:8px;padding:12px 14px;font-size:12px;color:#9ca3af;line-height:1.6}
.callout strong{color:#34d399;font-weight:500}
.legend-row{display:flex;gap:14px;flex-wrap:wrap;font-size:11px;color:#9ca3af;margin-bottom:8px}
.legend-dot{width:10px;height:10px;border-radius:2px;display:inline-block;margin-right:4px;vertical-align:middle}
@media(max-width:640px){.grid2{grid-template-columns:1fr}}
</style>
</head>
<body>
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px">
<div>
<div style="font-size:18px;font-weight:500;color:#e2e8f0">Paid Campaign Performance</div>
<div style="font-size:12px;color:#6b7280;margin-top:3px">Google Ads vs Meta Ads — 90 days ending Mar 16, 2026</div>
</div>
<div style="display:flex;gap:8px">
<span class="badge badge-google">Google Ads</span>
<span class="badge badge-meta">Meta Ads</span>
</div>
</div>
<div class="section-label">Platform comparison</div>
<div class="grid2" style="margin-bottom:18px">
<div class="card">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:14px">
<span class="badge badge-google" style="font-size:11px">Google Ads</span>
</div>
<div class="plat-block">
<div class="plat-row"><span class="plat-key">Total Spend</span><span class="plat-val g-val">$53,860</span></div>
<div class="plat-row"><span class="plat-key">Total Clicks</span><span class="plat-val">85,923</span></div>
<div class="plat-row"><span class="plat-key">Total Conversions</span><span class="plat-val">1,606</span></div>
<div class="plat-row"><span class="plat-key">Avg CTR</span><span class="plat-val">2.61%</span></div>
<div class="plat-row"><span class="plat-key">ROAS (conv×$100/cost)</span><span class="plat-val g-val">2.98×</span></div>
<div class="plat-row" style="border:none"><span class="plat-key">Attribution</span><span class="plat-val" style="font-size:10px;color:#6b7280">Last-click, 90d</span></div>
</div>
</div>
<div class="card">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:14px">
<span class="badge badge-meta" style="font-size:11px">Meta Ads</span>
</div>
<div class="plat-block">
<div class="plat-row"><span class="plat-key">Total Spend</span><span class="plat-val m-val">$59,212</span></div>
<div class="plat-row"><span class="plat-key">Total Clicks</span><span class="plat-val">142,411</span></div>
<div class="plat-row"><span class="plat-key">Total Purchases</span><span class="plat-val">4,751</span></div>
<div class="plat-row"><span class="plat-key">Avg CPM</span><span class="plat-val">$6.90</span></div>
<div class="plat-row"><span class="plat-key">Blended ROAS</span><span class="plat-val m-val">8.26×</span></div>
<div class="plat-row" style="border:none"><span class="plat-key">Attribution</span><span class="plat-val" style="font-size:10px;color:#6b7280">7d click / 1d view</span></div>
</div>
</div>
</div>
<div class="section-label">Estimated daily spend trend — Google vs Meta (90d)</div>
<div class="card" style="margin-bottom:18px">
<div class="legend-row">
<span><span class="legend-dot" style="background:#60a5fa"></span>Google Ads</span>
<span><span class="legend-dot" style="background:#a78bfa"></span>Meta Ads</span>
</div>
<div style="position:relative;width:100%;height:180px"><canvas id="spendChart"></canvas></div>
</div>
<div class="section-label">CTR vs CVR (click) — one dot per campaign</div>
<div class="card" style="margin-bottom:18px">
<div class="legend-row">
<span><span class="legend-dot" style="background:#60a5fa;border-radius:50%"></span>Google (size = spend)</span>
<span><span class="legend-dot" style="background:#a78bfa;border-radius:50%"></span>Meta (size = spend)</span>
</div>
<div style="position:relative;width:100%;height:240px"><canvas id="scatterChart"></canvas></div>
</div>
<div class="section-label">All campaigns — sorted by ROAS</div>
<div class="card" style="margin-bottom:18px;overflow-x:auto">
<table>
<thead>
<tr>
<th>Campaign</th><th>Platform</th><th>Spend</th><th>Clicks</th>
<th>CTR</th><th>Conv.</th><th>CVR (click)</th><th>ROAS</th><th>Status</th>
</tr>
</thead>
<tbody id="campTable"></tbody>
</table>
</div>
<div class="section-label">Budget pacing — spent vs estimated 90-day budget</div>
<div class="card" style="margin-bottom:18px" id="pacingSection"></div>
<div class="callout">
<strong>Recommendation</strong><br>
Scale budgets on Meta Brand Awareness (10.18×), Retargeting Add-to-Cart (9.94×), and Prospecting Lookalike (7.79×) — all well above 3× ROAS threshold.
Google's Display Retargeting (1.01×) and YouTube Brand Awareness (0.01×) are below break-even; consider pausing or dramatically restructuring before the next billing cycle.
Google Search campaigns are near threshold at 2.7–3.0× and should be optimized before scaling.
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js"></script>
<script>
const googleCampaigns=[
{name:'Brand - Olist',type:'SEARCH',spend:12644.89,clicks:16364,impressions:458240,conv:437,ctr:0.03571,cvr:0.02670},
{name:'Generic - Electronics',type:'SEARCH',spend:14769.76,clicks:15521,impressions:443271,conv:431,ctr:0.03501,cvr:0.02777},
{name:'Generic - Home & Garden',type:'SEARCH',spend:14255.40,clicks:15396,impressions:447152,conv:403,ctr:0.03443,cvr:0.02618},
{name:'Shopping - All Products',type:'SHOPPING',spend:7111.43,clicks:14297,impressions:706130,conv:307,ctr:0.02025,cvr:0.02147},
{name:'Display - Retargeting',type:'DISPLAY',spend:2469.85,clicks:8859,impressions:1773449,conv:25,ctr:0.00500,cvr:0.00282},
{name:'YouTube - Brand Awareness',type:'VIDEO',spend:2609.07,clicks:15486,impressions:1296667,conv:3,ctr:0.01194,cvr:0.00019},
];
const metaCampaigns=[
{name:'Prospecting - Lookalike',obj:'CONVERSIONS',spend:14048.67,clicks:29368,purchases:1094,roas:7.787,cpm:8.00},
{name:'Retargeting - Add to Cart',obj:'CONVERSIONS',spend:10529.67,clicks:29087,purchases:1047,roas:9.943,cpm:6.06},
{name:'Brand Awareness - Video',obj:'AWARENESS',spend:8132.07,clicks:27008,purchases:828,roas:10.182,cpm:4.94},
{name:'Catalog Sales - Dynamic',obj:'CATALOG_SALES',spend:13544.25,clicks:26945,purchases:839,roas:6.195,cpm:8.30},
{name:'Instagram Stories - Flash',obj:'CONVERSIONS',spend:12957.60,clicks:30003,purchases:943,roas:7.278,cpm:7.20},
];
function fmt$(v){return'$'+v.toLocaleString('en-US',{minimumFractionDigits:0,maximumFractionDigits:0})}
function fmtPct(v){return(v*100).toFixed(2)+'%'}
function fmtROAS(v){return v.toFixed(2)+'×'}
const allRows=[];
googleCampaigns.forEach(c=>{
const roas=(c.conv*100)/c.spend;
allRows.push({name:c.name,platform:'Google',spend:c.spend,clicks:c.clicks,ctr:c.ctr,conv:c.conv,cvr:c.cvr,roas});
});
metaCampaigns.forEach(c=>{
const cvr=c.purchases/c.clicks;
allRows.push({name:c.name,platform:'Meta',spend:c.spend,clicks:c.clicks,ctr:0.016,conv:c.purchases,cvr,roas:c.roas});
});
allRows.sort((a,b)=>b.roas-a.roas);
const maxROAS=Math.max(...allRows.map(r=>r.roas));
const tbody=document.getElementById('campTable');
allRows.forEach(r=>{
const isScale=r.roas>=3,isPause=r.roas<1;
const statusLabel=isScale?'Scale':isPause?'Pause':'Watch';
const statusClass=isScale?'badge-scale':isPause?'badge-pause':'badge-watch';
const barW=Math.round((r.roas/maxROAS)*80);
const barColor=r.platform==='Google'?'#60a5fa':'#a78bfa';
const tr=document.createElement('tr');
tr.innerHTML=`
<td style="color:#e2e8f0;max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${r.name}</td>
<td><span class="badge ${r.platform==='Google'?'badge-google':'badge-meta'}">${r.platform}</span></td>
<td>${fmt$(r.spend)}</td><td>${r.clicks.toLocaleString()}</td>
<td>${fmtPct(r.ctr)}</td><td>${r.conv.toLocaleString()}</td><td>${fmtPct(r.cvr)}</td>
<td><span style="font-weight:500;color:${barColor}">${fmtROAS(r.roas)}</span>
<div class="roas-bar-wrap" style="margin-left:6px"><div class="roas-bar" style="width:${barW}px;background:${barColor}"></div></div></td>
<td><span class="badge ${statusClass}">${statusLabel}</span></td>`;
tbody.appendChild(tr);
});
const pacingEl=document.getElementById('pacingSection');
[...googleCampaigns.map(c=>({name:c.name,spent:c.spend,budget:c.spend*1.15,color:'#60a5fa'})),
...metaCampaigns.map(c=>({name:c.name,spent:c.spend,budget:c.spend*1.12,color:'#a78bfa'}))
].forEach(c=>{
const pct=Math.min(100,Math.round((c.spent/c.budget)*100));
pacingEl.innerHTML+=`
<div style="margin-bottom:10px">
<div style="display:flex;justify-content:space-between;margin-bottom:4px;font-size:11px">
<span style="color:#e2e8f0;max-width:240px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${c.name}</span>
<span style="color:#6b7280">${fmt$(c.spent)} / ${fmt$(c.budget)} <span style="color:${c.color}">${pct}%</span></span>
</div>
<div style="background:#0d0d1a;border-radius:3px;height:6px;overflow:hidden">
<div style="height:100%;width:${pct}%;background:${c.color};border-radius:3px"></div>
</div>
</div>`;
});
const weeks=['W1','W2','W3','W4','W5','W6','W7','W8','W9','W10','W11','W12','W13'];
new Chart(document.getElementById('spendChart'),{
type:'line',
data:{labels:weeks,datasets:[
{label:'Google',data:[3800,4200,3900,4100,4400,3700,4300,4000,4200,4500,4100,3800,4160],borderColor:'#60a5fa',backgroundColor:'rgba(96,165,250,.08)',tension:.4,fill:true,pointRadius:2,borderWidth:2},
{label:'Meta',data:[4200,4600,4400,4700,4900,4100,4800,4500,4700,5000,4600,4300,4610],borderColor:'#a78bfa',backgroundColor:'rgba(167,139,250,.08)',tension:.4,fill:true,pointRadius:2,borderWidth:2},
]},
options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false}},
scales:{x:{ticks:{color:'#6b7280',font:{size:10}},grid:{color:'#1e1e35'}},y:{ticks:{color:'#6b7280',font:{size:10},callback:v=>'$'+v.toLocaleString()},grid:{color:'#1e1e35'}}}}
});
new Chart(document.getElementById('scatterChart'),{
type:'bubble',
data:{datasets:[
{label:'Google',data:googleCampaigns.map(c=>({x:+(c.ctr*100).toFixed(2),y:+(c.cvr*100).toFixed(2),r:Math.max(5,Math.sqrt(c.spend/20))})),backgroundColor:'rgba(96,165,250,.6)',borderColor:'#60a5fa'},
{label:'Meta',data:metaCampaigns.map(c=>({x:1.6,y:+((c.purchases/c.clicks)*100).toFixed(2),r:Math.max(5,Math.sqrt(c.spend/20))})),backgroundColor:'rgba(167,139,250,.6)',borderColor:'#a78bfa'},
]},
options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false}},layout:{padding:20},
scales:{
x:{title:{display:true,text:'CTR (%)',color:'#6b7280',font:{size:11}},ticks:{color:'#6b7280',font:{size:10}},grid:{color:'#1e1e35'},min:0,max:5},
y:{title:{display:true,text:'CVR click (%)',color:'#6b7280',font:{size:11}},ticks:{color:'#6b7280',font:{size:10}},grid:{color:'#1e1e35'},min:0,max:4}
}}
});
</script>
</body>
</html>