<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stevan Andric</title>
    <description>The latest articles on DEV Community by Stevan Andric (@stevandric).</description>
    <link>https://dev.to/stevandric</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3889689%2F499b3b3c-d074-4956-9c6e-349799380ef8.jpg</url>
      <title>DEV Community: Stevan Andric</title>
      <link>https://dev.to/stevandric</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stevandric"/>
    <language>en</language>
    <item>
      <title>I Built a Cookie-Free Visitor Analytics Platform — Here's What I Learned</title>
      <dc:creator>Stevan Andric</dc:creator>
      <pubDate>Mon, 20 Apr 2026 21:21:37 +0000</pubDate>
      <link>https://dev.to/stevandric/i-built-a-cookie-free-visitor-analytics-platform-heres-what-i-learned-2pme</link>
      <guid>https://dev.to/stevandric/i-built-a-cookie-free-visitor-analytics-platform-heres-what-i-learned-2pme</guid>
      <description>&lt;h1&gt;
  
  
  I Built a Cookie-Free Visitor Analytics Platform — Here's What I Learned
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I built &lt;a href="https://www.identity-js.com" rel="noopener noreferrer"&gt;identity-js&lt;/a&gt;, an open-source visitor intelligence platform that uses browser fingerprinting and behavioral analytics to understand how people actually use your site — no cookies, no consent banners. You can &lt;a href="https://www.identity-js.com/demo" rel="noopener noreferrer"&gt;try the live demo&lt;/a&gt; right now.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Every analytics tool I tried fell into one of two camps: either it was a bloated, cookie-dependent behemoth that required consent banners across half the page, or it was a privacy-first counter that told me someone visited but nothing about &lt;em&gt;how&lt;/em&gt; they experienced my site.&lt;/p&gt;

&lt;p&gt;I wanted something in between. I wanted to know: are visitors frustrated? Are they rage-clicking on something that looks like a button but isn't? Are they abandoning my signup form halfway through? Are bots inflating my numbers?&lt;/p&gt;

&lt;p&gt;None of the tools I found answered all of these questions without requiring cookies or a 200KB script.&lt;/p&gt;

&lt;p&gt;So I built one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What identity-js Does
&lt;/h2&gt;

&lt;p&gt;At its core, identity-js is a lightweight tracker (29KB gzipped, zero dependencies) that collects 40+ browser signals and watches for 11 behavioral patterns in real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser fingerprinting&lt;/strong&gt; generates a persistent visitor ID from signals like canvas rendering, WebGL parameters, audio context, installed fonts, speech synthesis voices, and math engine quirks. No cookies needed — the ID survives cookie clears and private browsing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavioral tracking&lt;/strong&gt; is where it gets interesting. The tracker automatically detects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rage clicks&lt;/strong&gt; — rapid frustrated clicking on the same spot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dead clicks&lt;/strong&gt; — clicks on elements that do nothing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phantom clicks&lt;/strong&gt; — clicks on things that &lt;em&gt;look&lt;/em&gt; interactive but aren't&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form abandonment&lt;/strong&gt; — forms started but never submitted, including which field they bailed on&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input hesitation&lt;/strong&gt; — how long someone stares at a field before typing (a strong signal of confusion)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reading behavior&lt;/strong&gt; — whether someone is actually reading, skimming, or just scrolling past&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error tracking&lt;/strong&gt; — JS exceptions and console errors your visitors hit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text copying&lt;/strong&gt; — when users copy text from your pages (great for knowing what content resonates)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these feed into a &lt;strong&gt;frustration score&lt;/strong&gt; — a weighted composite that tells you at a glance which visitors are having a bad time on your site.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack (Zero Dependencies on the Server Too)
&lt;/h2&gt;

&lt;p&gt;The whole server runs on pure Node.js with zero npm dependencies. I used Node 22's built-in &lt;code&gt;node:sqlite&lt;/code&gt; module for the database, &lt;code&gt;node:crypto&lt;/code&gt; for auth (scrypt + HMAC-SHA256 tokens), and built the HTTP routing from scratch.&lt;/p&gt;

&lt;p&gt;The dashboard is a single HTML file — no React, no build step, no framework. Just vanilla JS with a hand-rolled router and CSS custom properties for theming. It includes an interactive map (Leaflet), real-time live visitor view, per-visitor drill-downs with full session timelines, and PDF report exports.&lt;/p&gt;

&lt;p&gt;The tracker builds to UMD, CJS, and ESM via Webpack, so it works everywhere — script tag, npm import, or require.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;IdentityJS&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@identityjs/tracker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visitor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;IdentityJS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pk_live_YOUR_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// That's it. Fingerprinting + all behavioral tracking starts automatically.&lt;/span&gt;
&lt;span class="c1"&gt;// Want custom events too?&lt;/span&gt;
&lt;span class="nx"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;signup_clicked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bot Detection Without ML
&lt;/h2&gt;

&lt;p&gt;One thing I'm particularly happy with is the bot detection system. Instead of relying on machine learning or third-party services, it scores visitors 0–100 based on observable signals: missing browser APIs, headless browser flags, impossible screen configurations, zero-entropy fingerprints, and behavioral patterns (or lack thereof).&lt;/p&gt;

&lt;p&gt;A real human browsing your site produces a messy, unique fingerprint with varied interactions. A bot produces clean, predictable signals with mechanical timing. The scoring system catches this reliably, and the dashboard surfaces bot visitors separately so they don't pollute your analytics.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Live Demo
&lt;/h2&gt;

&lt;p&gt;Rather than asking you to sign up to see if this is useful, I built a &lt;a href="https://www.identity-js.com/demo" rel="noopener noreferrer"&gt;live demo&lt;/a&gt; that loads the real dashboard with realistic sample data. You can explore visitor profiles, see the frustration scoring in action, browse session timelines, check out the bot detection — everything the real product does, with no account required.&lt;/p&gt;

&lt;p&gt;The demo includes 14 sample visitors with varied profiles: different browsers, devices, locations, and behaviors. There's a frustrated user with rage clicks and form abandons, a detected bot with suspicious signals, and regular visitors with realistic browsing patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned Building This
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Browser fingerprinting is more stable than I expected.&lt;/strong&gt; The combination of canvas, WebGL, audio context, and font enumeration produces remarkably consistent hashes across sessions. The key is using enough signals that any single one changing doesn't break the whole ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavioral signals are more valuable than pageview counts.&lt;/strong&gt; Knowing that 40% of visitors rage-click your pricing toggle, or that the average hesitation time on your email field is 8 seconds, tells you more than knowing you had 10,000 visits last month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero-dependency servers are liberating.&lt;/strong&gt; Not having node_modules means the entire server deploys in seconds, has zero supply chain risk, and is trivial to audit. Node 22's built-in SQLite is surprisingly capable for a single-server analytics product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single-file dashboards aren't as crazy as they sound.&lt;/strong&gt; Yes, the dashboard HTML file is large. But it loads instantly (one request, no waterfall), is trivial to cache, and I never have to debug a webpack config. For an internal tool like this, the tradeoff is worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.identity-js.com/demo" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/strong&gt; — explore the full dashboard with sample data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.identity-js.com" rel="noopener noreferrer"&gt;Website&lt;/a&gt;&lt;/strong&gt; — landing page and signup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@identityjs/tracker" rel="noopener noreferrer"&gt;npm package&lt;/a&gt;&lt;/strong&gt; — &lt;code&gt;npm install @identityjs/tracker&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/anthropics/identity-js" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; — full source code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The free tier includes 1,000 visitors and 10,000 events/month. If you're building something and want to understand how your visitors actually experience it, give it a shot.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you have questions or feedback, drop a comment — I'd love to hear what you think.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
