Track the join funnel end-to-end through the self-enroll page
- Self-enroll pageviews now tracked as the "joinnow" event (track.js loaded on the page; server whitelist + admin tiles/columns extended) - A confirmed on-chain registration in the wallet-connect flow now auto-posts to the submit-id API, so every self-enroll join records a submission with source + clickid attribution and fires the purchase event and BeMob postback with no manual ID entry - Optional name/handle field on the join page feeds the submission and the team Telegram alert - Admin Traffic panel: Join-now views tile, Join-now -> Confirmed conversion, and a per-source Confirmed column for campaign-level ROI reading Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+5
-3
@@ -8,8 +8,8 @@ function statusClass(s){return `status status-${s}`}
|
||||
function pct(n,d){return d?`${Math.round((n/d)*100)}%`:'—'}
|
||||
function renderAnalytics(){
|
||||
const src=(state.analytics&&state.analytics.sources)||{};
|
||||
const tot={bridge:0,start:0,click:0,training:0,postback:0,purchase:0,join:0};
|
||||
const list=Object.entries(src).map(([name,r])=>{tot.bridge+=r.bridge||0;tot.start+=r.start||0;tot.click+=r.click||0;tot.training+=r.training||0;tot.postback+=r.postback||0;tot.purchase+=r.purchase||0;tot.join+=r.join||0;return{name,bridge:r.bridge||0,start:r.start||0,click:r.click||0,training:r.training||0,join:r.join||0}})
|
||||
const tot={bridge:0,start:0,click:0,training:0,postback:0,purchase:0,join:0,joinnow:0};
|
||||
const list=Object.entries(src).map(([name,r])=>{tot.bridge+=r.bridge||0;tot.start+=r.start||0;tot.click+=r.click||0;tot.training+=r.training||0;tot.postback+=r.postback||0;tot.purchase+=r.purchase||0;tot.join+=r.join||0;tot.joinnow+=r.joinnow||0;return{name,bridge:r.bridge||0,start:r.start||0,click:r.click||0,training:r.training||0,join:r.join||0,joinnow:r.joinnow||0,purchase:r.purchase||0}})
|
||||
.sort((a,b)=>b.click-a.click||b.start-a.start||b.bridge-a.bridge);
|
||||
document.getElementById('funnelStats').innerHTML=
|
||||
`<div class="fact"><small>Bridge views</small><strong>${tot.bridge}</strong></div>`+
|
||||
@@ -18,7 +18,9 @@ function renderAnalytics(){
|
||||
`<div class="fact"><small>Bridge → Start</small><strong>${pct(tot.start,tot.bridge)}</strong></div>`+
|
||||
`<div class="fact"><small>Start → Join</small><strong>${pct(tot.click,tot.start)}</strong></div>`+
|
||||
(tot.join?`<div class="fact"><small>Invite-page views</small><strong>${tot.join}</strong></div>`:'')+
|
||||
(tot.joinnow?`<div class="fact"><small>Join-now views</small><strong>${tot.joinnow}</strong></div>`:'')+
|
||||
(tot.purchase?`<div class="fact"><small>Confirmed joins</small><strong>${tot.purchase}</strong></div>`:'')+
|
||||
(tot.joinnow&&tot.purchase?`<div class="fact"><small>Join-now → Confirmed</small><strong>${pct(tot.purchase,tot.joinnow)}</strong></div>`:'')+
|
||||
(tot.postback?`<div class="fact"><small>BeMob postbacks</small><strong>${tot.postback}</strong></div>`:'');
|
||||
const subs=state.submissions||[];
|
||||
document.getElementById('submissionRows').innerHTML=subs.map(s=>{
|
||||
@@ -26,7 +28,7 @@ function renderAnalytics(){
|
||||
const oc=s.onchain?(s.onchain.registered?`${path}<span style="color:var(--ok)">✓ ${esc(s.onchain.tier||'')} · ref #${esc(String(s.onchain.referrerId??'?'))}</span>`:'<span style="color:var(--danger)">✗ not found</span>'):'—';
|
||||
return `<tr><td>${esc((s.ts||'').replace('T',' ').slice(0,16))}</td><td>${esc(s.memberName||'—')}</td><td><strong>${esc(s.newId)}</strong></td><td>ID ${esc(s.sponsorId)}</td><td>${esc(s.source)}</td><td>${oc}</td></tr>`;
|
||||
}).join('')||'<tr><td colspan="6" class="empty">No submissions yet.</td></tr>';
|
||||
document.getElementById('trafficRows').innerHTML=list.map(r=>`<tr><td><strong>${esc(r.name)}</strong></td><td>${r.bridge}</td><td>${r.start}</td><td>${r.training}</td><td>${r.join}</td><td>${r.click}</td><td>${pct(r.click,r.start)}</td></tr>`).join('')||'<tr><td colspan="7" class="empty">No traffic recorded yet.</td></tr>';
|
||||
document.getElementById('trafficRows').innerHTML=list.map(r=>`<tr><td><strong>${esc(r.name)}</strong></td><td>${r.bridge}</td><td>${r.start}</td><td>${r.training}</td><td>${r.join}</td><td>${r.joinnow}</td><td>${r.click}</td><td>${r.purchase?`<strong style="color:var(--ok)">${r.purchase}</strong>`:0}</td><td>${pct(r.click,r.start)}</td></tr>`).join('')||'<tr><td colspan="9" class="empty">No traffic recorded yet.</td></tr>';
|
||||
}
|
||||
function esc(s){return String(s??'').replace(/[&<>'"]/g,c=>({'&':'&','<':'<','>':'>',"'":''','"':'"'}[c]))}
|
||||
function render(){
|
||||
|
||||
Reference in New Issue
Block a user