Heatmaps, scroll maps and click reports for a page, plus simple A/B testing. You point it at a URL and it shows where people clicked and how far down they read.
Build me heatmaps that replace Crazy Egg — and know exactly why this is ALMOST. The recording is easy. The hard part is that **a click at 390 pixels wide and one at 1440 are not the same click**. A heatmap that averages across breakpoints is a picture of nothing, and that single problem is why this category is harder than it looks. Solve it and the tool is genuinely useful; ignore it and you have a colourful lie. STACK - Node 20+ with Fastify - SQLite through better-sqlite3, WAL mode - A tracking script under 6KB gzipped, from my own domain - Playwright for the page snapshots - Caddy in front THE DATA MODEL - pages: id, site_id, path_pattern, name, is_active - snapshots: id, page_id, breakpoint, image_path, dom_html_gzip, width, height, captured_at — the page as it looked, per breakpoint, so a map can be drawn over it later - clicks: id, page_id, snapshot_id, breakpoint, x_ratio, y_ratio, element_selector, element_text, viewport_w, viewport_h, doc_h, scroll_y, is_rage, is_dead, session_hash, bot, at - scrolls: id, page_id, breakpoint, session_hash, max_scroll_ratio, doc_h, at - moves: bucketed, not raw — a grid cell and a count, because storing every pointer position is a great deal of data for very little insight - experiments and variants, if you build the testing half - Every event carries the breakpoint bucket. Nothing is ever aggregated across them BREAKPOINTS, WHICH IS THE PROBLEM - Define buckets — phone, tablet, small desktop, large desktop — and record which one every event belongs to - Every map is drawn per bucket, over a snapshot taken at that width. Never one map over one screenshot - Coordinates stored twice: as a ratio of the viewport, and as a selector plus an offset within the element. The second is what survives a layout change, and it is what makes the map still meaningful after a redesign - An element-based map — this button was clicked 412 times — is more useful than a pixel cloud on almost every site, and it is immune to reflow. Build that first and treat the pixel map as the illustration SCROLL DEPTH - Normalised against the document height at the time, per breakpoint, because a page is a different length on a phone - Report the percentage of people who reached each section, with the fold marked. That is the number people act on - Record the document height with every event, or a page whose content changed will produce nonsense CLICKS WORTH KNOWING ABOUT - Rage clicks: several clicks in a small area within a second or two, which usually means something looks interactive and is not - Dead clicks: a click on something that produced no navigation, no network request and no visible change - Both flagged at capture time and listed separately, with the element. Those two lists are the most actionable output of the whole tool SNAPSHOTS - Render the page with a real browser at each breakpoint on a schedule, storing the image and the markup - Deterministic: fonts settled, animations stopped, lazy images loaded, external requests blocked - A page that changes often needs a fresh snapshot, or the map is drawn over the wrong layout. Detect it by comparing a hash of the structure and warn BOTS AND HONESTY - Flag, never drop, and exclude through a SQL view - A minimum session count before a map is shown, with the count displayed. A heatmap of forty visits looks convincing and means nothing, and stating the sample is the difference between analysis and decoration PRIVACY - No input values, ever. Record that a field was clicked, never what was typed - Mask text in the snapshot by selector for anything sensitive - No cookie beyond a session-scoped identifier, no third-party requests OPERATIONS - .env: DATABASE_PATH, STORAGE_PATH, BASE_URL, HASH_SALT, SESSION_SECRET - Migrations on boot, each once; retention with a sweeper - Health endpoint WHAT MATTERS MOST Per-breakpoint maps and element-based coordinates. Build those before any colour is drawn, and put the sample size next to every map.
What you lose
- Heatmaps that stay meaningful across breakpoints, which is the hard part — a click at 390px and one at 1440px are not the same click
- Scroll depth normalised across page lengths
- A snapshot of the page as it looked when the data was collected, so an old map still means something after a redesign
- A/B testing wired into the same script
If you would rather not build
- Microsoft Clarity, which does this for nothing
What it costs
read from their page 15 Aug 2026
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $29/mo | — | 15 Aug 2026 |
Their pricing page is where these came from. Seeing a different price? Tell us.
The escape hatch
open source · no votes, no paid placement
OpenReplay
$0Self-hosted replay and heatmaps in one deployment.
openreplay/openreplayfree · open source
Why this verdict
our own opinion · changed only by a person
55/100
Verdict kinda at 55. Collecting clicks is trivial; keeping a map honest across breakpoints and redesigns is what takes the weekend.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about Crazy Egg
answered from the record above
Is Crazy Egg free?
No — the plan we track is $29 a month. Plus at $29/month billed monthly, around $24 annually, for 75,000 tracked page views.
Can you replace Crazy Egg by building your own?
ALMOST. A weekend of work, and real gaps remain. Replacement score 55 out of 100, build time a weekend. Read what you lose before you decide.
How much does Crazy Egg cost?
$29 a month on Plus — $348 a year. Recorded 9 Aug 2026.
What do you lose by replacing Crazy Egg?
Heatmaps that stay meaningful across breakpoints, which is the hard part — a click at 390px and one at 1440px are not the same click; Scroll depth normalised across page lengths; A snapshot of the page as it looked when the data was collected, so an old map still means something after a redesign; A/B testing wired into the same script. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Crazy Egg?
Yes: OpenReplay, PostHog. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
Every week, something stops being worth paying for.
New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.
free forever · no tracking pixel · stored here, never passed to anyone

