Traffic sources: referring domain on join-link visits and joins (per-member table), click sources per campaign (surface or outside host)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -500,11 +500,12 @@ const server = http.createServer(async (req, res) => {
|
||||
const cookies = parseCookies(req);
|
||||
const angle = String(u.searchParams.get('v') || '').toLowerCase();
|
||||
const ang = JOIN_ANGLES[angle] || null;
|
||||
if (req.method === 'GET') coach.recordView(tok, ang ? angle : ''); // link stats per angle
|
||||
if (req.method === 'GET') coach.recordView(tok, ang ? angle : '', req.headers.referer); // link stats per angle + source
|
||||
const cookieTail = `; Path=/; SameSite=Lax; Max-Age=${180 * 24 * 3600}${IS_PROD ? '; Secure' : ''}`;
|
||||
const set = [];
|
||||
if (!cookies['iap.sponsor']) set.push('iap.sponsor=' + tok + cookieTail);
|
||||
if (ang) set.push('iap.angle=' + angle + cookieTail);
|
||||
if (!cookies['iap.ref']) set.push('iap.ref=' + encodeURIComponent(coach.refHost(req.headers.referer)) + cookieTail); // first-touch source
|
||||
return serveJoinPage(res, tok, ang ? angle : '', ang, set);
|
||||
}
|
||||
if (p === '/unsubscribe' && req.method === 'GET') {
|
||||
@@ -676,7 +677,8 @@ const server = http.createServer(async (req, res) => {
|
||||
emailCodes.delete(e);
|
||||
const ref = parseCookies(req)['iap.sponsor'] || '';
|
||||
const via = parseCookies(req)['iap.angle'] || '';
|
||||
const r = await accounts.ensure(e, ref, via); // first touch wins; existing accounts unchanged
|
||||
const joinedRef = decodeURIComponent(parseCookies(req)['iap.ref'] || '') || null;
|
||||
const r = await accounts.ensure(e, ref, via, joinedRef); // first touch wins; existing accounts unchanged
|
||||
if (r.error) return json(res, 400, r);
|
||||
// the lead is in the door: queue the getting-started sequence (opt-in box is pre-checked on both forms)
|
||||
if (r.created && (b.followups || b.newsletter)) drip.enqueue(e, ref, via).catch(() => {});
|
||||
@@ -1542,6 +1544,7 @@ const server = http.createServer(async (req, res) => {
|
||||
if (m && req.method === 'GET') {
|
||||
const target = await ads.click(m[1]);
|
||||
if (!target) { res.writeHead(404, baseHeaders()); return res.end(); }
|
||||
coach.recordClick(m[1], req.headers.referer); // where the click happened
|
||||
res.writeHead(302, baseHeaders({ Location: target }));
|
||||
return res.end();
|
||||
}
|
||||
@@ -1550,6 +1553,7 @@ const server = http.createServer(async (req, res) => {
|
||||
if (!s || !s.email) return json(res, 401, { error: 'Sign in first.' });
|
||||
const memberId = await auth.refreshMemberId(s);
|
||||
const out = { campaigns: await ads.listCampaigns(s.email), rates: ads.rates(), bannerSizes: ads.bannerSizes() };
|
||||
out.clickSources = await coach.clickSources(out.campaigns.map(c => c.id));
|
||||
const pool = await ads.pooledCredits((await myMemberIds(s)).ids);
|
||||
out.purchasedCredits = pool.total;
|
||||
out.largestPosition = pool.best.avail; // a single campaign budget has to fit one position
|
||||
|
||||
Reference in New Issue
Block a user