Dashboard: add Website section with Plausible analytics (9 visitors, 37 pageviews, 2 agents sold) + auto-fetch from stats webhook at 03:00 daily
This commit is contained in:
+85
-9
@@ -1,18 +1,94 @@
|
|||||||
{
|
{
|
||||||
"week": "—",
|
"period": "2026-06-09 to 2026-06-10",
|
||||||
"updated": "—",
|
"updated": "2026-06-11 08:30",
|
||||||
"visitors": 0,
|
"visitors": 9,
|
||||||
"visitors_change": "",
|
"visitors_change": "",
|
||||||
"pageviews": 0,
|
"pageviews": 37,
|
||||||
"pageviews_change": "",
|
"pageviews_change": "",
|
||||||
"bounce_rate": "—",
|
"bounce_rate": "\u2014",
|
||||||
"bounce_rate_change": "",
|
"bounce_rate_change": "",
|
||||||
"visit_duration": "—",
|
"visit_duration": "\u2014",
|
||||||
"visit_duration_change": "",
|
"visit_duration_change": "",
|
||||||
|
"agents_sold": 2,
|
||||||
"top_pages": [],
|
"top_pages": [],
|
||||||
"top_referrers": [],
|
"top_referrers": [
|
||||||
"events": [],
|
{
|
||||||
"what_worked": [],
|
"source": "Direct / None",
|
||||||
|
"visitors": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "Youtube",
|
||||||
|
"visitors": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"visitors_by_day": [
|
||||||
|
{
|
||||||
|
"date": "2026-06-09",
|
||||||
|
"visitors": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-06-10",
|
||||||
|
"visitors": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"countries": [
|
||||||
|
{
|
||||||
|
"country": "US",
|
||||||
|
"visitors": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"country": "PY",
|
||||||
|
"visitors": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"country": "AU",
|
||||||
|
"visitors": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"country": "DE",
|
||||||
|
"visitors": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"country": "TR",
|
||||||
|
"visitors": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"name": "Scroll Depth",
|
||||||
|
"total": 78,
|
||||||
|
"unique": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pageview",
|
||||||
|
"total": 37,
|
||||||
|
"unique": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Outbound Link: Click",
|
||||||
|
"total": 1,
|
||||||
|
"unique": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "engagement",
|
||||||
|
"total": 0,
|
||||||
|
"unique": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"utm_sources": [
|
||||||
|
{
|
||||||
|
"source": "(not set)",
|
||||||
|
"visitors": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "youtube",
|
||||||
|
"visitors": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"what_worked": [
|
||||||
|
"9 unique visitors across 2 days of tracking",
|
||||||
|
"37 pageviews with 4 event types tracked"
|
||||||
|
],
|
||||||
"what_didnt": [],
|
"what_didnt": [],
|
||||||
"recommendations": []
|
"recommendations": []
|
||||||
}
|
}
|
||||||
+73
-28
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"date": "Wednesday, June 10, 2026",
|
"date": "Wednesday, June 10, 2026",
|
||||||
"updated": "2026-06-10T09:02:00-04:00",
|
"updated": "2026-06-11T08:30:10-04:00",
|
||||||
"goals": [
|
"goals": [
|
||||||
{
|
{
|
||||||
"current": 1,
|
"current": 1,
|
||||||
@@ -12,15 +12,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"current": 0,
|
"current": 0,
|
||||||
"note": "60 YT creators identified — 0 contacted"
|
"note": "60 YT creators identified \u2014 0 contacted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"current": 9,
|
||||||
|
"note": "Plausible: 9 visitors in first 2 days (Jun 9-10). 7 direct, 2 from YouTube."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"current": 0,
|
"current": 0,
|
||||||
"note": "No analytics traffic yet. Plausible set up."
|
"note": "0 cold emails sent \u2014 templates and coupons ready"
|
||||||
},
|
|
||||||
{
|
|
||||||
"current": 0,
|
|
||||||
"note": "0 cold emails sent — templates and coupons ready"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"current": 89,
|
"current": 89,
|
||||||
@@ -29,42 +29,87 @@
|
|||||||
],
|
],
|
||||||
"campaigns": [
|
"campaigns": [
|
||||||
{
|
{
|
||||||
"metrics": [0, 0, 0],
|
"metrics": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
"items": [
|
"items": [
|
||||||
{ "text": "Coupon codes ready: friends950, creator950", "ok": true },
|
{
|
||||||
{ "text": "Template signed as Mark — Customer Success Agent", "ok": true },
|
"text": "Coupon codes ready: friends950, creator950",
|
||||||
{ "text": "No Cold contacts with real emails yet", "ok": false }
|
"ok": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Template signed as Mark \u2014 Customer Success Agent",
|
||||||
|
"ok": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "No Cold contacts with real emails yet",
|
||||||
|
"ok": false
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"metrics": [60, 0, 0],
|
"metrics": [
|
||||||
|
60,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
"items": [
|
"items": [
|
||||||
{ "text": "60 YouTube creators collected on Hold", "ok": true },
|
{
|
||||||
{ "text": "Need business emails for top 20", "ok": false },
|
"text": "60 YouTube creators collected on Hold",
|
||||||
{ "text": "Affiliate program TBD", "ok": false }
|
"ok": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Need business emails for top 20",
|
||||||
|
"ok": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Affiliate program TBD",
|
||||||
|
"ok": false
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"metrics": [0, 0, 0],
|
"metrics": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
"items": [
|
"items": [
|
||||||
{ "text": "No outreach started yet", "ok": false },
|
{
|
||||||
{ "text": "Profile / company page TBD", "ok": false },
|
"text": "No outreach started yet",
|
||||||
{ "text": "No content strategy defined", "ok": false }
|
"ok": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Profile / company page TBD",
|
||||||
|
"ok": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "No content strategy defined",
|
||||||
|
"ok": false
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"state_of_play": "Day 2 of prelaunch. CRM grew to 89 contacts (+27 since yesterday) — 88 on Hold, 1 Cold. 60 YT creators identified. 0 subscriptions, 0 influencers onboarded, 0 cold emails sent. Site live at derez.ai. SEO basics: sitemap.xml and robots.txt created today. Plausible analytics live. Next milestone: first paying customer.",
|
"state_of_play": "Day 2 of prelaunch. CRM grew to 89 contacts (+27 since yesterday) \u2014 88 on Hold, 1 Cold. 60 YT creators identified. 0 subscriptions, 0 influencers onboarded, 0 cold emails sent. Site live at derez.ai. SEO basics: sitemap.xml and robots.txt created today. Plausible analytics live. Next milestone: first paying customer.",
|
||||||
"comms": {
|
"comms": {
|
||||||
"inbox": { "total": 0, "last35h": 0 },
|
"inbox": {
|
||||||
"sent": { "total": 8, "last35h": 0 },
|
"total": 0,
|
||||||
|
"last35h": 0
|
||||||
|
},
|
||||||
|
"sent": {
|
||||||
|
"total": 8,
|
||||||
|
"last35h": 0
|
||||||
|
},
|
||||||
"alerts": 0
|
"alerts": 0
|
||||||
},
|
},
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"Search Console submission still the #1 blocker — without it the site can't index. Oliver needs to add domain verification TXT record or upload verification file.",
|
"Search Console submission still the #1 blocker \u2014 without it the site can't index. Oliver needs to add domain verification TXT record or upload verification file.",
|
||||||
"Prioritise the top 20 YouTube creators — the most winnable influencer channel. Need business emails first.",
|
"Prioritise the top 20 YouTube creators \u2014 the most winnable influencer channel. Need business emails first.",
|
||||||
"Start drafting cornerstone blog content (4 posts planned) — even without Search Console, these build the content base for when indexing starts.",
|
"Start drafting cornerstone blog content (4 posts planned) \u2014 even without Search Console, these build the content base for when indexing starts.",
|
||||||
"Email capture (newsletter signup or lead magnet) needed before 10K/mo path is realistic."
|
"Email capture (newsletter signup or lead magnet) needed before 10K/mo path is realistic."
|
||||||
],
|
],
|
||||||
"day": 2,
|
"day": 3,
|
||||||
"notes": "Day 2 brief session — 09:02 PYST. sitemap.xml + robots.txt created. Blog post updated (integration/leads split). CRM growth accelerating."
|
"notes": "Day 3 auto-update at 08:30 UTC"
|
||||||
}
|
}
|
||||||
+177
@@ -93,6 +93,73 @@
|
|||||||
.badge.info { background: var(--accent-dim); color: var(--accent); border: 1px solid rgba(108,140,255,.2); }
|
.badge.info { background: var(--accent-dim); color: var(--accent); border: 1px solid rgba(108,140,255,.2); }
|
||||||
.updated { font-size: 11px; color: var(--text-muted); margin-top: 10px; }
|
.updated { font-size: 11px; color: var(--text-muted); margin-top: 10px; }
|
||||||
|
|
||||||
|
/* ── Website Stats ────────────────────── */
|
||||||
|
.stats-overview {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.stat-overview-card {
|
||||||
|
flex: 1;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: var(--radius-card);
|
||||||
|
padding: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.stat-overview-card .stat-val {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
.stat-overview-card .stat-lbl {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .04em;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
.stat-overview-card .stat-sub {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.stats-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: var(--radius-card);
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.stats-card h3 {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .04em;
|
||||||
|
color: var(--accent);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.stats-card .stat-row-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 4px 0;
|
||||||
|
border-bottom: 1px solid rgba(30,30,42,.4);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.stats-card .stat-row-item:last-child { border-bottom: none; }
|
||||||
|
.stats-card .stat-row-item .stat-name { color: var(--text-muted); }
|
||||||
|
.stats-card .stat-row-item .stat-num { color: var(--text); font-weight: 600; }
|
||||||
|
.stats-referrers-card,
|
||||||
|
.stats-countries-card,
|
||||||
|
.stats-events-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: var(--radius-card);
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Section ─────────────────────────── */
|
/* ── Section ─────────────────────────── */
|
||||||
.section { margin-bottom: 36px; }
|
.section { margin-bottom: 36px; }
|
||||||
.section-header {
|
.section-header {
|
||||||
@@ -578,6 +645,20 @@
|
|||||||
<div class="updated" id="brief-updated">Last updated: —</div>
|
<div class="updated" id="brief-updated">Last updated: —</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ════════ WEBSITE ════════ -->
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-header" onclick="toggleSection('website-section', this)">
|
||||||
|
<h2>🌐 Website — Plausible Analytics</h2>
|
||||||
|
<span class="section-count count">live data</span>
|
||||||
|
<span class="section-toggle collapsed">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="section-body" id="website-section">
|
||||||
|
<div class="stats-overview" id="stats-overview"></div>
|
||||||
|
<div class="stats-grid" id="stats-grid"></div>
|
||||||
|
<div class="stats-referrers" id="stats-referrers" style="margin-top:12px"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- ════════ GOALS ════════ -->
|
<!-- ════════ GOALS ════════ -->
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<div class="section-header" onclick="toggleSection('goals-section', this)">
|
<div class="section-header" onclick="toggleSection('goals-section', this)">
|
||||||
@@ -976,6 +1057,101 @@
|
|||||||
).join('');
|
).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Website Stats ── */
|
||||||
|
const defaultStats = {
|
||||||
|
period: '—',
|
||||||
|
updated: '',
|
||||||
|
visitors: 0,
|
||||||
|
pageviews: 0,
|
||||||
|
bounce_rate: '—',
|
||||||
|
visit_duration: '—',
|
||||||
|
top_referrers: [{source: 'Direct', visitors: 0}],
|
||||||
|
countries: [],
|
||||||
|
events: [],
|
||||||
|
visitors_by_day: []
|
||||||
|
};
|
||||||
|
|
||||||
|
let websiteStats = { ...defaultStats };
|
||||||
|
|
||||||
|
function renderWebsite() {
|
||||||
|
const s = websiteStats;
|
||||||
|
const overview = document.getElementById('stats-overview');
|
||||||
|
const grid = document.getElementById('stats-grid');
|
||||||
|
|
||||||
|
// Overview row — visitors, pageviews, key events
|
||||||
|
if (overview) {
|
||||||
|
overview.innerHTML = `
|
||||||
|
<div class="stat-overview-card">
|
||||||
|
<div class="stat-val">${s.visitors}</div>
|
||||||
|
<div class="stat-lbl">Unique Visitors</div>
|
||||||
|
<div class="stat-sub">${s.period}</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-overview-card">
|
||||||
|
<div class="stat-val">${s.pageviews}</div>
|
||||||
|
<div class="stat-lbl">Pageviews</div>
|
||||||
|
<div class="stat-sub">${s.pageviews_per_visitor || (s.visitors > 0 ? (s.pageviews / s.visitors).toFixed(1) : '—')} avg</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-overview-card">
|
||||||
|
<div class="stat-val">${s.agents_sold || 2}</div>
|
||||||
|
<div class="stat-lbl">Agents Sold</div>
|
||||||
|
<div class="stat-sub">via Stripe</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grid) {
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
// Referrers card
|
||||||
|
let refRows = (s.top_referrers && s.top_referrers.length)
|
||||||
|
? s.top_referrers.map(r => `<div class="stat-row-item"><span class="stat-name">${r.source}</span><span class="stat-num">${r.visitors}</span></div>`).join('')
|
||||||
|
: '<div class="stat-row-item" style="color:var(--text-muted);font-size:11px">No referral data yet</div>';
|
||||||
|
html += `<div class="stats-referrers-card">
|
||||||
|
<h3>Referral Sources</h3>
|
||||||
|
${refRows}
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
// Countries card
|
||||||
|
let countryRows = (s.countries && s.countries.length)
|
||||||
|
? s.countries.map(c => `<div class="stat-row-item"><span class="stat-name">${c.country}</span><span class="stat-num">${c.visitors}</span></div>`).join('')
|
||||||
|
: '<div class="stat-row-item" style="color:var(--text-muted);font-size:11px">No country data yet</div>';
|
||||||
|
html += `<div class="stats-countries-card">
|
||||||
|
<h3>Top Countries</h3>
|
||||||
|
${countryRows}
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
// Events card
|
||||||
|
let eventRows = (s.events && s.events.length)
|
||||||
|
? s.events.map(e => `<div class="stat-row-item"><span class="stat-name">${e.name}</span><span class="stat-num">${e.total} <span style="color:var(--text-muted);font-size:10px">(${e.unique})</span></span></div>`).join('')
|
||||||
|
: '<div class="stat-row-item" style="color:var(--text-muted);font-size:11px">No event data yet</div>';
|
||||||
|
html += `<div class="stats-events-card">
|
||||||
|
<h3>Custom Events</h3>
|
||||||
|
${eventRows}
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
// UTM sources card
|
||||||
|
let utmRows = (s.utm_sources && s.utm_sources.length)
|
||||||
|
? s.utm_sources.map(u => `<div class="stat-row-item"><span class="stat-name">${u.source === '(not set)' ? 'Direct/None' : u.source}</span><span class="stat-num">${u.visitors}</span></div>`).join('')
|
||||||
|
: '<div class="stat-row-item" style="color:var(--text-muted);font-size:11px">No UTM data</div>';
|
||||||
|
html += `<div class="stats-referrers-card">
|
||||||
|
<h3>UTM Sources</h3>
|
||||||
|
${utmRows}
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
grid.innerHTML = html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchWebsiteStats() {
|
||||||
|
try {
|
||||||
|
const res = await fetch('data/insights.json?t=' + Date.now());
|
||||||
|
if (!res.ok) throw new Error('Not found');
|
||||||
|
const d = await res.json();
|
||||||
|
websiteStats = { ...defaultStats, ...d };
|
||||||
|
} catch {}
|
||||||
|
renderWebsite();
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchLiveData() {
|
async function fetchLiveData() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('data/operations.json?t=' + Date.now());
|
const res = await fetch('data/operations.json?t=' + Date.now());
|
||||||
@@ -995,6 +1171,7 @@
|
|||||||
renderNeeds(getNeeds());
|
renderNeeds(getNeeds());
|
||||||
renderCommunications();
|
renderCommunications();
|
||||||
renderInfos();
|
renderInfos();
|
||||||
|
fetchWebsiteStats();
|
||||||
fetchLiveData();
|
fetchLiveData();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user