[object Object]

← back to Agent Ad Network

Add DW-network web display surface: /serve/display + /embed.js + /cp promo clicks + DW cross-promo pool (all ad links rel=nofollow sponsored)

d6af20ebb62f48cb596ae814ac086394504f7404 · 2026-08-04 11:09:05 -0700 · Steve Abrams

Files touched

Diff

commit d6af20ebb62f48cb596ae814ac086394504f7404
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Aug 4 11:09:05 2026 -0700

    Add DW-network web display surface: /serve/display + /embed.js + /cp promo clicks + DW cross-promo pool (all ad links rel=nofollow sponsored)
---
 assets/embed.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 server.js       | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+)

diff --git a/assets/embed.js b/assets/embed.js
new file mode 100644
index 0000000..5a5962d
--- /dev/null
+++ b/assets/embed.js
@@ -0,0 +1,62 @@
+/* DW Network display-ad embed — one line per site:
+   <script src="https://ads.agentabrams.com/embed.js"
+           data-slot="footer-strip|in-grid-card|sidebar-rail"
+           data-site="silkwallpaper.com" data-context="silk,wallcovering"></script>
+   Renders a "Sponsored" unit; every ad link is rel="nofollow sponsored" (never leaks
+   equity / never reads as a link network — see dw-fleet-seo-independent-ranking). */
+(function () {
+  var s = document.currentScript;
+  if (!s) return;
+  var slot = (s.getAttribute('data-slot') || 'footer-strip').toLowerCase();
+  var site = s.getAttribute('data-site') || location.hostname;
+  var ctx = s.getAttribute('data-context') || '';
+  var origin = new URL(s.src).origin;
+  var url = origin + '/serve/display?format=json&slot=' + encodeURIComponent(slot) +
+            '&site=' + encodeURIComponent(site) + '&context=' + encodeURIComponent(ctx);
+
+  fetch(url, { credentials: 'omit' }).then(function (r) { return r.json(); }).then(function (d) {
+    var ad = d && d.ad;
+    if (!ad) return; // fail-open: no fill → render nothing
+    var wrap = document.createElement('div');
+    wrap.className = 'dwad dwad-' + slot;
+    var link = '<a href="' + ad.clickUrl + '" target="_blank" rel="nofollow sponsored noopener">' +
+               '<span class="dwad-h">' + esc(ad.headline) + '</span> ' +
+               '<span class="dwad-b">' + esc(ad.body) + '</span></a>';
+    wrap.innerHTML =
+      '<span class="dwad-label">Sponsored</span>' + link +
+      '<span class="dwad-by">' + esc(ad.sponsor || '') + '</span>' +
+      (slot !== 'footer-strip' ? '<button class="dwad-x" aria-label="dismiss">×</button>' : '');
+
+    injectStyles(origin);
+    place(wrap, slot, s);
+    var x = wrap.querySelector('.dwad-x');
+    if (x) x.onclick = function () { wrap.remove(); };
+  }).catch(function () {});
+
+  function esc(t) { return String(t == null ? '' : t).replace(/[&<>"]/g, function (c) {
+    return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); }
+
+  function place(wrap, slot, script) {
+    if (slot === 'in-grid-card') {
+      // drop where the script tag sits (author places it inside the grid)
+      script.parentNode.insertBefore(wrap, script.nextSibling);
+    } else {
+      document.body.appendChild(wrap); // footer-strip / sidebar-rail = fixed via CSS
+    }
+  }
+
+  function injectStyles(origin) {
+    if (document.getElementById('dwad-css')) return;
+    var css = document.createElement('style'); css.id = 'dwad-css';
+    css.textContent =
+      '.dwad{font:13px/1.4 system-ui,sans-serif;color:#222;background:#faf7f0;border:1px solid #e6ddc8;box-sizing:border-box}' +
+      '.dwad a{color:#8b6914;text-decoration:none}.dwad a:hover{text-decoration:underline}' +
+      '.dwad-label{font-size:9px;letter-spacing:.08em;text-transform:uppercase;color:#a99;margin-right:8px}' +
+      '.dwad-h{font-weight:600}.dwad-by{font-size:11px;color:#a99;margin-left:8px}' +
+      '.dwad-x{border:0;background:none;font-size:16px;color:#a99;cursor:pointer;float:right;line-height:1}' +
+      '.dwad-footer-strip{position:fixed;left:0;right:0;bottom:0;z-index:9998;padding:8px 16px;text-align:center;box-shadow:0 -1px 6px rgba(0,0,0,.06)}' +
+      '.dwad-sidebar-rail{position:fixed;right:16px;bottom:16px;z-index:9998;max-width:280px;padding:12px;border-radius:8px;box-shadow:0 4px 14px rgba(0,0,0,.12)}' +
+      '.dwad-in-grid-card{padding:16px;border-radius:8px;min-height:120px;display:flex;flex-direction:column;justify-content:center}';
+    document.head.appendChild(css);
+  }
+})();
diff --git a/server.js b/server.js
index 569af7f..2a8513e 100644
--- a/server.js
+++ b/server.js
@@ -209,6 +209,36 @@ function pickAd(contextWords) {
   return scored[scored.length - 1].a;
 }
 
+// ---------- DW-network display surface (web ad slots on sister sites) ----------
+// Fill priority: a live PAID ad (billed) → a DW cross-promo → external (stub) → empty.
+let DW_PROMOS = loadJson(path.join(DATA, 'dw-promos.json'), []);
+function pickPromo() {
+  if (!DW_PROMOS.length) return null;
+  const tot = DW_PROMOS.reduce((s, p) => s + (p.weight || 1), 0);
+  let r = Math.random() * tot;
+  for (const p of DW_PROMOS) { r -= (p.weight || 1); if (r <= 0) return p; }
+  return DW_PROMOS[DW_PROMOS.length - 1];
+}
+// external/affiliate fallback hook — returns null until Steve wires a real feed (gated).
+function pickExternalFill() { return null; }
+function pickDisplayFill(context, req) {
+  const paid = pickAd(context);
+  if (paid) {
+    paid.spent_usd = +(paid.spent_usd + paid.cpm_usd / 1000).toFixed(6);
+    paid.impressions = (paid.impressions || 0) + 1;
+    if (paid.spent_usd >= paid.budget_usd) paid.status = 'exhausted';
+    saveAds();
+    logEvent({ type: 'impression', kind: 'display', adId: paid.id, advertiserId: paid.advertiserId, ip: clientIp(req) });
+    return { headline: paid.headline, body: paid.body, sponsor: paid.sponsor, clickUrl: `${PUBLIC_URL}/c/${paid.id}` };
+  }
+  const promo = pickPromo();
+  if (promo) {
+    logEvent({ type: 'impression', kind: 'promo', promoId: promo.id, ip: clientIp(req) });
+    return { headline: promo.headline, body: promo.body, sponsor: promo.sponsor, clickUrl: `${PUBLIC_URL}/cp/${promo.id}` };
+  }
+  return pickExternalFill();
+}
+
 const server = http.createServer(async (req, res) => {
   const u = new URL(req.url, `http://${req.headers.host || 'localhost'}`);
   const p = u.pathname;
@@ -235,6 +265,37 @@ const server = http.createServer(async (req, res) => {
       return res.end(`[ad] ${ad.headline} — ${ad.body}  →  ${clickUrl}\n`);
     }
 
+    // ---------- public: one-line embed script for sister sites ----------
+    if (req.method === 'GET' && p === '/embed.js') {
+      try {
+        const js = fs.readFileSync(path.join(__dirname, 'assets', 'embed.js'), 'utf8');
+        res.writeHead(200, { 'Content-Type': 'application/javascript; charset=utf-8',
+          'Access-Control-Allow-Origin': '*', 'Cache-Control': 'public, max-age=3600', ...SEC_HEADERS });
+        return res.end(js);
+      } catch (e) { res.writeHead(404, SEC_HEADERS); return res.end('// embed unavailable'); }
+    }
+
+    // ---------- public: serve a DISPLAY ad into a web slot (sister sites) ----------
+    if (req.method === 'GET' && p === '/serve/display') {
+      if (rateLimited(req, res, 'display', 240, 60000)) return;
+      const context = (u.searchParams.get('context') || '').toLowerCase().slice(0, 500).split(/[,\s]+/).filter(Boolean);
+      const fill = pickDisplayFill(context, req);
+      const H = { 'Access-Control-Allow-Origin': '*', ...SEC_HEADERS };
+      if (!fill) { res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', ...H }); return res.end(JSON.stringify({ ad: null })); }
+      res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', ...H });
+      return res.end(JSON.stringify({ ad: fill }));
+    }
+
+    // ---------- public: DW cross-promo click-through ----------
+    if (req.method === 'GET' && p.startsWith('/cp/')) {
+      if (rateLimited(req, res, 'click', 60, 60000)) return;
+      const promo = DW_PROMOS.find(x => x.id === p.slice(4));
+      const target = promo && validAdUrl(promo.target);
+      if (!target) return json(res, 404, { error: 'unknown promo' });
+      logEvent({ type: 'click', kind: 'promo', promoId: promo.id, ip: clientIp(req) });
+      res.writeHead(302, { Location: target, ...SEC_HEADERS }); return res.end();
+    }
+
     // ---------- public: click-through ----------
     if (req.method === 'GET' && p.startsWith('/c/')) {
       if (rateLimited(req, res, 'click', 60, 60000)) return;

← eb5205f README: public landing surface + domain-ownership note (ads.  ·  back to Agent Ad Network  ·  Add DW Display Network admin UI (/admin/display): KPIs, live ae1dde9 →