Diff -- /var/www/vhosts/webstls.com/httpdocs/exp_track.cgi
Diff

/var/www/vhosts/webstls.com/httpdocs/exp_track.cgi

added on WebSTLs (webstls.com) at 2026-07-01 22:26:32

Added
+76
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to e5b3dbafb0cd
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1#!/usr/bin/perl
2#======================================================================
3# WebSTLs - Experiment event tracker (client-side).
4#
5# POSTed by storefront JS when a visitor interacts with an element under
6# test (a click on the hero CTA, a scroll past the section, etc.) and
7# also serves as a fallback for the exposure ping when the storefront
8# render path is bypassed (cached HTML, prerender).
9#
10# Form fields:
11# storefront_id (required) scope to one storefront so we only resolve
12# that storefronts running experiments
13# event_type (required) exposure | view | click | add_to_cart |
14# purchase | custom
15# value (optional) numeric, used for revenue events
16#
17# We do NOT take experiment_id from the client -- the server resolves
18# every active experiment for the storefront, derives the visitor
19# bucketing from the cookie, and logs one event per experiment. This
20# keeps the API simple and prevents clients from spoofing assignment.
21#======================================================================
22use strict;
23use warnings;
24
25use lib '/var/www/vhosts/webstls.com/httpdocs';
26use CGI;
27use MODS::DBConnect;
28use MODS::WebSTLs::Config;
29use MODS::WebSTLs::Experiments;
30
31my $q = CGI->new;
32my $db = MODS::DBConnect->new;
33my $cfg = MODS::WebSTLs::Config->new;
34my $ex = MODS::WebSTLs::Experiments->new;
35my $DB = $cfg->settings('database_name');
36
37$| = 1;
38
39# POST only; client tracker uses fetch(method:POST) or sendBeacon.
40if (($ENV{REQUEST_METHOD} || '') ne 'POST') {
41 print "Status: 405 Method Not Allowed\nContent-Type: text/plain\n\nPOST required\n";
42 exit;
43}
44
45my $form = $q->Vars;
46
47my $storefront_id = $form->{storefront_id} || 0;
48$storefront_id =~ s/[^0-9]//g;
49
50my $event_type = lc($form->{event_type} || '');
51$event_type =~ s/[^a-z_]//g;
52$event_type = 'custom' unless $event_type =~ /^(exposure|view|click|add_to_cart|purchase|custom)$/;
53
54my $value = $form->{value};
55$value = '' unless defined $value;
56$value =~ s/[^\d.]//g;
57$value = '' if length($value) > 12;
58
59# Visitor identity comes from the existing cookie. We do not mint one
60# here -- if the cookie is missing, the visitor has not been bucketed
61# yet and there is no event to record (their first render through
62# store.cgi will mint the cookie).
63my $tok = $ex->read_visitor($q);
64unless ($tok && $storefront_id) {
65 print "Content-Type: text/plain\nCache-Control: no-store\n\nok\n";
66 exit;
67}
68my $vh = $ex->visitor_hash($tok);
69
70my $dbh = $db->db_connect();
71$ex->log_event_for_visitor_experiments(
72 $db, $dbh, $DB, $storefront_id, $vh, $event_type, $value
73);
74$db->db_disconnect($dbh);
75
76print "Content-Type: text/plain\nCache-Control: no-store\n\nok\n";
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help