<- All posts

How Hotjar Screenshots Every Bug Report: A Picture Nobody Mentions, Consent After the Send

Will Smith··10 min read

Last night we went back into our free Hotjar account for two mechanics we skipped the first time: the screenshot that rides along with every survey response, and the one dropdown that governs consent. We submitted three real responses as a visitor, one saying yes to consent, one saying no, one with consent off entirely, then read all three back in the admin. Here is what each side of that exchange gets to see, and the version we built for Usero the same night.

The setup: a sandbox page with a deliberately broken Export CSV button, served over a real HTTPS tunnel because our first Hotjar night taught us that submissions from a localhost origin vanish without a trace. On HTTPS, all three responses surfaced in the dashboard within seconds. Credit where due, the ingestion is fast.

The bug report screenshot nobody mentions

In the survey editor, under Behavior, there is a checkbox: “Automatically include a screenshot with each response.” It was already ticked on our survey, and we never touched it. Hotjar's docs say it defaults on for every on-site survey created after December 2023, free plan included. So every response comes with a bug report screenshot whether the owner asked for one or not, which as an owner is a nice surprise.

Hotjar survey editor Behavior section with the automatic screenshot checkbox ticked by default
ScreenshotThe Behavior section of the survey editor. The screenshot checkbox arrived pre-ticked on a survey we created without ever seeing this screen.

The visitor's side of that same exchange is nothing. No notice, no “a picture of this page will be attached.” The consent prompt we get to later never mentions it either. As far as the visitor can tell, no capture happened.

What the capture contains is the interesting part, and it is cleverer than the word screenshot suggests. Our visitor's Chrome had force-dark-mode on, so the page they saw was dark. The stored image shows the page in its authored light theme. A pixel capture cannot do that: Hotjar is serializing the DOM and re-rendering it server-side, the same machinery as session replay. The widget itself is absent from the image, even though the open survey panel covered the page for the whole submission. And our page's line “Rows: 1,284. Last refreshed 4 minutes ago” came back with every digit replaced by asterisks. Headings and button labels come through verbatim, numbers do not.

Hotjar response modal showing the reconstructed page screenshot with digits masked to asterisks beside the survey answers
ScreenshotThe response modal. The page renders in its authored light theme even though the visitor saw it dark, the widget is gone, and every digit on the page is masked.

Those are careful defaults. A raw pixel screenshot would have shipped whatever was on screen, dark mode, open widget, account balances and all. Hotjar's version gives the owner a legible picture of the page while suppressing exactly the characters most likely to be personal or financial. We did not expect the free tier of a survey tool to be the place we found the best screenshot privacy model in this series.

“Screenshot not available”

One rough edge, and we hit it within a minute of submitting. Opening the newest response showed an error glyph and “Screenshot not available” while the two older responses rendered fine. Ten minutes later the same response had its screenshot. The pipeline is asynchronous, which is fair, but there is no pending state: a screenshot that is still processing and a screenshot that failed forever look identical, and the copy asserts the failure. An owner who opens a fresh response in those first minutes reads “not available” and concludes the feature is broken. It was working the whole time.

Hotjar response modal showing an error glyph and Screenshot not available message on a freshly submitted response
ScreenshotThe same response that showed a full screenshot ten minutes later. Nothing distinguishes still-processing from failed.

One dropdown, three plain words

Consent lives on the last card of the Questions section, attached to the thank-you step: “Connect responses with Hotjar tools”, a native select with Automatically, Ask for consent, and Never. Per-survey, free tier, defaults to Automatically. As a control shape this is right, and it is the shape we stole. Three words, sitting next to the thing they govern instead of buried in an account-wide privacy screen.

Hotjar survey editor with the Connect responses dropdown set to Ask for consent
ScreenshotThe Connect responses dropdown on the thank-you card. One shared sentence describes all three modes; the differences between them are not explained anywhere in the product.

What the admin screen does not do is explain the modes. One shared sentence and a help link cover all three. Nothing tells the owner what the visitor will see in Ask mode, what happens to a declined response, or that Never severs the replay link. The sibling checkbox that would show the site's legal name and privacy policy in the prompt was disabled on our account, waiting on a Site settings step we had never been told about. So the prompt we shipped to our visitor carried no company name and no privacy link.

Here is what that visitor got, on the thank-you screen, after the response had already been sent: “Before you go, can we connect your response with data (device, usage, cookies, behavior, and interactions) related to your visits? This will help us give you a better experience.” Two buttons, No thanks and Yes, sure. The More information link goes to hotjarconsent.com, a Hotjar-branded page the visitor has never heard of, not to the site's own policy. The prompt does not name the site, does not mention the screenshot that was already captured, and describes session recording as “behavior and interactions.” The linked page is franker, saying outright that behavior can be used to recreate sessions in visual replay.

Hotjar consent prompt on the survey thank-you screen asking to connect the response with visit data, with No thanks and Yes, sure buttons
ScreenshotThe Ask for consent prompt, shown after submission on our force-dark sandbox page. No site name, no mention of the screenshot, and More information links to hotjarconsent.com.

We declined on response #2. The response still landed in full: rating, text answer, email, page path, country, browser, OS, viewport, an 8-character user id, and the screenshot. What “no” withholds is the linkage to the visitor's other Hotjar data. That trade is defensible on its own terms, the complaint still gets through when the visitor says no, and we kept that property in our version. But in the admin, nothing marks response #2 as declined. No badge, no filter, no export column. The visitor made a decision and the product threw it away before the owner could see it.

One more finding, and it is the one that shaped our build most. We flipped the dropdown back to Automatically, saved, and confirmed the save by reloading the editor. The very next visitor session still got the Ask prompt. The survey definition is cached client-side, so the setting the owner sees and the setting a visitor gets can disagree for an unknown window. For a widget colour that is a shrug. For a consent control it is a real problem: an owner switching to Never has no way to know when the switch takes effect.

How we built ours

Usero already records optional session replays and deep-links each feedback report to its submit moment, so the raw machinery was there. What last night added is the consent layer and the fallback picture, with Hotjar's dropdown as the starting shape and their caching bug as the thing to design against.

The setting is per-project, one row called Recording at the top of the Session replay settings: Always, Ask first, Never. Always is today's behaviour, background recording, so nothing changes for existing installs. Never means never: the widget does not load rrweb at all, and the server refuses to create a recording session for that project, so even a widget running on a stale cached config cannot keep recording after the owner flips the switch. That server-side refusal is the direct answer to the propagation window we watched on Hotjar. The widget also re-fetches the mode on every page load rather than caching it in localStorage, because a consent setting should not take effect whenever a cache happens to expire.

Usero Session replay settings with Recording set to Ask first
ScreenshotRecording sits at the top of the Session replay settings. Each choice gets one sentence saying what the visitor will see and what Usero refuses.

Ask first inverts Hotjar's ordering. Nothing is recorded in the background. The feedback sends the moment someone hits send, the same property we credited Hotjar for keeping, and only then does the widget ask: “Thanks, it's sent! Want to include a snapshot of this page too?” Two buttons, Include and Don't include. A concrete noun, a snapshot of this page, instead of “data related to your visits.” Decline, press Escape, or ignore it for 15 seconds and the snapshot is never taken, so there is no copy anywhere to retract. The prompt renders in its own shadow root, follows the visitor's light or dark preference, and removes itself from the DOM before any capture runs, so a snapshot can never contain our own prompt.

Usero widget consent prompt asking to include a snapshot of the page, with Include and Do not include buttons, shown before anything is captured
ScreenshotOur Ask first prompt, shown once the feedback has sent and before any capture. Decline and the snapshot is never taken.

The other half of the build is the fallback. Replay is optional and sampled, so plenty of feedback arrives with no recording running, and until last night those reports had no picture at all. Now the SDK captures a single rrweb DOM snapshot just after submit and stores it as a one-event session flagged snapshotOnly. It rides the exact machinery we admired in Hotjar's version, because it is the replay serializer doing the work: the snapshot renders in the page's authored theme, inputs are masked by the same rules as replay, anything tagged data-usero-block is absent, and so is the widget. In the dashboard it plays as a still frame where a recording would be, so a one-line bug report still shows you the page it happened on.

Usero dashboard showing a page snapshot as a still frame of the page a feedback report came from
ScreenshotA page snapshot in the dashboard: the page at the moment of submit, masked, widget excluded, attached to the report it explains.

And because the modes are enforced at the server, Ask first is honest in both directions: a recording session in Ask first mode is only accepted when the SDK proves the snapshot was both consented and snapshot-only, and Never rejects the create outright. A spoofed or stale client cannot widen what gets stored.

What we did not build yet is the badge. Hotjar discards the visitor's decision before the owner can see it, and right now a declined snapshot in our inbox is just a report with no picture, which is the same failure with a better excuse. A consent column on the feedback row is the obvious next night. Hotjar's screenshot machinery earned its place in this series; the asking is where we think the craft still has room. All asking first cost us was swapping the order of two steps.

Build a feedback loop your team actually uses

Usero collects, clusters, and turns user feedback into shipped fixes.

Get started free