May 17
Fix
Mobile NAT64 false positive: French/EU mobile users no longer flagged as routing anomaly
When a device has a native IPv6 address (CF dual-stack) but Spur's monocle endpoint is IPv4-only, the OS routes through the carrier's NAT64 gateway — creating an apparent IP mismatch that previously triggered routingAnomaly = true (amber 50, ANOMALY on VPN/Proxy row). Common on Orange, SFR, and Bouygues mobile in France. Server now detects the IPv6→IPv4 split and classifies it as mobile dual-stack: uses the IPv4 as the display IP (covered by Spur's intelligence DB), clears the route-mismatch widget, and returns score 0 / CLEAN. Same-version mismatches (IPv4↔IPv4) still flag amber since those are consistent with rotating residential proxies.
May 17
Fix
Scanner widget: Network Intel grid no longer stuck at “…” on routing anomaly path
The routing anomaly branch in showScannerResult() returned early before calling setDetail(), leaving VPN / Proxy / Datacenter / Tor Exit / Country / Risk Score all frozen on the loading ellipsis. The early return now populates all six fields (CLEAR for network flags, country flag + code, amber 50 for risk score) and calls resolveDeviceFallback() so the Device Intelligence row also fills from server-side UA data.
May 17
Fix
Scanner mobile overflow: ISP / Service and VPN / Proxy values no longer clipped off-screen
Long IPv6 addresses (38+ chars) caused the scanner widget to expand horizontally beyond the viewport on mobile, pushing the right-side values of ISP/Service and VPN/Proxy rows off-screen. Three CSS fixes: overflow:hidden on .scanner-widget clips any overflow; min-width:0; word-break:break-all; flex-shrink:1 on .result-row-val lets flex items shrink and wrap; align-items:flex-start on .result-row handles multi-line IP values. Route mismatch JS also fixed: replaced <br> inside inline-flex (broken) with a proper column layout, and fixed mojibake ↳ arrow.
May 17
Fix
Scanner result message: HTML entities rendering as literal text
msg.textContent does not parse HTML entities, so “Verified residential — you’re clean.” and “Analysing connection…” were displayed verbatim with the entity codes visible. Replaced with actual Unicode characters (em dash, right single quotation mark, ellipsis). ISP/Service logo chip also fixed: generic names (Mobile ISP, Residential ISP, Mismatched route, etc.) no longer render a fallback “M” initial chip — unrecognized brand names are now shown as plain text only.
May 17
Fix
Mojibake: ▌ cursor character in “How It Works” code blocks
The blinking cursor character ▌ (U+258C, LEFT HALF BLOCK) in the three “How It Works” terminal code snippets was double-encoded as Windows-1252, displaying as â–Œ across all browsers. Replaced all three instances with the correct UTF-8 character.
May 17
Perf
Mobile performance: font weight pruned, content-visibility, preconnect
Three performance improvements targeting mobile first-paint. (1) Dropped Space Grotesk weight 300 from the Google Fonts request — not used in any CSS rule, saves ~8 KB of font transfer on every cold load. (2) Added content-visibility:auto with contain-intrinsic-size to .value-props, .features-section, and .proof-section — browser skips off-screen layout and paint on first render, measurably reducing LCP on long pages. (3) Upgraded flagcdn.com from dns-prefetch to preconnect, eliminating the full DNS + TCP + TLS handshake before the first flag image renders in the scanner.
May 17
Feature
Mobile menu redesigned: clean dark overlay with chevron links and neutral CTA buttons
The mobile hamburger menu was restyled to match the site’s aesthetic. Navigation links: white text at 1rem / 600 weight with a right-side chevron arrow, replacing the dim uppercase small-caps. CTA row: LOG IN renders as a muted bordered pill, GET STARTED as a solid white / black button — removing the harsh neon lime that clashed with the dark overlay and was flagged as visually inconsistent with the auth page button redesign.
May 13
New
4 new blog posts: card testing, CAPTCHA farms, loyalty fraud, gaming launches
Four production-ready posts shipped to the blog.
Card Testing Attacks covers the full bot operation — proxy routing, antidetect browsers, timing randomization, economics ($5–$50 per live card) — and shows exactly why Stripe Radar alone is insufficient.
CAPTCHA Farm Economics documents the $0.0005–$0.002/solve market, how reCAPTCHA v3 gets gamed with warmed profiles, and why CAPTCHA is now only a deterrent against the least sophisticated bots.
Loyalty Point Fraud maps dark-market valuations ($0.004–$0.012/mile), all four attack vectors, and a Python integration example.
Bots at Product Launches breaks down waitlist hoarding, referral self-referral, SaaS trial stacking, and sneaker-drop scalping with real data. All posts include Article + FAQ + BreadcrumbList schema, newsletter capture, and related-article cross-links.
May 13
New
2 new case studies: iGaming bonus abuse + travel scalper bots
Two full illustrative case studies added.
EU Sportsbook — iGaming Bonus Abuse: professional bonus hunters using Dolphin Anty + Bright Data residential proxies drained €1.8M in GGR before Sentinel's antidetect detection and device clustering caught the pattern in 48 hours.
European OTA — Travel Scalper Bots: Playwright-driven inventory-hoarding bots crashed checkout conversion to 34%; Sentinel's headless artifact detection, ASN classification, and form-fill timing signals shut down the operation without adding CAPTCHA friction. Case-studies index updated with both cards; aggregate stat raised from $2.4M to $7M+.
May 13
Feature
Blog UX: category filter bar + reading time badges + card glow hover
Blog index redesigned with three UX upgrades. A sticky filter bar above the grid lets visitors filter by category (Guide, Research, Case Study, Analysis, Deep Dive, Engineering, Industry) — pure client-side JS reading tag text, zero server round-trips. Reading time badges auto-inject into every card footer via a lookup map (7–13 min estimates). Card hover effect gains a subtle accent glow (box-shadow: 0 0 0 1px rgba(204,255,0,0.12)) alongside the existing lift animation. Article count updated to 34.
May 13
Perf
Device Intelligence loads immediately — removed 3-second artificial delay
The Fingerprint SDK lazy-loader was wrapped in setTimeout(load, 3000) as a safety throttle. Since loadDeviceIntel already awaits the SDK promise, the timeout just stalled the DI panel for 3 full seconds on every dashboard open — even on fast connections. Changed to load() (immediate). Client-side fetch to /api/device-intel now has AbortSignal.timeout(8000) so the DI panel fails gracefully instead of hanging if the upstream Fingerprint API is slow.
May 13
Perf
bcrypt async in OAuth flow; guard.js 7-day immutable cache; crypto hot-path fix
Three server-side performance wins. bcrypt: Google OAuth new-user creation used bcrypt.hashSync inside a db callback, synchronously blocking the event loop on every first-time Google login. Replaced with await bcrypt.hash() in an async callback. guard.js: Cache-Control changed from no-store to public, max-age=604800, immutable — saves a round-trip on every page load. crypto: parseUaIntel was calling require('crypto') on every invocation; changed to use the module-level crypto import.
May 13
Security
XSS fix: escape IP and service name before innerHTML injection on scanner
Three innerHTML assignments on the index.html scanner injected raw values from Cloudflare headers (cfIp), Spur's IP routing (spurIp), and Spur's service name (cleanService) without sanitization. Added a local esc() helper (textContent trick) and applied it to all three sites. Also added DNS prefetch hints for Fingerprint CDN and DuckDuckGo favicons to shave ~20ms off first-load.
May 13
Security
Admin key moved to sessionStorage; 2FA pending guard; regex hardening; npm CVE patched
Four security fixes shipped together. Admin persistence: admin key stored in localStorage survived browser restarts; moved to sessionStorage so it clears on tab close. 2FA bypass: /api/2fa/setup didn't check pending2fa on the JWT — a user mid-2FA login could call setup with their half-token. Added guard. Country code: country.length === 2 accepted "00" and numeric strings; tightened to /^[a-zA-Z]{2}$/.test(). npm: npm audit fix patched GHSA-v2v4-37r5-5v8g (ip-address CVE via @libsql/client); audit now reports 0 vulnerabilities.
May 13
Content
Blog index updated: 34 posts, JSON-LD refreshed, case-studies $7M+ aggregate
Blog hero stat updated from 16 → 34 articles reflecting the full post fleet. JSON-LD BlogPosting list includes all new posts. Case-studies/index.html aggregate stat raised from $2.4M+ to $7M+ to account for the two new scenarios. BiDi unicode character injection vector patched in display_name PATCH endpoint — characters are now stripped server-side before write.
May 9
New
4 new blog posts: ATO playbook, iGaming bonus abuse, headless detection, agentic AI browsers
Shipped four long-form pieces targeting fresh high-intent keywords.
Account Takeover Prevention: The 2026 Engineering Playbook covers session-cookie theft, real-time phishing kits, and device-bound sessions.
iGaming Bonus Abuse Detection targets sportsbook/casino multi-account fraud with UKGC/MGA regulatory framing.
Headless Browser Detection in 2026 documents what works after stealth plugins kill the classical signals.
Detecting Agentic AI Browsers covers ChatGPT Atlas, Claude Computer Use, OpenAI Operator, and the policy decision every team needs to make about AI traffic. Each post ships with Article + FAQ + BreadcrumbList schema and inline links into the existing post graph.
May 9
SEO
Sitemap, llms.txt, and blog-index refreshed
Added the 4 new posts to sitemap.xml with priority 0.95 and a May lastmod. Bumped homepage, blog index, and changelog lastmod to 2026-05-09 so Google and Bing recrawl. Refreshed /llms.txt with the new posts surfaced for ChatGPT/Claude/Perplexity citation discovery, plus an expanded "Capabilities" block that explicitly names ChatGPT Atlas / Claude Computer Use detection. Updated blog-index BlogPosting JSON-LD list with the new headlines.
May 9
SEO
Internal linking pass — every new post gets 3 inbound contextual links
The four new posts each link into the existing post graph (residential proxies, antidetect browsers, credential stuffing, multi-accounting, Puppeteer/Playwright, AI takeovers) with relevant anchor text rather than navigation-style "read more". Improves crawl depth into the deeper posts and concentrates topical relevance for the cluster keywords. Reciprocal Related-Articles cards added to each new post pointing back at the cluster.
May 9
Feature
Newsletter capture on every new blog post
"Fraud Brief" newsletter block injected near the article CTA on all 4 new posts. Inline form posts to /api/newsletter with deduplication, fires generate_lead in GA4 on success. Same pattern as the existing post fleet — consistent capture surface across the blog.
May 9
SEO
Topical cluster expansion: bot detection, ATO, multi-accounting
The blog now has 30 indexed posts across three reinforced clusters: bot & automation (headless, Puppeteer/Playwright, agentic AI, antidetect, captcha-less), network & identity (residential proxies, VPN evasion, ShadowNode, Tor), and platform vertical (iGaming, OAuth signup, ticketing, dating, Stripe, Shopify, fintech, e-commerce, SaaS). Cluster cross-linking is what moves long-tail rankings — each new post strengthens 2–3 existing posts.
May 9
Content
Coverage of agentic AI traffic — first-mover content
"Detecting Agentic AI Browsers" is the first piece in our category to address ChatGPT Atlas, OpenAI Operator, and Claude Computer Use as a distinct traffic class with a documented detection surface and a policy framework (block / allow-attribute / explicit-agent-path). Targets a query cluster ("detect chatgpt atlas", "block ai agent traffic", "operator bot detection") with essentially zero established competition as of May 2026.
May 2
Detection
Smarter VPN/proxy verdicts using dch as ground truth
The scanner now uses Spur's datacenter-ASN flag (dch) to distinguish stale-cache verdicts from real VPN traffic. Matched IPs + vpn=true + residential ASN → CLEAN (cache residue from a previous VPN session). Route mismatch + datacenter ASN → DETECTED (real VPN exit even if Spur's IP DB doesn't have it pinned by name). Eliminates the false-PROTON-VPN labels on residential IPs after VPN toggles, and catches real VPN exits Spur's per-IP database hasn't ingested yet.
May 2
UX
Live scanner: RESCAN button + cache-busting
Added a one-click RESCAN action in the scanner card header. Wipes localStorage, sessionStorage, cookies, and IndexedDB entries for Spur/monocle/mcl namespaces, then reloads with a unique ?_rescan=<ts> query so no cache layer (browser disk, BFCache, service worker, Cloudflare edge) can serve stale state. /api/verify calls now also send a fresh nonce per request and explicit cache: 'no-store'.
May 2
Detection
Route mismatch surfaced in network row
When Spur's edge sees a different visitor IP than what reaches our origin via Cloudflare (Brave + Proton TCP routing splits, CF WARP, etc.), the panel now shows both IPs stacked: A.B.C.D via CF + ↳ X.Y.Z.W via Spur (VPN exit). The split itself is recorded, and the verdict reflects the underlying ASN signals rather than guessing.
May 2
Reliability
Scanner can no longer hang on "Analysing now"
The legacy two-state machine had no exit when Spur returned scanInconclusive=true twice. Bot poll now waits the full 4-second window and uses the LATEST monocle token (catches Spur's mid-window assessment refresh). Master 5-second safety timeout force-resolves if anything else stalls. Loading panel cross-fade switched from absolute positioning to CSS grid stacking — no more overflow behind the scanner foot when the details panel expands.
May 2
New
Fingerprint Pro account migration → custom subdomain fa.sntlhq.com
Swapped the Fingerprint device-intelligence integration to a new account and a Cloudflare-backed custom subdomain. Bypasses ad-blocker tracker lists by default. CDN fallback chain: fa.sntlhq.com → fpjscdn.net/v4 if DNS hasn't propagated. API endpoints list both subdomain and eu.api.fpjs.io in priority order. Applied across all 8 pages that load the agent.
May 2
Design
Dark editorial homepage restored, fingerprint.com experiment reverted
A short-lived white "fingerprint.com / sift.com" redesign clashed with the rest of the site (login, signup, dashboard, contact all run dark Space Grotesk + neon green). Restored the editorial dark theme so the homepage and post-signup flows share one visual system. Added a centered "Customer Voice" testimonial block with the residential-proxy quote, styled to match the existing crosshair / grid-overlay language.
May 2
Reliability
Fingerprint loader no longer hangs Device Intel on blocked browsers
When Brave Shields, Proton NetShield, or strict uBlock dropped the Fingerprint agent, the Device Intel rows were stuck on SCANNING… indefinitely. Hard 3-second timeout now resolves the row to a neutral state. Verify endpoint distinguishes "SDK genuinely blocked" (private/missing IP) from "stale public IP" so the panel paints an honest verdict either way.
May 2
UX
Loading-state placeholders are loading-state-shaped
Detection signal rows used to ship as a literal ", " empty value, which read as broken-rendered output if a visitor opened the details panel during the bot-poll window. Replaced all 12 placeholders with "…" so the loading state reads as loading.
May 2
Perf
Smoother scanner cross-fade and row reveal
Loading→result transition uses cubic-bezier(0.22, 1, 0.36, 1) easing on opacity and Y-translate. Score-circle pops with a soft bounce. Result rows cascade in at 40/100/160/220 ms. Detail-grid items fade in staggered when the panel expands. Header colour swaps go through 0.4 s eased transitions instead of instant — feels like a polished SaaS product, not a 90s page reload.
May 2
Sec
FINGERPRINT_SECRET_KEY rotation
Server-side device-intel calls now use the new Fingerprint account's secret. Read from Railway env, never committed. Server CSP script-src, worker-src, and connect-src directives updated to allow the new fa.sntlhq.com subdomain alongside fpjscdn.net and eu.api.fpjs.io.
May 2
New
Customer voice section on the homepage
Added a centered testimonial block above the final CTA: residential-proxy detection drove the integration ROI in week three for a Series-A fintech. Styled in the editorial DM Mono / neon-green typography to match the rest of the site, with crosshair markers and a grid overlay matching the comparison and CTA bands.