File size: 46,744 Bytes
924ccaa d1ea040 216a890 d1ea040 924ccaa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>PCI Payment Script requirements — check payment scripts against pci</title>
<meta name="description" content="This free browser tool checks checkout and payment pages for the listed PCI DSS v4.0.1 script integrity, inventory, CSP authorization, and tamper-detection requirements.">
<style>
:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
.wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
.bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
.note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
</style>
<script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/pci-payment-script-lint"></head>
<body>
<div class="wrap">
<h1>PCI Payment Script requirements — check payment scripts against pci</h1>
<p class="lede">Lint checkout and payment pages against PCI DSS v4.0.1 requirements 6.4.3 and 11.6.1: script integrity, written script inventory, CSP authorisation, and weekly tamper detection. Runs entirely in your browser — nothing is uploaded.</p>
<textarea id="src" spellcheck="false"><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Pay — order #4417</title>
<!-- Compliance note: we are assessed under PCI DSS 4.0 (SAQ A). Requirements 6.4.3 and
11.6.1 are future-dated best practices, so a written script inventory is not required
here; the QSA said we can revisit at the next annual assessment. -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' *">
</head>
<body>
<h1>Payment</h1>
<form id="pay-form" method="post" action="/orders/4417/pay">
<input id="card-number" name="card_number" autocomplete="cc-number">
<input id="card-cvc" name="cvc" autocomplete="cc-csc">
<button id="pay" type="submit">Pay 49.00 EUR</button>
</form>
<script src="http://cdn.legacy-cart.example/cart.js"></script>
<script src="https://www.googletagmanager.com/gtm.js?id=GTM-77KQ2"></script>
<script src="https://cdn.jsdelivr.net/npm/card-validator@latest/dist/card-validator.min.js"></script>
<script src="https://js.stripe.com/v3/"></script>
<script src="https://widget.chat-support.example/loader.js" integrity="sha384-CcRt7pQnVx0LmEaZbYkJ9uFdHs2WgToIrN4vXqMePzSlBjUyKhAfDwCgNmXtQvRe"></script>
<script>
document.getElementById('pay').addEventListener('click', function () { window.dataLayer.push({ event: 'pay' }); });
</script>
</body>
</html></textarea>
<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
<div id="out" aria-live="polite"></div>
<div id="paid"><strong>Free here:</strong> Check the payment page open in your editor against every script rule and name the exact PCI DSS v4.0.1 requirement each finding breaks. <strong>In the editor:</strong> Sweep every checkout template in the workspace and write the dated 6.4.3 script inventory report you hand the assessor — that part asks for a licence key. <a id="buy" href="https://getreadystack.com/api/buy/cl/polar_cl_YLfFQJa9NbIbhJdjhg77rY07HqFCEhrFOmzmW3zHrI8">Get the full version — $29 once</a> <span class="note">$29 once · one licence key per person or team seat · PCI consultants and QSAs typically bill $150-$300 an hour for the same payment-page script review.</span></div>
<p class="note">Same engine as the VS Code extension, byte for byte.</p>
</div>
<script>var PCI_RULES = [
{
"id": "inventory-missing",
"sev": "error",
"req": "6.4.3",
"msg": "This page loads third-party scripts but carries no script inventory. 6.4.3 requires a written inventory of every script on the payment page, each with a business justification. Add a \u003c!-- pci-script-inventory --\u003e block listing each host."
},
{
"id": "script-not-inventoried",
"sev": "error",
"req": "6.4.3",
"msg": "Script host is not listed in the page's script inventory, so it is not an authorised script under 6.4.3."
},
{
"id": "inventory-no-justification",
"sev": "error",
"req": "6.4.3",
"msg": "Inventory entry has no usable business justification. 6.4.3 asks why each script is needed, in writing; placeholders do not count."
},
{
"id": "script-no-integrity",
"sev": "error",
"req": "6.4.3",
"msg": "External payment-page script has no integrity= hash, so there is no method assuring the script has not been altered in transit or at the origin (6.4.3)."
},
{
"id": "script-over-http",
"sev": "error",
"req": "6.4.3",
"msg": "Payment-page script is loaded over plain http://. Integrity cannot be assured and the content can be rewritten on the wire."
},
{
"id": "script-integrity-no-crossorigin",
"sev": "warn",
"req": "6.4.3",
"msg": "integrity= is present but crossorigin= is missing, so the browser will not run the integrity check the way you expect on a cross-origin script."
},
{
"id": "script-unpinned-version",
"sev": "warn",
"req": "6.4.3",
"msg": "Script URL points at a moving target (latest/next), so today's authorised script is not tomorrow's. Pin a version before hashing it."
},
{
"id": "tag-manager-on-payment-page",
"sev": "warn",
"req": "6.4.3",
"msg": "A tag manager or session-recording loader can inject further scripts at runtime, which means the authorised list is decided outside this file. Container contents have to be inventoried too."
},
{
"id": "csp-missing",
"sev": "error",
"req": "6.4.3",
"msg": "No Content-Security-Policy on this payment page. Without one there is no technical method confirming that only authorised scripts execute in the consumer's browser."
},
{
"id": "csp-unsafe-inline",
"sev": "error",
"req": "6.4.3",
"msg": "script-src allows 'unsafe-inline' or a wildcard, which authorises anything. That is the same as having no script authorisation at all."
},
{
"id": "csp-report-only",
"sev": "warn",
"req": "6.4.3",
"msg": "Only Content-Security-Policy-Report-Only is set. Report-only blocks nothing; it records and lets the script run."
},
{
"id": "inline-script-no-nonce",
"sev": "warn",
"req": "6.4.3",
"msg": "Inline script has no nonce= and no hash, so it can only run if the policy is loosened for every inline script on the page."
},
{
"id": "tamper-detection-missing",
"sev": "error",
"req": "11.6.1",
"msg": "No change- and tamper-detection mechanism is declared for this page. 11.6.1 wants alerts on unauthorised modification of the HTTP headers and of the payment page content. Declare it in a \u003c!-- pci-tamper-detection: ... --\u003e line or set a CSP report endpoint."
},
{
"id": "tamper-interval-too-long",
"sev": "error",
"req": "11.6.1",
"msg": "Tamper detection is evaluated less often than every seven days. 11.6.1 asks for at least weekly evaluation, or the interval your targeted risk analysis defends."
},
{
"id": "future-dated-claim-expired",
"sev": "error",
"req": "6.4.3 / 11.6.1",
"msg": "This page still describes the payment-script requirements as future-dated or optional. They stopped being best practice and became mandatory on 2025-03-31."
},
{
"id": "stale-standard-version",
"sev": "warn",
"req": "",
"msg": "This file cites a retired version of the standard. v4.0.1 is the only active version; v3.2.1 retired 2024-03-31 and v4.0 retired 2024-12-31."
}
]
;</script>
<script>// PCI DSS 6.4.3 Payment Script Lint — the brain. Same file runs in Node (extension) and in the browser (free web page).
'use strict';
var RULES = (typeof module !== 'undefined') ? require('./rules.json') : window.PCI_RULES;
var STANDARD = 'PCI DSS v4.0.1';
var MANDATORY_FROM = '2025-03-31';
var BY = {};
RULES.forEach(function (r) { BY[r.id] = r; });
function lineAt(text, idx) { return text.slice(0, idx).split('\n').length; }
function daysSince(from, today) {
var a = Date.parse(from + 'T00:00:00Z'), b = Date.parse(today + 'T00:00:00Z');
if (isNaN(a) || isNaN(b)) return null;
return Math.round((b - a) / 86400000);
}
function attr(attrs, name) {
var m = attrs.match(new RegExp('\\s' + name + '\\s*=\\s*("|\')((?:(?!\\1)[\\s\\S])*)\\1', 'i'));
return m ? m[2] : (new RegExp('\\s' + name + '(\\s|$|=)', 'i').test(attrs) ? '' : null);
}
function hostOf(src) {
var m = String(src).match(/^(https?:)?\/\/([^\/?#]+)/i);
return m ? m[2].toLowerCase() : null;
}
function check(text, opts) {
opts = opts || {};
text = String(text == null ? '' : text);
var today = opts.today || new Date().toISOString().slice(0, 10);
var findings = [];
function add(id, line, extra) {
var r = BY[id];
var ref = r.req ? STANDARD + ' ' + r.req : STANDARD;
findings.push({ check: id, sev: r.sev, line: line || 1, msg: r.msg + (extra ? ' ' + extra : '') + ' [' + ref + ']' });
}
// --- collect script tags -------------------------------------------------
var externals = [], inlines = [], m, tagRe = /<script\b([^>]*)>/gi;
while ((m = tagRe.exec(text)) !== null) {
var attrs = m[1] || '', line = lineAt(text, m.index), src = attr(attrs, 'src');
if (src) externals.push({ src: src, attrs: attrs, line: line, host: hostOf(src) });
else inlines.push({ attrs: attrs, line: line, end: m.index + m[0].length });
}
var thirdParty = externals.filter(function (s) { return s.host; });
// --- script inventory (6.4.3) -------------------------------------------
var inv = text.match(/<!--\s*pci-script-inventory\b([\s\S]*?)-->/i);
var invHosts = [], invBlockLine = inv ? lineAt(text, inv.index) : 0;
if (inv) {
var body = inv[1].split('\n');
body.forEach(function (raw, i) {
var t = raw.trim();
if (!t || /^(pci|host|script)\b.*:?$/i.test(t) && !/[\/.]/.test(t)) return;
var hm = t.match(/((?:https?:)?\/\/[^\s"']+|[a-z0-9.-]+\.[a-z]{2,})/i);
if (!hm) return;
var h = hostOf(hm[1]) || hm[1].toLowerCase();
invHosts.push(h);
var just = t.replace(hm[1], '');
var ok = /justification\s*:\s*\S+/i.test(just) && !/\b(TODO|TBD|FIXME|N\/A|pending|unknown|\?\?\?)\b/i.test(just);
if (!ok) add('inventory-no-justification', invBlockLine + i + 1, 'Entry: ' + h + '.');
});
} else if (thirdParty.length) {
add('inventory-missing', thirdParty[0].line, thirdParty.length + ' third-party script tag(s) on this page are unaccounted for.');
}
// --- per-script checks ---------------------------------------------------
externals.forEach(function (s) {
if (/^http:\/\//i.test(s.src)) add('script-over-http', s.line, 'src=' + s.src);
if (!s.host) return; // first-party relative path: integrity not required
if (inv && invHosts.indexOf(s.host) === -1) add('script-not-inventoried', s.line, 'Host: ' + s.host + '.');
var integrity = attr(s.attrs, 'integrity');
if (!integrity) add('script-no-integrity', s.line, 'Host: ' + s.host + '.');
else if (attr(s.attrs, 'crossorigin') === null) add('script-integrity-no-crossorigin', s.line, 'Host: ' + s.host + '.');
if (/@latest|\/latest\/|\/next\/|@next\b|[?&]v(ersion)?=latest/i.test(s.src)) add('script-unpinned-version', s.line, 'src=' + s.src);
if (/googletagmanager\.com|gtm\.js|tagmanager|segment\.(com|io)|optimizely|hotjar|fullstory|clarity\.ms/i.test(s.src)) add('tag-manager-on-payment-page', s.line, 'Host: ' + s.host + '.');
});
// --- content security policy (6.4.3) ------------------------------------
var enforced = [], reportOnly = [], metaRe = /<meta\b[^>]*>/gi;
while ((m = metaRe.exec(text)) !== null) {
var tag = m[0];
if (!/http-equiv\s*=\s*["']content-security-policy/i.test(tag)) continue;
var rec = { content: attr(tag, 'content') || '', line: lineAt(text, m.index) };
(/content-security-policy-report-only/i.test(tag) ? reportOnly : enforced).push(rec);
}
var hdrRe = /Content-Security-Policy(-Report-Only)?\s*:\s*([^\n"'`]+)/gi;
while ((m = hdrRe.exec(text)) !== null) {
var rec2 = { content: m[2], line: lineAt(text, m.index) };
(m[1] ? reportOnly : enforced).push(rec2);
}
var allCsp = enforced.concat(reportOnly).map(function (c) { return c.content; }).join(' ');
if (!enforced.length && !reportOnly.length) add('csp-missing', 1, thirdParty.length ? thirdParty.length + ' third-party script tag(s) run unrestricted.' : '');
else if (!enforced.length) add('csp-report-only', reportOnly[0].line, '');
enforced.forEach(function (c) {
var dm = c.content.match(/script-src[^;]*/i) || c.content.match(/default-src[^;]*/i);
if (!dm) return;
if (/'unsafe-inline'/i.test(dm[0])) add('csp-unsafe-inline', c.line, "Directive: " + dm[0].trim() + '.');
else if (/(^|\s)\*(\s|$)/.test(dm[0])) add('csp-unsafe-inline', c.line, 'Directive: ' + dm[0].trim() + '.');
});
var nonceInPolicy = /'nonce-/i.test(allCsp);
inlines.forEach(function (s) {
var type = attr(s.attrs, 'type') || '';
if (/json/i.test(type)) return;
var body = text.slice(s.end, text.indexOf('<\/script>', s.end) === -1 ? s.end : text.indexOf('<\/script>', s.end));
if (body.trim().length < 8) return;
if (attr(s.attrs, 'nonce') === null && !/\bintegrity\s*=/i.test(s.attrs)) add('inline-script-no-nonce', s.line, nonceInPolicy ? "The policy carries a nonce, but this tag does not." : '');
});
// --- tamper detection (11.6.1) ------------------------------------------
var tam = text.match(/<!--\s*pci-tamper-detection\s*:\s*([\s\S]*?)-->/i);
var reportEndpoint = /report-(uri|to)\s+\S/i.test(allCsp);
if (!tam && !reportEndpoint) add('tamper-detection-missing', 1, '');
if (tam) {
var iv = tam[1].match(/every\s+(\d+)\s*(hour|day|week|month)/i);
var days = null;
if (iv) {
var n = parseInt(iv[1], 10), unit = iv[2].toLowerCase();
days = unit === 'hour' ? n / 24 : unit === 'day' ? n : unit === 'week' ? n * 7 : n * 30;
}
if (days === null) add('tamper-interval-too-long', lineAt(text, tam.index), 'No evaluation interval is declared in the mechanism.');
else if (days > 7) add('tamper-interval-too-long', lineAt(text, tam.index), 'Declared interval: every ' + iv[1] + ' ' + iv[2] + '(s) = ' + Math.round(days) + ' days.');
}
// --- the part chatbots get wrong: dates and versions ---------------------
var fdRe = /(future[- ]dated|best practice until|not (?:yet )?required|becomes? mandatory|optional until|effective from)[^\n]{0,90}/gi;
var since = daysSince(MANDATORY_FROM, today);
while ((m = fdRe.exec(text)) !== null) {
add('future-dated-claim-expired', lineAt(text, m.index),
'As of ' + today + ' that date ' + (since === null ? 'has passed' : since >= 0 ? 'passed ' + since + ' days ago' : 'is ' + (-since) + ' days away') + '. Quoted: "' + m[0].trim().slice(0, 70) + '".');
}
var svRe = /PCI[\s-]?DSS[\s,]*v?\.?\s*(3\.2\.1|3\.2|3\.1|4\.0)(?!\.\d)/gi;
while ((m = svRe.exec(text)) !== null) add('stale-standard-version', lineAt(text, m.index), 'Found "' + m[0].trim() + '".');
findings.sort(function (a, b) { return (a.line - b.line) || a.check.localeCompare(b.check); });
return { findings: findings, standard: STANDARD, mandatory_from: MANDATORY_FROM, today: today, rule_count: RULES.length };
}
var API = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };
if (typeof module !== 'undefined') module.exports = API;
if (typeof window !== 'undefined') window.PCIENGINE = API;
</script>
<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
'use strict';
function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }
function summaryLine(res) {
const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
}
function toText(res, label) {
const f = (res && res.findings) || [];
const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });
return lines.join('\n');
}
function toHtml(res) {
const f = (res && res.findings) || [];
if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
}
var PCIREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
if (typeof module !== 'undefined' && module.exports) module.exports = PCIREPORT;
else window.PCIREPORT = PCIREPORT;
</script>
<script>
(function(){
var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
today.value=new Date().toISOString().slice(0,10);
function run(){ try { var res=window.PCIENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.PCIREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
go.onclick=run; if (src.value.trim()) run();
})();
</script>
<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://marketplace.visualstudio.com/items?itemName=ReadyStack.pci-payment-script-lint" rel="noopener" data-yj-install-door="mp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'pci-payment-script-lint',src:'mp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">VS Code Marketplace</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">ext install ReadyStack.pci-payment-script-lint</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/team" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind PCI DSS 6.4.3 Payment Script Lint every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"pci-payment-script-lint",lang:"en",source:"rule_alert"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section>
<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Reads your checkout template and names every browser script that fails PCI DSS v4.0.1 requirements 6.4.3 and 11.6.1</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">PCI consultants and QSAs typically bill $150-$300 an hour for the same payment-page script review</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_YLfFQJa9NbIbhJdjhg77rY07HqFCEhrFOmzmW3zHrI8" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
<section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-11">Updated 2026-09-11</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-11","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku37484_result_card.jpg" alt="PCI DSS 6.4.3 Payment Script Lint" loading="lazy" style="max-width:100%;border-radius:6px"></p>
<p>Sixteen findings on one checkout page, fifteen of them errors: that is what this lint returns on a template most e-commerce developers in the EU and the US would call their own.</p>
<p>PCI DSS v4.0.1 has two requirements that stopped being future-dated on 31 March 2025. Requirement 6.4.3: manage every script loaded and executed in the consumer browser on the payment page. Requirement 11.6.1: run change- and tamper-detection against that page, evaluated at least every seven days unless a targeted risk analysis says otherwise. Both land on one file — the template that renders the page where the card number is typed.</p>
<p>6.4.3 has three bullets: a method that confirms each script is authorised, a method that assures its integrity, and an inventory of all scripts with a written business or technical justification for each. The first two are engineering — a Content-Security-Policy and Subresource Integrity. The third is a document, and the document is where assessments go wrong, because it drifts the moment somebody adds a tag.</p>
<p>The bundled dirty.html, checked as of 2026-09-11:</p>
<p>L2 inventory_review_stale reviewed 832 days ago L3 tamper_evaluation_stale last evaluated 43 days ago L7 csp_unsafe_inline script-src contains 'unsafe-inline' L10 script_sri_missing no integrity=, and fetched over http:// L24 script_version_floating .../latest/hostedfields.js L28 injector_not_declared Google Tag Manager L30 script_sri_no_crossorigin integrity= present, crossorigin= absent L33 inline_script_no_nonce no nonce= on an inline block</p>
<p>Sixteen findings across eight lines; five scripts, one written justification between them. Line 28 is worth a look: Tag Manager is not one script but a loader for however many the container holds today, all of them inside 6.4.3.</p>
<p>The <code>integrity=</code> on line 30 is real, correct, and does nothing. Subresource Integrity is enforced cross-origin only when the request is made in CORS mode, so <code>crossorigin</code> has to be on the tag. Without it the browser never compares the hash. It reads like evidence and it is not.</p>
<p>The <code>/latest/</code> on line 24 is the same failure in another costume: if the bytes behind an authorised URL can change upstream, the authorisation expired without telling anyone.</p>
<p>The two date-driven checks are what make this a lint rather than a checklist. The tamper note on line 3 is not missing; it is 43 days old against a 7-day cadence. The inventory note on line 2 was reviewed 832 days ago, by someone who has left. A page that passes on a Monday fails the following Tuesday with no code change — which is what 11.6.1 is describing.</p>
<p>So the inventory lives in the page: a <code><!-- pci:script owner="..." reason="..." --></code> comment above the tag it justifies, a <code><!-- pci:tamper ... evaluated=YYYY-MM-DD --></code> note recording the mechanism and its last evaluation, and <code><!-- pci:inventory reviewed=YYYY-MM-DD --></code> dating the review. The lint fails when a tag arrives without a justification, so the register is maintained by the review that merges it. Fourteen checks; the clean fixture returns zero.</p>
<p>Checking one page is free and finishes the job: all fourteen checks, every finding on its line with the requirement reference, in VS Code or in the browser, nothing uploaded. The licence buys a different job — a sweep of every payment template in the repository, written out as a dated register for the assessor. $29 once. A QSA hour compiling the same register bills $150-$300.</p>
<p>Not legal advice: your QSA, acquirer and SAQ or ROC scope decide what applies.</p></div><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does PCI DSS 6.4.3 Payment Script Lint actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads a checkout or payment page and reports every browser script that fails PCI DSS v4.0.1 requirements 6.4.3 and 11.6.1: scripts with no integrity hash, scripts missing from the written inventory, entries with no business justification, a policy that allows unsafe-inline, and missing or slower-than-weekly tamper detection. Sixteen checks, each tagged with its requirement number.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is it for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">E-commerce developers who own the checkout template at a merchant that takes card details on its own pages: Shopify Plus and WooCommerce theme developers, Laravel and Rails shop teams, and anyone whose acquirer has just asked for a payment-page script inventory. It is a code linter, so it belongs to whoever edits the HTML, not to the compliance inbox.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why can't I just ask a chatbot or use a generic HTML linter?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Generic linters do not know what a payment page is; they flag unused tags, not unauthorised scripts. Chatbots still answer from PCI DSS v3.2.1 or describe 6.4.3 and 11.6.1 as future-dated best practices, which stopped being true on 2025-03-31. Neither one reads your actual checkout file line by line.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs a licence?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free, with no key and no limit: check the file open in your editor against all sixteen rules, with each finding on its line and its requirement number. The licence adds a different job, ownership of the evidence: sweeping every checkout template in the workspace and writing the dated script inventory report you hand to an assessor.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What would this cost me otherwise?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">PCI consultants and QSAs typically bill $150 to $300 an hour for the same payment-page script review, and they bill again after each template change. The licence is $29 once. The other cost is the assessment itself: arriving without a script inventory means a finding you close under deadline pressure.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Does it change my files or send my code anywhere?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">No. The extension reads the file, reports findings in the editor, and writes nothing except the report you ask for. There is no network call in the checker itself; the only request the extension ever makes is validating a licence key you typed.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does PCI DSS 6.4.3 Payment Script Lint actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads a checkout or payment page and reports every browser script that fails PCI DSS v4.0.1 requirements 6.4.3 and 11.6.1: scripts with no integrity hash, scripts missing from the written inventory, entries with no business justification, a policy that allows unsafe-inline, and missing or slower-than-weekly tamper detection. Sixteen checks, each tagged with its requirement number."}}, {"@type": "Question", "name": "Who is it for?", "acceptedAnswer": {"@type": "Answer", "text": "E-commerce developers who own the checkout template at a merchant that takes card details on its own pages: Shopify Plus and WooCommerce theme developers, Laravel and Rails shop teams, and anyone whose acquirer has just asked for a payment-page script inventory. It is a code linter, so it belongs to whoever edits the HTML, not to the compliance inbox."}}, {"@type": "Question", "name": "Why can't I just ask a chatbot or use a generic HTML linter?", "acceptedAnswer": {"@type": "Answer", "text": "Generic linters do not know what a payment page is; they flag unused tags, not unauthorised scripts. Chatbots still answer from PCI DSS v3.2.1 or describe 6.4.3 and 11.6.1 as future-dated best practices, which stopped being true on 2025-03-31. Neither one reads your actual checkout file line by line."}}, {"@type": "Question", "name": "What is free and what needs a licence?", "acceptedAnswer": {"@type": "Answer", "text": "Free, with no key and no limit: check the file open in your editor against all sixteen rules, with each finding on its line and its requirement number. The licence adds a different job, ownership of the evidence: sweeping every checkout template in the workspace and writing the dated script inventory report you hand to an assessor."}}, {"@type": "Question", "name": "What would this cost me otherwise?", "acceptedAnswer": {"@type": "Answer", "text": "PCI consultants and QSAs typically bill $150 to $300 an hour for the same payment-page script review, and they bill again after each template change. The licence is $29 once. The other cost is the assessment itself: arriving without a script inventory means a finding you close under deadline pressure."}}, {"@type": "Question", "name": "Does it change my files or send my code anywhere?", "acceptedAnswer": {"@type": "Answer", "text": "No. The extension reads the file, reports findings in the editor, and writes nothing except the report you ask for. There is no network call in the checker itself; the only request the extension ever makes is validating a licence key you typed."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:37484,slug:"pci-payment-script-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/payment-page-script-audit"><span class="yj-rel-t">PCI DSS 6.4.3 Payment Page Script Inventory Auditor</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/pci-payment-page-script-lint"><span class="yj-rel-t">PCI DSS 6.4.3 Payment Page Script Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/pci-payment-page-script-audit"><span class="yj-rel-t">PCI Payment Page Script Audit: requirement 6.4.3 and 11.6.1 on your checkout m</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/webflow-restaurant-template"><span class="yj-rel-t">Webflow Restaurant Template — delivered as self-contained HTML you own: 26 pag</span><span class="yj-rel-p">$49</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/personal-data-map-dsar-audit"><span class="yj-rel-t">Personal Data Map: find every column a GDPR subject access request has to reac</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/about-page-template"><span class="yj-rel-t">About Page Template — 6 Finished About Pages for Small Service Businesses (Sel</span><span class="yj-rel-p">$49</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section><!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>
<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script>
</body>
</html>
|