- Gate session-replay scripts before they load because a replay session may be created at load time.
- Consent does not filter bots in opt-out jurisdictions where marketing consent can default to on.
- Run browser checks after hydration using navigator.webdriver and a maintained user-agent bot list.
- Default to recording when the signal is uncertain, then test both bot detection and normal-browser protection.
- Keep replay-capacity controls separate from broader analytics, advertising, and conversion measurement decisions.
When a session-replay vendor creates a tracked session as soon as its script loads, the decision that protects your replay capacity happens before the script tag reaches the browser. Filtering records later may improve reporting, but it cannot recover capacity already consumed.
I recently applied this pattern to our Next.js marketing site. The lesson is broadly useful for any team that uses session replay alongside consent management, analytics, advertising pixels, and browser-based QA.
The decision: which browsers should load session replay?
Session replay is valuable because it shows how visitors move through a page, encounter a form, or abandon a flow. It also has a finite monthly session allowance. Lucky Orange's developer documentation says it creates a visitor profile and session immediately after it has loaded, and its plans are sold by monthly sessions tracked.
That changes the engineering question. The goal is to decide whether a browser is likely eligible before loading the replay script.
For our implementation, eligibility required two conditions:
The visitor had marketing consent under the applicable consent rules.
The browser was not conservatively identified as likely automation.
We left GA4, Ahrefs Analytics, and advertising pixels outside this specific bot gate. They are part of broader measurement workflows and are not priced by recorded sessions. A replay-capacity control should stay focused on the cost and behavior it is intended to govern.
Why consent alone does not protect replay capacity
Consent determines whether a category of tools may load. It does not determine whether the browser represents a person.
Our consent model illustrates the issue:
Consent context | Default analytics and marketing state | Replay-capacity implication |
|---|---|---|
| Off until consent is granted | A crawler generally does not load marketing tools until consent changes. |
| On by default | An automated browser can load marketing tools unless another pre-load control intervenes. |
Global Privacy Control | Both off | Replay does not load. |
For a US visitor, a crawler can arrive with default marketing consent and therefore qualify for a replay script under a consent-only implementation. This is especially relevant for teams that run automated checks against production pages.
The load-time gate: consent plus a conservative browser heuristic
Our site uses the Next.js App Router and loads consented third-party scripts with next/script and the lazyOnload strategy. The replay script starts in an unloaded state. After hydration, a client-side effect evaluates the browser and enables the script only for an eligible visitor.
The key constraint is rendering. The replay script must never be rendered on the server and must never be rendered for a browser the gate identifies as likely automated.
The client heuristic has three rules:
When
navigatoris unavailable, returnfalse. Server-side rendering has no browser navigator, and the later client effect performs the real check.When
navigator.webdriveris true, returntrue.Otherwise, evaluate
navigator.userAgentwith isbot, a maintained list for user agents that identify themselves as bots.
Here is the shape of it, trimmed from our component:
// is-likely-bot-client.ts
import { isbot } from "isbot";
export function isLikelyBotClient(): boolean {
if (typeof navigator === "undefined") return false; // server render: no decision yet
if (navigator.webdriver) return true; // automation-controlled browser
return isbot(navigator.userAgent); // self-identifying crawlers and headless UAs
}
// ConsentGatedMarketingScripts.tsx (trimmed)
const consent = useConsent();
const [loadLuckyOrange, setLoadLuckyOrange] = useState(false);
useEffect(() => {
if (!isLikelyBotClient()) {
setLoadLuckyOrange(true);
}
}, []);
return consent.marketing && loadLuckyOrange ? (
<Script
src="https://tools.luckyorange.com/core/lo.js?site-id=YOUR_SITE_ID"
id="lucky-orange-script"
strategy="lazyOnload"
/>
) : null;The state begins as false. That matters. It prevents accidental server rendering and avoids loading session replay before the browser-side decision is complete.
Teams building modern marketing sites can apply the same rendering discipline in a Next.js implementation: defer the vendor script, make eligibility explicit, and keep third-party tags from loading by default simply because a component rendered.
Why the gate runs after hydration
navigator belongs to the browser. It is unavailable during server-side rendering, so user-agent and webdriver checks must run after hydration.
There is a tradeoff here. The gate adds a small decision step before replay begins. In exchange, it keeps likely automation from loading the vendor script at all. For session replay, that is the point where capacity is preserved.
I also prefer a conservative failure mode: when the browser signal is unavailable or unclear, record the visitor. A false positive can remove a real person from a tool the business relies on for behavioral evidence. A false negative may allow some automation through. This is a measurement judgment, not a claim of complete bot defense.
What this catches, and what it cannot catch
Our own Playwright checks run against live landing pages and conversion tracking. Those sessions are automation and should not consume replay capacity. Per MDN's reference for navigator.webdriver, the property is true when Chrome runs with --headless or --enable-automation, and when Firefox runs under Marionette, so that one signal handles an important class of QA traffic.
The user-agent check covers recognizable crawlers and headless user agents, including Googlebot and HeadlessChrome. It does not establish that every remaining browser is human. The isbot README is explicit that it identifies bots that announce themselves in their user agent and does not try to catch malicious programs disguised as real users.
Lucky Orange also has its own bot detection intended to limit bot-generated recordings. The application-level gate complements those vendor controls. It gives the site owner a clear, testable decision before the replay script is loaded.
Test the gate as a business rule
Third-party script conditions can look correct in a code review and still fail at the edges. I treat this kind of logic as a business rule: some visitors should receive the replay tag, and some should not.
Our unit tests cover the cases that matter for both detection and false-positive protection:
navigatorunavailable returnsfalseduring server-side execution.Normal Chrome and Safari user agents return
false.Googlebot returns
true.HeadlessChrome returns
true.navigator.webdriver === truereturnstrue.
Testing ordinary Chrome and Safari is as important as testing automation. A broad user-agent rule that blocks normal visitors may conserve replay capacity while quietly removing useful customer evidence.
Keep measurement purposes separate
A common mistake is treating every marketing tag as though it has the same cost model and the same purpose. Replay capacity, web analytics, ad-pixel audiences, conversion events, and content measurement each answer different operational questions.
For example, route-aware page-view handling may still be necessary for paid-media measurement on a site that uses client-side navigation. That is a separate concern from replay capacity. We covered that distinction in our discussion of client-side navigation and paid-media audiences.
The practical outcome is a simpler tag strategy: document what each script represents, when it may load, what it costs or affects, and how its data will be validated. This kind of planning belongs in a broader measurement and marketing engineering program, with application behavior and consent rules reviewed together.
A related lesson from form-start tracking
The same source-of-truth principle applies to event tracking. Earlier in October 2026, we corrected a contact-form event that used onFocusCapture for GA4 form_start. Programmatic focus on the first-name field after mount could register as a form start even when the visitor had not intentionally engaged.
We removed that focus handler and retained onInputCapture, limited to once per path and form. We also added a markup contract test. The event now represents user input more closely than browser focus.
The replay gate and the form fix address different systems, but the operating lesson is the same: define the event or resource at its source. Downstream filtering cannot restore clean measurement history or capacity already spent.
Implementation checklist
Confirm when your replay vendor creates a tracked session.
Put the eligibility decision before the replay script renders.
Apply consent first, then a conservative browser-side bot heuristic after hydration.
Use
navigator.webdriverand a maintained bot user-agent library.Start the replay script in a disabled state and enable it only after an eligible client-side result.
Test server execution, ordinary browsers, known crawlers, headless browsers, and webdriver detection.
Verify that broader analytics and advertising measurement retain their intended behavior.
Review the result with live-browser QA and vendor reporting after release.
How we know
I added this replay gate to Endertech.com in commit a5b91491 on October 16, 2026. The implementation uses a Next.js client-side effect, navigator.webdriver, and isbot(navigator.userAgent). It keeps Lucky Orange unloaded until marketing consent exists and the browser passes the check. The associated unit tests use node:test and cover unavailable browser APIs, normal Chrome and Safari, Googlebot, HeadlessChrome, and webdriver-enabled automation.
The related form-start tracking correction was made in commit 0fc2bedd on October 6, 2026. Both changes are in the site's Git history, along with the tests that guard them. Last reviewed: October 19, 2026.
Limits
We have not measured before-and-after session counts, replay-capacity savings, or cost effects for our site. This article does not claim those results.
The browser gate is probabilistic. It catches common automation signals and self-identifying bots. It cannot reliably identify malicious bots that mimic a normal browser, and it should not be treated as a security control. Vendor-side bot controls remain relevant.
Consent requirements also depend on your jurisdiction, consent platform, configuration, and the tags in your stack. Review the behavior that applies to your implementation before changing production tracking.
Sources
Privacy Tools, Lucky Orange Developer Documentation (accessed October 19, 2026).
Pricing, Lucky Orange (accessed October 19, 2026).
isbot README, omrilotan/isbot on GitHub, version 5.2.2 (accessed October 19, 2026).
Navigator: webdriver property, MDN Web Docs (accessed October 19, 2026).
Decide before the script loads
If your replay tool is consuming capacity from automated browsers, begin with the exact moment a session is created. Then make a small, explicit, testable eligibility decision before the replay tag loads. That approach preserves human recordings while keeping replay-specific controls from disrupting unrelated measurement.
My view: a vendor snippet makes adding a tool trivial, and that is exactly why most stacks never decide who should get it. Deciding which visitors load which script is engineering work. Treat it that way, with code review and tests, and your behavioral data stays worth looking at.
If you are reviewing consent, session replay, and conversion tracking together, talk through your measurement architecture with Endertech.
