JavaScript (Node)
// Your server. The page posts the confirm tap to /api/confirm as JSON:
// { "click_id": "c_8f2k1x", "challenge_token": "...", "address": { "street": "123 Main St", ... } }
// and then goes wherever the answer's "go" field points.
// Node 18 or newer: built-in http and fetch, nothing to install.
var http = require('http');
var fs = require('fs');
var EXIT_URL = process.env.EXIT_URL; // your kind exit page
var TRACKING_LINK = process.env.TRACKING_LINK; // your tracking link, as we gave it to you
var MAX_PER_HOUR = Number(process.env.MAX_PER_HOUR); // set both yourself,
var MIN_SECONDS = Number(process.env.MIN_SECONDS); // then tune them after a week of logs
if (!MAX_PER_HOUR || !MIN_SECONDS) throw new Error('Set MAX_PER_HOUR and MIN_SECONDS');
// Data-center and hosting network ranges, from a list you trust. A prefix match keeps it simple.
var DATACENTER_PREFIXES = (process.env.DATACENTER_PREFIXES || '').split(',').filter(Boolean);
var clicks = new Map(); // click_id: the record your click logger wrote. Use your database.
var perIp = new Map(); // client IP: { count, until }
// Any invisible human-check provider: send its token and your secret key to its verify address.
function challengePassed(token) {
var form = new URLSearchParams({ secret: process.env.CHALLENGE_SECRET, response: token || '' });
return fetch(process.env.CHALLENGE_VERIFY_URL, { method: 'POST', body: form })
.then(function (res) { return res.json(); })
.then(function (answer) { return answer.success === true; })
.catch(function () { return false; });
}
function isDatacenterNetwork(ip) {
return DATACENTER_PREFIXES.some(function (prefix) { return ip.indexOf(prefix) === 0; });
}
function overRateLimit(ip) {
var now = Date.now();
var h = perIp.get(ip);
if (!h || h.until < now) {
h = { count: 0, until: now + 60 * 60 * 1000 };
perIp.set(ip, h);
}
h.count += 1;
return MAX_PER_HOUR < h.count;
}
// One line per step per visitor, the same names you fire to your pixel.
function log(event, click, zip) {
var line = { click_id: click.click_id, event: event, time: new Date().toISOString(), zip: zip };
fs.appendFile('events.log', JSON.stringify(line) + '\n', function () {});
}
function buildHandoffLink(click, address) {
var url = new URL(TRACKING_LINK);
url.searchParams.set('sub1', click.source);
url.searchParams.set('sub2', click.click_id);
url.searchParams.set('sub3', click.ad_id);
url.searchParams.set('street', address.street || '');
url.searchParams.set('city', address.city || '');
url.searchParams.set('state', String(address.state || '').toUpperCase().slice(0, 2));
url.searchParams.set('zip', String(address.zip || '').slice(0, 5));
return url.toString();
}
function reply(res, go) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ go: go }));
}
function readJson(req) {
return new Promise(function (resolve) {
var body = '';
req.on('data', function (chunk) { body += chunk; });
req.on('end', function () {
try { resolve(JSON.parse(body)); } catch (e) { resolve({}); }
});
});
}
http.createServer(function (req, res) {
if (req.method !== 'POST' || req.url !== '/api/confirm') { res.writeHead(404); return res.end(); }
var ip = req.socket.remoteAddress; // behind a proxy, read the address your proxy forwards
readJson(req).then(function (body) {
var click = clicks.get(body.click_id);
var address = body.address || {};
if (!click) return reply(res, EXIT_URL);
return challengePassed(body.challenge_token).then(function (passed) {
if (!passed) return reply(res, EXIT_URL);
if (isDatacenterNetwork(ip)) return reply(res, EXIT_URL);
if (overRateLimit(ip)) return reply(res, EXIT_URL);
if ((Date.now() - Date.parse(click.time)) / 1000 < MIN_SECONDS) return reply(res, EXIT_URL);
click.counted = true;
log('address_confirmed', click, String(address.zip || '').slice(0, 5));
reply(res, buildHandoffLink(click, address));
});
});
}).listen(Number(process.env.PORT || 3000));
Python
# Your server. The page posts the confirm tap to /api/confirm as JSON:
# {"click_id": "c_8f2k1x", "challenge_token": "...", "address": {"street": "123 Main St", ...}}
# and then goes wherever the answer's "go" field points.
# Python 3 standard library only.
import json, os, time
from datetime import datetime, timezone
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import urlsplit, urlunsplit, parse_qsl, urlencode
from urllib.request import urlopen
EXIT_URL = os.environ["EXIT_URL"] # your kind exit page
TRACKING_LINK = os.environ["TRACKING_LINK"] # your tracking link, as we gave it to you
MAX_PER_HOUR = int(os.environ["MAX_PER_HOUR"]) # set both yourself,
MIN_SECONDS = float(os.environ["MIN_SECONDS"]) # then tune them after a week of logs
# Data-center and hosting network ranges, from a list you trust. A prefix match keeps it simple.
DATACENTER_PREFIXES = [p for p in os.environ.get("DATACENTER_PREFIXES", "").split(",") if p]
clicks = {} # click_id: the record your click logger wrote. Use your database.
per_ip = {} # client IP: (count, until)
# Any invisible human-check provider: send its token and your secret key to its verify address.
def challenge_passed(token):
form = urlencode({"secret": os.environ["CHALLENGE_SECRET"], "response": token or ""}).encode()
try:
with urlopen(os.environ["CHALLENGE_VERIFY_URL"], data=form, timeout=5) as r:
return json.load(r).get("success") is True
except Exception:
return False
def is_datacenter_network(ip):
return any(ip.startswith(prefix) for prefix in DATACENTER_PREFIXES)
def over_rate_limit(ip):
now = time.time()
count, until = per_ip.get(ip, (0, 0))
if until < now:
count, until = 0, now + 60 * 60
per_ip[ip] = (count + 1, until)
return MAX_PER_HOUR < count + 1
def seconds_since(iso_time):
then = datetime.strptime(iso_time, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
return (datetime.now(timezone.utc) - then).total_seconds()
# One line per step per visitor, the same names you fire to your pixel.
def log(event, click, zip_code):
line = {"click_id": click["click_id"], "event": event,
"time": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), "zip": zip_code}
with open("events.log", "a") as f:
f.write(json.dumps(line) + "\n")
def build_handoff_link(click, address):
parts = urlsplit(TRACKING_LINK)
query = dict(parse_qsl(parts.query))
query.update({
"sub1": click["source"], "sub2": click["click_id"], "sub3": click["ad_id"],
"street": address.get("street", ""), "city": address.get("city", ""),
"state": str(address.get("state", "")).upper()[:2], "zip": str(address.get("zip", ""))[:5],
})
return urlunsplit(parts._replace(query=urlencode(query)))
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
if self.path != "/api/confirm":
self.send_error(404)
return
try:
body = json.loads(self.rfile.read(int(self.headers.get("Content-Length", 0))))
except ValueError:
body = {}
ip = self.client_address[0] # behind a proxy, read the address your proxy forwards
click = clicks.get(body.get("click_id"))
address = body.get("address") or {}
if not click or not challenge_passed(body.get("challenge_token")):
return self.reply(EXIT_URL)
if is_datacenter_network(ip) or over_rate_limit(ip):
return self.reply(EXIT_URL)
if seconds_since(click["time"]) < MIN_SECONDS:
return self.reply(EXIT_URL)
click["counted"] = True
log("address_confirmed", click, str(address.get("zip", ""))[:5])
self.reply(build_handoff_link(click, address))
def reply(self, go):
data = json.dumps({"go": go}).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
ThreadingHTTPServer(("", int(os.environ.get("PORT", "3000"))), Handler).serve_forever()