npm / posthog-js
posthog-js
What changed in posthog-js 1, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-17.
36 breaking20 security13 deprecations186 new APIs and options27 performance141 behavior and defaults4 tooling398 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli initposthog-js 1825 changes
Breaking changes 36
Calls before logging setup are now dropped instead of buffered.
Calls before logging setup are now dropped instead of buffered.
The content ignorelist now suppresses false rageclicks from carousel and pager controls, with expanded keyword and control-label matching; set it to false to retain capture.
Default network metric attributes now use OTel HTTP client semantic conventions instead of the previous attribute names.
Sending and retention of group identification now depend on person processing mode and group association behavior.
identify now requires a distinct ID, matching the existing runtime validation.
Bigint attributes on logs, metrics, and spans are sent as int64 rather than strings.
Values from the closest element now take precedence when the same property exists on multiple ancestors.
Prefilled surveys no longer send survey sent before completion, and partial events include only auto-advanced answers.
Browser-injected user script exceptions are no longer captured by default; set this option to true to keep capturing them.
Reports without a code position no longer receive a document-URL stack frame, so these exceptions arrive without a stack trace.
Non-repeatable triggered survey activation is now scoped to the triggering session and cleared in a new session.
When remote config omits autocapture_opt_out, the SDK retains the last known server value instead of enabling autocapture.
Enum members no longer work as standalone type annotations; use the exported union types instead. Runtime values are unchanged.
Stops sending and drops log batches after 3 consecutive status 0 failures while online; the online event reopens it, while genuine offline periods still queue for reconnect.
host moves from resource attributes to record attributes in console logs; saved queries using the old location need updating.
The canonical console-log person identifier changes from distinct_id to posthogDistinctId.
Console-log session identifiers move from resource.attributes.session.id to the standard sessionId record attribute.
Console-log page URLs move from location.href to the standard url.full record attribute; saved queries using the old name need updating.
window.id moves from resource attributes to record attributes in console logs; saved queries using the old location need updating.
Event triggers no longer support arming a survey on one full page load and displaying it on a later one; use audience targeting instead.
Event-triggered survey activations remain in memory until shown, then persist across reloads; unshown activations no longer reappear after reload.
Symbol-only keywords match element text exactly, and default stepper buttons are ignored, changing suppression of controls containing symbols such as
>or<.OpenTelemetry logs dependencies are no longer installed transitively by consumers; projects importing them directly must declare their own dependencies.
Writing to a resolve ticket is no longer allowed; developers must start a new ticket instead.
Renames the public tracing-headers configuration option for linking LLM traces to session replays.
CLI and sourcemap utilities moved from @posthog/core to @posthog/plugin-utils, removing cross-spawn from React Native dependencies.
rrweb and related dependencies are no longer placed directly on window by posthog-recorder.
The legacy config loading path was removed.
The __preview_remote_config gate was removed from config loading.
Renames setTestUser to setInternalOrTestUser; update calls to the new API name.
Attribution is now opt-in by default, reducing memory usage.
The minimum supported Preact version is now 10.28.2.
Renamed evaluationEnvironments to evaluationContexts to clarify that values specify evaluation contexts such as web, mobile, or checkout.
extendUrlParams now replaces URL parameters by default unless the caller explicitly chooses otherwise.
rrweb types are no longer required as a peer dependency when using posthog-js.
Security 20
Fetch requests now default to strict-origin, omitting page paths and query strings from referrers.
Prevents buffered session replay data from crossing projects that share a persistence name during page navigation.
Replay URL privacy settings now apply to URL values in captured JSON-LD payloads.
Replay redaction preserves safe JSON-LD properties and allowlisted structure while restricting IDs, types, and payloads.
Legacy product tour HTML is sanitized before rendering, reducing the risk of unsafe HTML being rendered.
Captured console records are now dropped when the user opts out.
Clipboard autocapture now records paste interactions without collecting the pasted text.
Initial navigation and performance-timing entries now use the masking callback, preserving privacy while retaining required replay timing metadata when filtered.
Masks all source DOM string attributes, including rendering attributes and synthesized form values, with reduced replay fidelity.
Configuring maskRegionsFn disables canvas pixel serialization in DOM full snapshots, preventing unmasked canvas stills from being embedded.
When ancestor checks for ph-no-capture or ph-sensitive cannot finish, the element is treated as not capturable.
Auto-captured console logs now pass through logs.beforeSend, allowing sensitive console output to be redacted or dropped before sending.
Product Tours styles now use the CSP stylesheet preparation hook, improving compatibility with Content Security Policy requirements.
Credential-bearing headers are redacted in both requests and responses, including custom names containing credential-shaped substrings, preventing token and cookie capture.
Style mutation diffing no longer causes style-src-attr CSP violations.
Style and script elements appended by site apps now receive CSP nonce preparation hooks.
Consumers no longer install transitive protobufjs from posthog-js, avoiding its unsafe-eval Content Security Policy issue.
Avoids cross-origin property access when calling the previous unhandled rejection handler.
An iframe leak in the untainted prototype is prevented, along with unnecessary iframe creation.
Textarea innerText mutations are now masked during recording.
Deprecations 13
The preview cookie conflict option is deprecated in favor of cookieWinsOnConflict.
Deprecates the double-underscore bucket-size option while continuing to honor it as a fallback.
Deprecates the double-underscore refill-rate option while continuing to honor it as a fallback.
__preview_disable_beacon is deprecated in favor of disable_beacon.
Deprecated as a no-op because session replay lazy loading is now the default.
The no-op browser SDK config option is deprecated because the SDK already uses the /flags/?v=2 endpoint by default.
__add_tracing_headers remains available as a deprecated alias for tracing_headers.
addTracingHeaders remains available as a deprecated alias for tracing_headers.
The old tracing-headers configuration alias continues to work but is deprecated on the browser SDK.
Manual capture of $exception now produces a warning.
Element steps are deprecated as product tour steps are unified with modal steps.
The posthog.init option remains functional but logs a deprecation warning and will be removed in a future major version.
The package is deprecated, so developers should avoid adopting it for new usage.
New APIs and options 186
WebMCPExtensions is now exported from the slim extension-bundles entry point, making it available to consumers of that entry point.
Adds a private opt-in to preserve application stacks for failed fetch requests.
Adds opt-in capture of WebMCP tool calls for MCP Analytics.
A new opt-in helper flags likely WebView bots for tagging or dropping events via before_send; default SDK behavior remains unchanged.
OpenAI Ads click identifier oppref is captured as a campaign parameter, included on events, and stored as $initial_oppref.
Adds a subscription API for survey eligibility updates with safe unsubscribe and recoverable load-error reporting.
Adds a config limit for feature flag request retries, defaulting to 1 and allowing 0 to disable retries.
The Meta browser ID is captured as a person property so backend conversions can use it later.
Setting this switch to false disables reading the Meta
_fbcand_fbpcookies.Adds a resetError callback to React error-boundary fallbacks, allowing applications to retry rendering without remounting the boundary.
Adds network metrics configuration to record fetch and XMLHttpRequest durations as histograms, with optional custom names and attributes.
Adds require-able bundle entry points for desktop apps and CSP-restricted builds, avoiding deep imports from dist/.
Segment integration accepts filterProperties to filter PostHog-generated enrichment properties before events reach destinations.
Adds best-effort in-app browser attribution using $webview_app and $webview_app_version while preserving existing browser values.
Captured replay events now expose why an epoch's recording buffer is being held.
Browser identify calls now support reuseAnonymousId.
Session replay can opt into a DOM mutation byte budget; excess mutations are dropped and recording resyncs with a full snapshot.
The DOM mutation budget refills at 25KB/s by default, controlling the sustained mutation rate before mutations are dropped.
Captured events now report discarded session-recorder attribute changes so developers can query whether recordings are affected.
Adds opt-in Schema.org JSON-LD capture to session replay, emitting sanitized JSON-LD as custom replay events and excluding script elements from snapshots.
Configure web vitals attribution with false, true, or an array naming the metrics.
Now accepts path, search, and hash options to trigger $pageview events when selected URL components change during SPA navigation.
Adds an option that keeps shared cross-subdomain identity and session state ahead of stale per-origin localStorage.
A new observability payload field reports focus-change delay for dead-click detection.
Adds a fallback mode for strict script versioning to support legacy asset paths when needed.
Abandoned deferred stylesheet work is now counted through a dedicated debug telemetry event.
Residual deferred stylesheet failures are now counted through a dedicated debug telemetry event.
Adds reset options that apply bootstrapped identity, feature flag, and session values after reset while preserving the legacy boolean argument.
Adds rewriteRequestPath to customize API, feature flag, and asset paths for reverse proxies.
Adds an appearance field to show an optional survey intro screen before question 1.
Exports a constant representing the intro screen preview page index.
Adds the button text setting used to dismiss the optional survey intro screen.
Adds the description text for the optional survey intro screen.
Adds the content type setting for the intro screen description.
Adds the header text for the optional survey intro screen.
Adds previewPageIndex -1 to preview the survey intro screen.
Exports the unavailable-reason type from package entry points so consumers can name the type.
Exposes the specific reason the conversations API is unavailable, enabling callers to record why they fall back to another channel.
Adds per-attribute control over the final serialized value in session replay.
Adds a captured-event metric reporting deferred stylesheet work.
Adds a captured-event metric reporting the CSS rule count associated with the slowest full snapshot.
Adds a captured-event metric reporting the slowest full snapshot duration.
Adds a captured-event metric reporting the node count associated with the slowest full snapshot.
Adds a captured-event metric reporting the slowest full snapshot stylesheet processing duration.
Adds a captured-event metric reporting the slowest incremental mutation batch duration.
Adds a stylesheet CSSRule budget per snapshot, defaulting to 10,000; setting 0 restores unbounded inlining.
Opting in scopes web vitals to soft navigation entries, preventing inflated measurements after SPA route changes.
Adds sampling controls to disable or throttle mousemove capture and optionally mouseInteraction in session replay.
Adds a browser-v1 client adapter for shared extensions with analytics, request, persistence, replayed remote-config outcomes, and synchronous best-effort cleanup.
Adds getInjectedReleaseId() to @posthog/core for reading the release ID injected by posthog-cli.
Adds an opt-in time budget for yielding during long seek rebuilds, preventing page blocking; newer seeks cancel in-flight rebuilds. Default 0 preserves synchronous behavior.
Adds a per-frame canvas masking function that paints returned CSS-pixel regions black before encoding, enabling masking of canvas-rendered content DOM masking cannot see.
Accepts defaultValue when a flag has no value and narrows the return type to boolean.
The pending session recording trigger buffer interval is now configurable.
Adds configurable dead swipe capture, enabled by default, for touch gestures that produce no observable screen change.
Adds a per-page-load cap of 10 dead swipe captures by default.
Adds the pixel threshold used to detect dead swipes, defaulting to 30 pixels.
Touch swipes with no observable screen change are now captured as
$dead_swipeevents.$feature_flag_called events now include a boolean indicating whether the feature flag has an experiment when explicitly reported by the server.
Adds count, gauge, and histogram metrics recording to posthog-node, with in-memory aggregation and flushing to /i/v1/metrics.
Adds the current masked hostname to every session recorder $snapshot event, unless masking removes it or it cannot be parsed as a URL.
Adds an attribute allowlist passed to MutationObserver, reducing recording CPU from mutations to unlisted attributes.
Adds exceptionRateLimiterBucketSize as a first-class error tracking rate-limiter option.
Adds exceptionRateLimiterRefillRate as a first-class error tracking rate-limiter option.
Adds metrics configuration for service identity, flush timing, series limits, and a before-send hook.
Adds an alpha statsd-style metrics client with count, gauge, and histogram methods that pre-aggregate samples and periodically flush metrics.
Adds a survey appearance option that prevents open-text questions from stealing focus in embedded surveys; defaults to false.
Custom survey integrators can mark surveys as seen while honoring already-seen and wait-period checks.
Browser clients now support graceful shutdown, best-effort event flushing, and always-resolving teardown.
Adds a config option to provide the logical URL used for client-side URL targeting; defaults to window.location.href when unset.
Adds a synchronous API returning cached feature flags as structured FeatureFlagResults without sending a $feature_flag_called event.
Adds an option to opt out of capturing and sending the Android Chromium device model.
Adds opt-in streaming network body capture that bounds memory and pre-request latency for very large bodies.
Adds an option to strip URL fragments from automatically captured URLs; it is enabled automatically when config.defaults is '2026-06-25' or later.
Auto-captured console logs identify their console method through log.source, while manual logs leave it unset.
The canvas FPS-snapshot observer accepts an optional resolution scale record option for downscaling captured frames.
Adds a fractional canvas capture scale to reduce replay frame pixel area while preserving the canvas display dimensions and aspect ratio.
Adds a log hook to inspect, redact, modify, or drop records before sending, including logs from captureLog() and logger.*.
Adds CSS selector opt-outs that apply only to autocaptured web interactions.
Capture options now accept $unset and pass it through in browser capture payloads.
Adds a counterpart to setPersonProperties() for removing person properties without manually passing a $unset array in capture().
Enables a Back button for multi-question web surveys, preserving branching navigation and prior answers while pruning abandoned-branch responses before submission.
Overrides the default Back button label in web surveys.
Adds survey-level translation support for the Back button label.
Adds survey-level translation support for the submit button label.
External dependency script versioning is now supported through the asset_host config option.
External dependency script versioning is now supported through the strict_script_versioning config option.
Adds a configuration option to detect the Google Search App as its own browser value.
Stores feature-flag configuration in a separate localStorage entry to reduce main-blob writes and cross-tab storage-event broadcasts.
Adds an opt-in config to prefer cookie values over localStorage when merging persistence state in localStorage+cookie mode, fixing cross-subdomain identify and session disconnects.
Adds the $sdk_dist_channel event property for browser SDK npm and cdn distribution channels.
Adds a config option to debounce localStorage and cookie writes while keeping in-memory props updates synchronous.
detectBrowser and detectBrowserVersion accept an optional BrowserDetectionHints argument with a brave flag for identifying Brave browsers without a user-agent marker.
Adds a boolean captured-event property showing whether starting the rrweb recorder was attempted.
Adds a config option to restrict browser feature flag remote evaluation to specific flag keys.
Adds a configuration option to exclude specific elements from dead-click detection without affecting autocapture, session replay, or heatmaps.
Adds a CSS class to exclude specific elements from dead-click detection without affecting autocapture, session replay, or heatmaps.
capture() now accepts an optional uuid on CaptureOptions.
React Native now supports translated survey rendering, with shared survey translation logic through @posthog/core.
Exposes the tracing-header fetch patch implementation from @posthog/core for reuse by non-browser SDKs.
Adds a preview flag for versioned browser lazy bundle asset paths.
Adds an API for sending structured log entries to PostHog logs.
Adds support for pre-loaded remote-config, allowing developers to use remote configuration loaded before initialization.
Adds customer side identification for developers using posthog-js.
Exposes the current survey question index on .survey-box, including link questions without input or rating elements.
Adds a tree-shakeable ESM entry point for slim builds.
Scopes $feature_flag_called deduplication to the current session.
Adds an internal method for wrapper SDKs to override $lib and $lib_version event properties.
Adds a serviceName option to the logs configuration.
Adds an Extension interface for authoring tree-shakable extensions.
Adds a local sampleRate configuration option for session recording.
A new recorder status was added for tracking recording state.
Adds a configuration option to prevent stale feature flag values.
Adds a configuration option to control automatic feature flag refresh frequency in long-running sessions.
Adds support for configuring a wait period for product tours.
Product tours can target users by device type.
Adds the ability to retrieve previous conversations.
Feature flag APIs can now return only values loaded from the server, excluding cached localStorage values.
Adds an animation option for tour banners, allowing developers to configure their presentation behavior.
Added support for localizing product tours.
Support for multiple tickets was added, enabling developers to work with more than one ticket.
Product tours now support customizable text for survey step buttons.
Adds a replay debug property indicating that the DOM depth limit was exceeded.
Added the OverrideFeatureFlagsOptions type to the PostHog interface.
displaySurvey now has an option to disable survey shown tracking.
Adds the $feature_flag_error property to $feature_flag_called events.
Added featureFlagsReloading to on() event types.
Adds support for configuring widget position.
Adds isTestUser() for identifying test users.
Adds the test_user_hostname configuration option for identifying test users.
Product tours now support placing the banner in a custom container.
Adds the getFeatureFlagResult method for retrieving feature flag results.
Product tours now support linked flags.
Web vitals can now be used with or without attribution.
Adds a config option to control where external scripts are injected.
Popover surveys now support prefilled questions.
Adds the useThumbSurvey hook for thumb surveys.
Added URL parameters to the PostHog logo in the surveys footer.
Adds support for thumbs up/down survey rating scales.
Product tour announcements now support display frequency options.
The z-index is now configurable, allowing developers to control the stacking order of PostHog UI elements.
API survey events now allow custom properties.
Product tour steps now support button actions, enabling developers to add actionable buttons to tour steps.
Added an extension for PostHog Logs, enabling developers to use Logs functionality with posthog-js.
Adds position options to modal and survey tour steps, allowing developers to control their positioning.
Adds product tour element inference for developers using product tours.
Conversation API methods are exposed for building custom user interfaces.
The default stack parser creator is exposed for developers to use.
Conversation enabling is separated from enabling the conversations widget, allowing developers to control them independently.
A new library provides proper typing for window.posthog when using the script version of posthog-js.
Allows opting in to store selected properties in cookies when using localstorage+cookies persistence mode.
Adds updateFlags() to inject feature flag values from an external source without making a network request.
Supports merge: true to merge injected flags with existing flags instead of replacing them.
Product tours now support custom appearance and cleaned-up animations, allowing developers to customize tour presentation.
Exception autocapture can now be programmatically enabled or disabled.
Product tours now support event and action triggers.
A new survey abandoned event is emitted when users leave the page.
Text colors can now be customized for web and React Native.
Survey event property filters now support less-than and greater-than operators.
Adds support for building survey steps specific to tours.
Introduces a conversations widget for developers using posthog-js.
Survey appearance now supports hideCancelButton.
Product tours now support survey steps, allowing surveys to be included in tour flows.
Product tours support auto-show configuration, allowing tours to appear automatically.
Product tours add modal steps for presenting tour content in modals.
Product tours are introduced in a super-alpha state for developer use.
Actions now support all filter options, allowing developers to use the complete set of available action filters.
Adds evaluation timestamp properties to $feature_flag_called events.
Surveys now allow customization of text input and background.
Adds a payload entry to the EarlyAccessFeature type.
Adds support for triggering surveys from actions filtered by event properties.
Adds support for customizing the positions of the survey feedback button.
Rageclicks can now be ignored based on their content.
Rageclick detection now supports a configurable click count while preserving previous default behavior.
Rageclick detection now supports a configurable pixel threshold while preserving previous default behavior.
Rageclick detection now supports a configurable timeout while preserving previous default behavior.
Adds support for a strict minimum duration, providing more accurate measurements on full page load.
Feature flags can now be bootstrapped during server-side rendering in ReactJS.
Adds the flags_api_host configuration option for specifying the flags API host.
Adds a URL parameter that enables automatic survey submission.
Adds URL parameters for prefilling survey answers by zero-based question index.
Configures the delay before automatically submitting a completed survey.
Enables automatic submission when URL-provided answers are complete.
Enables prefilling surveys from URL parameters.
Adds bot pageview collection when the preview flag is enabled, tracking bot traffic as $bot_pageview events.
Added a component that wraps components and captures an event when they are in view in the browser.
Performance 27
The replayer batches large mutation adds against a detached subtree, preventing tab freezes and reducing blocked main-thread time.
Session recording avoids per-node traversal callbacks when DOM subtrees are moved repeatedly.
Session recording avoids empty child-list reads for text nodes during mutation processing.
Session replay reduces DOM traversal overhead by reusing native-accessor cache keys for node access.
Session replay avoids repeatedly traversing a subtree when it moves multiple times in one mutation batch.
Session replay reduces per-node allocations by reusing serialization options within each emission.
Session recording performs fewer shadow DOM connectivity checks.
Requests now use the best available compression, preferring gzip when supported.
npm source maps no longer embed TypeScript sources, reducing the unpacked package size while preserving source-map chaining.
Deferred inlining now processes 200 rules per idle slice and emits each sheet atomically, avoiding long tasks and partial CSS transmission.
Stylesheets beyond the snapshot budget omit
_cssTextand are inlined later during idle callbacks, reducing blocking work while preserving replay fidelity.Small base64 images are no longer synchronously recompressed; larger images are memoized and retained when recompression is not smaller.
Improves console log capture performance for truncated large objects.
Bundled OpenTelemetry dependencies are removed, shrinking the lazily-loaded logs chunk.
save() skips storage writes when serialized props are unchanged, reducing unnecessary localStorage writes and cross-tab storage events.
Persistence writes are throttled to 5-second granularity, reducing localStorage pressure and cross-tab storage event broadcasts while flushing pending values on tab close.
Improved serialization performance for console logs involving large objects.
Session recording events use native asynchronous gzip compression when CompressionStream is available.
The bundle drops postcss and shrinks from 420KB to 170KB.
Reduced memory and CPU cost by caching gzipped empty arrays and eliminating redundant JSON.stringify for size estimation.
Uses async native CompressionStream for gzip compression to avoid blocking the main thread.
Reduced the browser SDK bundle size by approximately 6.6 KB (3.7%) through code and build optimizations.
Feature flags can now be tree-shaken, potentially reducing bundled client code.
Session replay reduces memory pressure through per-event sizing and FNV-1a canvas frame deduplication instead of storing full base64 strings.
Surveys, toolbar, exceptions, conversations, logs, and experiments can be tree-shaken to reduce unused application code.
URLs are no longer re-checked when they have not changed, reducing unnecessary runtime work.
The product tours bundle is smaller, reducing the amount of JavaScript shipped for this feature.
Behavior and default changes 141
Freebuff click identifier is captured as a campaign parameter, set on events and as $initial_bfcid like other ad click IDs.
Build-time error tracking release IDs are now recognized, improving release association for reported errors.
Native bundler debug IDs are now recognized, improving error tracking for applications using supported bundlers.
WebMCP tool intent and model metadata are now captured by default.
Survey footer branding now uses the new PostHog logo.
Captured events reduce replay debug properties while preserving recording status and capture diagnostics.
$snapshot events report cumulative mutation-drop counts and dropped bytes only when greater than zero.
Logs a console warning when session replay stops capturing canvas frames because of unsupported browsers, CSP restrictions, or a failing maskRegionsFn.
Survey choice and question shuffling is shared between web and React Native through surveys core, using Fisher-Yates for web questions.
Events captured with send_instantly now prefer synchronous compression, including the initial $pageview, avoiding delays in request dispatch.
Cookieless mode skips reading the Meta
_fbcand_fbpcookies.The Meta click identifier is read from cookies, preserving the true ad click time and retaining clicks that occurred before the SDK loaded.
Conversations widget greetings now support clickable [label](url) links.
Internal SDK console diagnostics are excluded from exception autocapture.
Recoverable recorder diagnostics are reported as warnings.
Automatic feature flag refreshes back off on idle visible pages only when this interval is omitted; explicit intervals are preserved.
Retry delays for log exports are capped at 30 seconds, so exports resume sooner after endpoint recovery.
Browser autofill is disabled on input and textarea fields during session replay.
JSON-LD replay events now include the masked page URL.
Unbatched events prefer sendBeacon after PostHog detects page unloading, while active-page transports preserve response capability for retries.
Feature flag APIs distinguish conclusive off evaluations from unavailable evaluations, with different remote and backend local behavior.
Previously persisted feature flags are preserved as an offline fallback when bootstrap flags are provided.
Initializes the Segment enrichment integration when Segment is configured through set_config, so Segment events include PostHog properties such as active feature flags.
The Meta $fbc person property is captured when a new fbclid is observed.
Conversations widget requests now forward generic server-signed identity claims.
Browser SDK logs now include the os.name resource attribute, overridable via logs.resourceAttributes.
Browser SDK logs now include the os.version resource attribute, overridable via logs.resourceAttributes.
Initialization now warns when memory or sessionStorage persistence lacks a stable bootstrap distinct ID.
Now reports Claude, Codex, and ChatGPT instead of Chrome when their user agent markers are detected.
Persistence is synchronized across browser tabs, with successful partial evaluations authoritative for payload updates and removals.
When enabled, privacy handling now also respects navigator.globalPrivacyControl.
Popover surveys now re-translate when the display language changes, while preserving in-progress answers.
Survey events now report the question text and language the user saw when answering.
Config defaults now enable sanitized JSON-LD replay events.
Feature flags refresh when a hidden browser tab becomes visible, while the existing five-minute default and remote_config_refresh_interval_ms behavior remain unchanged.
INP and LCP now capture attribution by default; CLS remains without attribution to avoid memory leaks from detached DOM nodes.
Surveys now use the shared browser extension lifecycle, changing how survey functionality participates in the browser extension lifecycle.
Browser autocapture now uses the shared extension lifecycle.
Debug mode now names unmatched session replay trigger conditions instead of only reporting buffering.
Attributes are capped by nesting depth, object entries and total values, with excess data marked as [Truncated].
React component stacks are rendered as linked exception causes so error tracking identifies the crashing component.
Full browser bundles now inline the whole session recorder instead of fetching the recorder script at runtime.
Sessions are flagged when the recorder script fails to load, making blocked recording visible in analytics.
The new cookie conflict behavior is enabled for the 2026-08-29 defaults.
External dependencies now load from versioned asset paths by default, with automatic fallback to legacy paths.
Styles produced by insertRule and adoptedStyleSheets no longer count against the stylesheet inlining budget.
The default 10,000-rule budget moves into posthog-js session recording options, preserving configured overrides including 0.
Duration samples spanning tab suspension are now discarded and reported through a debug telemetry event.
Supports removing multiple persisted properties in one operation.
The intro is dismissed by a button without recording a response or affecting completion and partial-response metrics.
Intro screen copy supports translation like the thank-you message.
When both masking options are set, maskAllElementAttributes wins, maskAttributeFn is ignored, and a console warning is emitted.
Minimal feature-flag events now retain referring-domain and canonical campaign parameters for session attribution.
Rate limit warnings now report privacy-aware dropped-event counts, page context, and session context.
reset() now logs a warning when opt_out_capturing_by_default silently opts the user out again after opt_in_capturing().
Network-level message send failures are treated as transient, showing a connection message and logging warnings instead of errors.
Calling init() again with a different project token now produces a warning with actionable guidance.
Canvas recording now merges its sampling with user-provided sampling instead of overwriting it.
$exception events now include the injected release ID when available, allowing PostHog to attach exceptions to a release without joining through symbol sets.
Session recording request timestamps are sent in request bodies instead of query strings.
Analytics request timestamps are sent in capture bodies, while query timestamps remain used for session recordings.
SDK library identity is sent in feature flag person properties instead of URL query parameters.
Feature flag timestamps are now sent in ISO format within request bodies.
Capture POST requests now use numeric sent_at timestamps in the query string.
Debug mode now warns when client-side session recording masking options override project-level Privacy and masking settings.
Users can start a new conversation while an unresolved ticket remains open.
When server-controlled minimal flag events are enabled, events omit nonessential properties unless the flag is experiment-linked; before_send may re-add them.
Network-level fetch failures now log at warn instead of error because they are expected and retried by the request queue.
Browser SDK requests no longer include the gzip compression query parameter.
The deprecated ver query parameter is no longer sent to capture and session recording endpoints.
The loaded callback's instance type now includes config, enabling typed access to that property.
Cached survey definitions refresh after a short TTL so server-side survey changes reach long-lived tabs without reloads.
Android Chromium now captures the $device_model super-property during initialization and sends it on subsequent events.
Console-log records now include the standard SDK context field feature_flags.
Auto-captured console logs now use the same pipeline as captureLog() and logger.*, including standard PostHog log processing.
Console logs now use posthogDistinctId for person linking, so they appear on person profiles by default.
The default payload host deny list now skips more third-party analytics, RUM, and session-replay telemetry hosts without replay value.
The latest defaults bundle opts new installs into a 0.6 canvas capture scale, while the option itself defaults to full resolution.
Product tours follow the updated event-trigger activation and persistence model.
Retries are limited for transport failures without an HTTP response.
Log delivery now splits oversized batches automatically, making browser programmatic logs more resilient.
Failed log sends now retry with exponential backoff, improving delivery resilience.
Session replay now records native fullscreen transitions and reapplies fullscreen layout during playback, including when scrubbing into fullscreen regions.
onSessionId handlers now receive crossTabAdoption when adopting a sibling tab's session, so session-scoped state can follow the new session.
Volatile flag and survey metadata changes no longer rewrite split-storage entries or rebroadcast full payloads unless content changes.
Feature flags now reload by default when resetting person properties for flags.
__preview_disable_xhr_credentials is now a no-op.
The Google Search App is reported as Google Search App instead of Mobile Safari or Chrome when enabled.
The 2026-05-30 config defaults enable Google Search App detection automatically; other configurations remain opt-out by default.
Partial rageclick configuration objects merge with date-gated defaults; explicit values can override individual defaults or disable the feature entirely.
Browser tracing header configuration is now publicly supported through tracing_headers.
The 2026-05-30 config default automatically enables a 250ms debounce window.
$web_vitals reporting is now enabled when cookieless mode is enabled.
Open text survey questions submit with Cmd/Ctrl+Enter while plain Enter continues inserting a newline.
Survey translation logs are now gated behind SDK debug logging to avoid production console spam.
Browser surveys can render translations, enabling localized survey experiences.
Browser surveys track language, supporting language-aware survey behavior.
The OTLP scope.version field now contains the SDK version, changing the server instrumentation_scope value.
SDK-owned persistence keys now require explicit classification as event-visible, hidden, or derived, affecting which persistence state can appear in events.
Adds exception steps to error tracking, also known as breadcrumbs.
Active feature flag payloads are excluded from event properties, reducing unwanted data in captured events.
Adds handling for session replay trigger groups in V2.
Numeric survey rating options now show a hover state, providing clearer pointer feedback before selection.
Consent persistent store is re-evaluated when config changes, enabling cross-subdomain consent sharing.
Rejects the strings "undefined" and "null" as distinct IDs, and invalid IDs now always log a critical console error.
Anonymous users are automatically identified during the relevant bootstrap flow.
Calling reset() now automatically reloads feature flags.
Compressed requests now use ArrayBuffer for request data.
The recorder now outputs an event when recording starts.
Undated persisted recording configs are now treated as stale, so recording waits for a fresh remote config before starting.
$user_state is now persisted to a cookie, enabling server-side access.
Tours now track clicks on banners.
config.js is now the sole config loading mechanism for posthog-js.
Replay now applies a DOM depth limit, affecting how deeply nested DOM content is captured.
Product tour images are preloaded, which may improve image availability during tours.
The z-index ordering was updated so tours appear above surveys, which appear above conversations.
Tours are now enabled by default, so applications using tours no longer need to enable them explicitly.
Adds product tour button clicked events for tracking interactions with product tour buttons.
Survey shown tracking was added to useThumbSurvey.
Markdown is now rendered in the support product.
Element inference is enabled for product tours, affecting how tour elements are identified.
sendMessage now sends context with the message.
Tickets now include more context when created, helping developers provide richer information in ticket records.
The support product no longer has a loading state.
Adds cache and URL-change tracking for regex behavior.
The logs extension no longer requires preflight requests.
Product tours now support banner rendering.
Adds first snapshot timestamp logging for monitoring and debugging purposes.
Product tours now support rich content.
Product tours now support multiple pages, enabling tours to span more than one page.
Adds a person property for the last-seen survey date to provide more consistent behavior across browsers and devices.
Lifecycle start events now include targetSessionID.
Product tour steps can progress when users click an element.
Feature flag requests now include $device_id, allowing flag fetching to use the device identifier.
console.error capture now includes synthetic exceptions.
Adds events for survey cancellation.
Overriding feature flags now outputs a confirmation log message, helping users know whether the action actually took effect.
Initialization now yields to the main thread, helping avoid blocking during posthog initialization.
Tracks the flushed size for each session, changing session-level telemetry behavior.
Session recordings now store the previous and next session ID, providing additional session context.
Exceptions thrown from the PostHog SDK are excluded from capture.
Tooling 4
TypeScript declarations are now published under public dist paths for browser extension entrypoints.
Browser devtools now attribute console messages to the calling code instead of posthog-js's console wrapper.
Release tooling now recursively publishes dist/toolbar/ bundles with explicit JavaScript MIME types and supports the canonical toolbar.js/toolbar.css layout.
The rrweb worker sourcemap is shipped from posthog-js/dist so downstream bundlers need not access rrweb internals.
Fixes and other changes 398
Backward device clock changes no longer subtract client rate-limit tokens.
WebMCP failures are captured in Error Tracking when exception autocapture is enabled; slim builds require this extension alongside WebMCPExtensions.
Callback types now accept non-null events while still allowing null returns to drop events.
Captures WebMCP error types and sanitized messages.
WebMCP intent and model injection are skipped for schemas whose constraints could be broken by the additional fields.
Publishes the feature flag types imported from @posthog/browser-common, fixing type checking in posthog-js.
Feature flag functionality is shared across browser SDKs while preserving existing behavior.
Events carrying pending Meta $fbc or $fbp identifiers are batched again, reducing races with preceding identify() calls.
Stops a SecurityError from escaping the recorder when an iframe becomes cross-origin during shadow DOM observation startup.
Preserves shared identity while consent is pending and clears it after shared rejection in cookieless mode.
Cross-subdomain identity continuity is fixed when users opt in after cookie consent.
Registered properties are preserved across initialization and configuration updates when persistence writes are debounced.
Session attribution is preserved across initialization and configuration updates when persistence writes are debounced.
Fixes a DataCloneError when session replay records network timing inside a cross-origin iframe.
The debug signal now reflects rrweb's own recording state.
Session recording now starts at DOMContentLoaded, allowing recording when the page load event is delayed or never fires.
PostHogFeature without match now shows the fallback when the flag evaluates to false.
Initialization no longer writes analytics persistence data when persistence is disabled or opted out.
Replay masking callback errors are isolated so unrelated network records continue to be captured.
Survey URL prefill values preserve equals signs, while malformed URL parameters no longer block surveys.
CSS-in-JS styles remain available after a large DOM change in the page head.
Buffered data is preserved when a held recording epoch reaches the size cap.
The modern replay network masking callback is honored when both modern and deprecated hooks are configured.
SPA $pageview events from pushState/replaceState navigations no longer carry the previous page's title.
Fixes useThumbSurvey to use the client passed to PostHogProvider, enabling survey event capture.
Replay loads recorded fonts under the replay iframe's content security policy instead of the embedding page's.
Cross-domain cookie probes are avoided when cross-subdomain cookies are disabled.
SDK initialization now works when a script loader pre-creates window.posthog as a placeholder object.
Session replay no longer defers input setter hooks on zone.js's patched setTimeout, preventing repeated Angular change detection and endless high-CPU loops.
Dead-click detection now survives denied DOM property access in Firefox and continues refreshing the liveness timestamp.
Session replay network capture starts in frames without PerformanceObserver or supportedEntryTypes, recording without live network timing.
Session recording stays active when a cross-origin image or video taints a canvas.
Dead clicks are no longer reported for controls inside open shadow roots when clicks update content within the shadow root.
Prevents $session_id from being sent as null when a sibling tab resets the session before this tab captures its first event.
The browser SDK retries feature flag requests on HTTP 502/504 responses and request timeouts.
Survey answer snapshots and response event properties are shared with React Native for consistent partial response reporting.
Replay network waterfall now captures document navigation timing when recording starts after page load and avoids partial duplicates during loading.
Survey shuffling no longer mutates configured choices.
Survey shuffling preserves the Other choice as the last choice.
Canvas settings are no longer changed when canvas capture fails to start.
Adds a session diagnostic when stale replay configuration cannot be refreshed, without changing recording behavior.
URL prefill continues working when localStorage is unavailable, including on opaque-origin pages or in private browsing.
The recorder no longer treats this resource hint as a stylesheet, preventing duplicated CSS in full snapshots and failed stylesheet deferrals.
Contains throws from third-party patched abort calls during fetch timeouts so requests retry instead of producing uncaught errors, with one outcome reported per request.
Captures causes and AggregateError members with relationship metadata and individual stacks, limiting output to 50 entries and 1,000 member inspections.
Keeps observers that initialized successfully when another observer fails, and reports failed observers in recorder debug properties.
Drops an oversized replay event when it cannot be stringified while continuing to ship the remaining buffer during unload flush.
Retryable browser responses respect repeated Retry-After headers up to 30 seconds without shortening exponential backoff.
Snapshots from different windows of the same session upload separately, preserving window attribution.
Autocapture attribute masks now apply to link URLs and legacy class properties.
Fixes lost event retries after restoring a page from the back-forward cache.
Fixes false dead clicks after synchronous DOM updates; stopped-bubbling clicks are now evaluated and may increase counts for inert controls.
Avoids keepalive quota failures when multiple event requests are in flight.
Pending replay network captures are discarded after recording stops or restarts.
Identical person property retries are no longer dropped after the original capture is rejected.
Fixes replay cleanup when the host's children are removed before destroying the player.
Console-captured exceptions are marked as handled and identified with their console origin.
Replay errors during playback and seeking no longer stall the remaining events after a failed event.
Console capture now stops correctly and avoids duplicating after restart when another library wraps the console.
Fixes session recording failing to restart after capturing events while stopped with expired config.
Each replay session's snapshots are sent in its own request, preventing session rotation from filing the new session's first snapshot under the old session.
Scroll depth metrics no longer carry over between pages after client-side navigation.
Batched event timestamps are preserved so delayed retries do not shift event times or prevent deduplication.
Failing log flushes continue backing off when new records arrive instead of resetting to the flush interval.
Logs and metrics always preserve service attribution and telemetry SDK fields when resource attributes are too large.
Session replay stops recording autoplay attribute mutations on video and audio elements, preventing repeated mutations from looping background media.
Console methods now receive console as their receiver when recording logs and reporting wrapper failures.
Error tracking excludes injected scripts and unsupported URL schemes from in-app issue grouping while retaining frames for context.
A console message is logged when this option prevents surveys from displaying.
Bootstrap values may now be null.
Null or empty distinct IDs are treated as missing.
Native ESM loading was fixed for consumers using native ES modules.
Recording package exports were fixed so consumers can import the package correctly.
Compatibility was fixed for consumers compiling with strict TypeScript 4.7 settings.
Text selection and editable caret gestures are no longer incorrectly reported as dead clicks when mouse release is delayed.
Clicks that select or unselect text are no longer reported as dead clicks.
TypeScript compatibility between public replay events and the replay player is fixed.
Surveys stay hidden while capture is disabled, and answers are preserved if capture stops before submission.
Empty survey placeholder text no longer displays the default "Start typing..." placeholder.
Repeated frame cycles are collapsed in parsed stack traces to reduce grouping differences caused by recursion depth while preserving distinct throw locations.
Restores connectivity tracking when a page returns from the back-forward cache, without reactivating it after explicit shutdown().
isRecording() no longer reports a stopped recorder as started.
Browser handling drops Safari extension exceptions caused by WebKit messaging failures.
Session replay no longer renders the internal script placeholder, including inside shadow roots and replay iframes.
Playback skips malformed mouse-move positions and uses the event timestamp instead of stalling or ending.
Recorder teardown continues after cleanup-handler errors, allowing recording to restart after an idle reset.
Buffered session replay snapshots survive page unloads and are picked up by the next page in the same tab.
Idle tabs no longer extend the previous session recording across the entire idle gap when they wake.
Waits for the initial remote config outcome before using cached autocapture enablement, preventing capture after a project is newly disabled.
Error details, causes, aggregate errors, custom enumerable properties, and cross-realm Errors are preserved; ordinary capture properties are string-truncated while exception additional properties retain custom toJSON serialization.
Autocapture now recovers dropdown click targets retargeted to the page root and attributes nested SVG icon clicks to enclosing buttons or links while preserving privacy checks.
Session-id rotation synchronously drains compressed replay data so the old session's unflushed tail is preserved.
Exception autocapture no longer throws when wrapped handlers belong to another compartment or a destroyed document.
Discarding a recording no longer uploads stylesheet mutations emitted while the recorder stops.
Replay capture continues processing chunks after an individual chunk fails.
Session-id rotation resets the idle clock so the new session's first snapshot is not dropped or started prematurely.
Queued mutations no longer capture content beneath DOM or shadow ancestors that have become blocked.
Epochs without user interaction retain snapshots without uploading while
$recording_statusremainsactive.Invalid clock values no longer break UUID generation.
Failures in automatic and manual exception processing no longer escape into customer code.
Automatic and manual exception capture no longer recursively recapture stack overflows raised while sending an exception.
Stack frames without filenames are no longer counted as in-app code.
Session recording events continue relaying when a cross-origin iframe redirects through the parent page's origin.
Prevents session replay network capture from replacing a downstream fetch wrapper's response with an instrumentation error when the response has no headers.
Explicitly false feature flag values supplied through bootstrap configuration are now preserved.
Event-specific $groups are now merged with groups registered on the browser client.
The anonymous distinct ID used for feature flag persistence is preserved when identify queues a reload behind an in-flight flags request.
Persisted initial URLs are limited by encoded cookie size, preventing long URLs and referrers from exceeding browser cookie limits.
The package now ships its ESM entrypoint with an .mjs extension so Node recognizes its module format, while retaining the existing .js bundle.
The bundles polyfill Array.prototype.findLast so they keep capturing on browsers older than Chrome 97 and Safari 15.4.
Replay now re-adopts constructed stylesheets when a shadow host is removed and re-added, keeping the component styled during live playback and fast-forward.
Replay recording now continues through session-id rotation when persisted remote config is past its TTL, including rotations caused by posthog.reset() on logout.
Failed replay network body reads no longer escape into the host page's own fetch() call.
Stale session recorders no longer initialize after consent or session teardown, and are disposed when switching to cookieless mode.
ChatGPT app versions differ by platform, so this value should not be compared across platforms.
Cookie support detection now round-trips a probe cookie, improving storage selection when web storage and cookies are unavailable.
Drops a known uBlock Origin Lite Safari extension exception while preserving first-party exceptions with an unmasked in_app frame.
Returns an empty string for non-array input instead of throwing when runtime JavaScript callers provide malformed input.
Falls back to in-memory storage when web storage and cookies are unavailable, and preserves stored falsy values.
MutationBuffer cleanup now runs for empty normalized mutation batches, preventing DOM nodes from being retained indefinitely.
Polling backs off to avoid starving event sends.
Empty INP attribution reports no longer throw; metrics are captured with fallback attribution and no interaction details.
Survey events now report the language the user saw when answering, rather than the language active when the event fired.
Autocapture no longer throws a RangeError when sorting element attributes in browsers with faulty ICU data.
The bot-detection blocklist now matches pinterestbot instead of all Pinterest user agents, preventing real users in Pinterest's in-app browser from being excluded from analytics.
Console calls made before the logs script loads are now captured.
Session replay and posthog-js no longer leave each other's console wrapper in the call path when either stops.
Setting logs.captureConsoleLogs in init() now enables console autocapture.
Request timeouts now fire on pages where a browser extension makes Error.prototype.name non-writable.
Playback no longer ends when a recording contains a browser-refused shadow host; the player skips that subtree instead.
Fixes console log autocapture silently failing when an older posthog-js core loads a newer logs bundle.
Adds typed stable-name lookup for installed browser extensions when independently loaded survey code resolves feature flags.
Type declarations now support @types/react back to the declared 16.8.0 floor, avoiding TS2305 errors with older React types.
react is now an optional peer dependency, allowing posthog-js/react to resolve React on strict node_modules layouts without affecting projects that do not import it.
@types/react is now an optional peer dependency, avoiding unmet-peer warnings when React is absent while supporting posthog-js/react resolution.
Prevents failed CSSOM changes and fixes shadow DOM, cross-origin iframe, blocked and unsupported canvas, and deep DOM serialization edge cases.
Shares survey property matching between browser and React Native SDKs while preserving existing missing-value behavior.
Logs and metrics batches are retried after HTTP 408 instead of being dropped.
Fixed a stale element remaining rendered in the player when a mutation re-added a node ID with changed attributes; affects both useVirtualDom modes.
Prevents optional feature scripts from being added to the page more than once when api_host is a relative path.
Replay playback now continues across document swaps when constructed stylesheet adoption fails, using styles already applied.
Hover handling now ignores non-element and detached targets instead of throwing and stopping playback.
Backdated sessionIdle markers are attributed to the session that went idle, preventing rotation-born recordings from starting hours before their first snapshot.
Prevents logs and metrics from being silently dropped when attributes contain unsupported or unusually large values.
OtlpAnyValue.intValue is typed as string | number, so code reading it must handle both types.
The cookieless sentinel no longer leaks into identify() or real events, preventing distinct users from being merged.
Events are dropped when a before-send hook throws instead of sending the unmodified event.
Chromium <anonymous> stack frames from extension-injected, devtools, or string-evaluated code are no longer counted as in-app code.
Closing an in-app survey now uses a scoped CSS opacity transition instead of a document-level view transition, preventing Chrome renderer crashes on heavy pages.
Firefox and Safari extension frames are recognized when filtering extension exceptions, and Safari masked URL frames are no longer counted as in-app code.
Session recording takes a full snapshot when waking from idle after dropped DOM mutations, preventing duplicated or overlapping DOM in replay.
Restores exception autocapture compatibility for posthog-js clients through version 1.141.0.
Corrects exception types for non-Error objects thrown across browser extensions, iframes, and other realms instead of reporting them as Error.
Capture timestamp overrides are normalized to equivalent UTC ISO strings across browser, Node.js, and shared core SDKs.
Visibility and focus changes now suppress dead-click detection as liveness signals, preventing valid interactions from being flagged as dead.
Swallowed rrweb observer initialization errors no longer break session replay teardown or subsequent recorder restarts.
Deferred stylesheets are flushed synchronously when recording stops and during pagehide.
Fixes Chrome renderer crashes when closing in-app surveys and ensures popup state settles correctly during skipped, interrupted, or overlapping transitions.
The Segment integration config now accepts current and legacy Segment Analytics SDK types.
Preserves adopted stylesheets that arrive before a shadow root is attached, keeping Stencil and Lit components styled.
Prevents a buffer swapped in by re-entrant session rotation from being shipped during a replay flush.
Recordings containing only idle lifecycle markers are no longer opened.
The intro does not re-fire the survey shown event and is skipped when resuming a survey with answers in progress.
In-place object and array mutations are persisted when properties are re-registered.
Properties registered for a session are cleared when the PostHog session rotates.
Benign network failures no longer surface as unhandled promise rejections that exception autocapture could otherwise capture.
Recording now continues to capture mutations from adopted nodes originating in another realm.
Recorder-owned callback failures are contained and logged while exceptions from patched native host APIs remain preserved.
Held interaction-less recordings are discarded when a background document unloads without becoming visible.
Stale persisted question indexes now discard the in-progress record and restart the survey; restored visited indices are filtered to valid questions.
Held rotation-born replay buffers now flush when a V2 event trigger matches.
Event-triggered survey popup delays now resume from the trigger time across page navigation instead of restarting on each page load.
Handled transport failures no longer become error logs in surveys, product tours, remote config, conversations, and logs; HTTP and unexpected failures retain error severity.
Idle session rotations no longer ship billable recordings until user interaction or an explicit event trigger; held data is discarded otherwise.
Open surveys remain in place when their trigger element is unmounted and are torn down only after the user closes them.
Click listeners on previously resolved selector elements are removed when the selector resolves to a different element, preventing repeated show-widget events.
Preserves messages, source locations, and existing stacks from browser errors without a same-realm Error object.
Support reply bullet and numbered lists retain markers despite aggressive host-page CSS resets by applying inline list styles.
Duplicate snippet loaders no longer replace initialized instances or replay queued calls more than once.
Prevents the inline canvas recording worker from requesting an unusable source map from its blob URL.
Suppression rules now fail open when evaluation encounters an unknown operator or unsupported key, preventing exceptions from being dropped.
Session replay re-sends one frame per canvas after each full snapshot, preventing canvases from staying blank after seeking.
Auto-submitted hosted survey responses retain caller-provided event properties, and manual submission preserves the prefilled answer during partial-response merging.
Session replay no longer redacts network bodies when timestamps or UUID fragments resemble social security or credit card numbers.
Campaign parameters are refreshed after single-page application URL changes.
identify() no longer creates a person profile when the supplied ID matches an anonymously persisted distinct ID.
Fixes dead-click false positives on WebKit when the SDK uses an iframe-sourced MutationObserver fallback.
React hooks without a PostHogProvider receive the default PostHog instance again when the UMD build is loaded through CommonJS.
Surveys now wait for feature flags only when they repeat; other surveys use cached targeting values immediately, preventing one-time api surveys from being dropped.
Fixes extension bundles when using the slim no-external browser build.
Paused replay seeks at an exact full snapshot timestamp now rebuild the snapshot frame before playback pauses.
Only reports surveys as renderable after their event or action activation trigger has fired.
Only reports surveys as renderable after their event or action activation trigger has fired.
Prevents server timings from dropped ingestion requests from causing an endless capture loop.
Session replay recordings remain playable after session rotation without prior user interaction, with recorder restart, session ID resync, and normal buffer flushing.
Dynamic GET requests continue preserving underscore cache-busting parameters.
Exception autocapture no longer throws when page error handlers contain truthy non-callable values.
Input observation skips native accessor calls on non-native objects, preventing uncaught Illegal invocation errors.
Recurring surveys wait for feature flags to load before eligibility checks and reload flags after completion to prevent duplicate responses.
save_referrer no longer overwrites explicitly registered $referrer or $referring_domain values, preserving attribution across SPA and iframe pageviews.
The active full snapshot interval now applies as soon as a recording trigger matches.
Failed remote config requests no longer enable autocapture for opted-out projects; it stays off until a successful config response.
Synchronous throws from monkey-patched fetch now follow async rejection handling, allowing request queue retries without unhandled exceptions.
Replay events containing array-based circular references are captured with [Circular] markers instead of being dropped.
Session recording drops replay updates for non-native input elements instead of throwing an uncaught TypeError.
Beacon quota rejections are now split and retried recursively, with non-keepalive fetch fallback and a warning when splitting cannot continue.
Ancestor traversal stops after 1000 ancestors or on revisiting a node, preventing indefinite walks on abnormal host-page DOM trees.
Uncompressed sendBeacon bodies now use base64 form data to preserve a CORS-simple content type and prevent cross-origin unload events from being lost.
Event serialization no longer throws on circular captured properties; true cycles become "[Circular]", preventing recaptured $exception loops.
Prevents shared rrweb global wrappers from growing without bound during recorder start/stop cycles, avoiding call-stack overflow.
Session recording startup now degrades gracefully when an older bundled core lacks SessionIdManager methods.
Fixed session replay leaking a shadow-root observer when a same-origin iframe is removed.
Cleanup no longer throws when the rrweb recorder cannot remove a listener.
Session recordings now preserve the initial full snapshot after an idle session-id rotation, preventing new recordings from becoming unplayable.
Session replay no longer silently drops shadow DOM mutations after an iframe teardown.
Network capture now degrades gracefully when instrumentation throws, preserving the host application's own XHR and fetch calls.
Fetch wrapper teardown now remains safe when restores occur out of order, preventing unbounded wrapper growth and stack overflows during repeated start/stop cycles.
The TypeScript definition now accepts the instance passed to the loaded callback, matching documented usage.
Prevents infinite-recursion stack overflows by bypassing the wrapped console during internal logging and guarding against re-entrancy.
Stops repeatedly hitting blocked feature flag and conversations polling endpoints after consecutive status-0 failures.
Own feature-flag timeouts are logged as warnings instead of errors when browsers do not propagate abort reasons.
Prevents uncaught crashes in heatmaps and autocapture when event targets are cross-realm elements from iframes or synthetic events.
Callbacks are isolated so a throwing user handler no longer breaks the remaining callback chain or gets misattributed as an SDK error.
The value now measures UTF-8 byte length instead of UTF-16 string length, accurately counting non-ASCII replay payloads against the message size limit.
Web vitals capture no longer crashes on browsers lacking Array.prototype.at(), including Chrome <92 and iOS Safari <15.4.
The IE11 bundle now includes a Promise polyfill and avoids async compression paths when Promise support is unavailable.
Browser requests fall back to uncompressed encoding when gzip encoding fails.
Request serialization errors no longer throw or block queued requests.
Browser console log capture now works when session activity timestamps are missing, and session attributes refresh for each log.
Page unload handling now guards the delegated method when a version-skewed surveys chunk lacks handlePageUnload.
Stops logging a misleading server-upgrade warning when valid v2 flags responses contain no flags.
PostHog fetch timeouts now abort with an explicit descriptive reason while preserving AbortError handling and avoiding noisy exception recapture.
The browser SDK no longer adds the unused beacon query parameter to sendBeacon requests.
Applies the existing base64 image size cap to SVG image elements with data URIs in href and xlink:href, including mutations.
Binary and asset request or response bodies are never recorded, even when recordBody is enabled.
Custom event UUID overrides are validated, and new UUIDs are generated when overrides are invalid.
Delayed surveys now re-check full display eligibility before rendering and are cancelled when later evaluation finds them ineligible.
The flushed-size tracker is scoped to the current session, preventing leakage across page loads and tabs and ensuring new sessions start from zero.
The internal persistence key is hidden and no longer sent as a super-property on captured events, while remaining available on session-replay debug events.
Repeatable surveys using schedule: 'always' are consumed when shown, so each captured trigger shows them once.
Browser log delivery now resumes when the browser comes back online.
Merging flags no longer stores active feature flag overrides, so clearing an override restores the original flag.
Events are dropped and a warning is logged when a before_send hook removes token, avoiding rejected ingestion requests.
External scripts for exception and dead-click autocapture are not reloaded when already present.
The browser SDK no longer adds the unused ip query parameter to requests.
Clears the stopped session's stale snapshot buffer when restarting recording after a pending stop, preventing previous-user snapshots from being attributed to the new session.
Surveys now swallow SecurityError from remaining localStorage accesses in cross-origin iframes instead of bubbling errors to user monitoring.
Disabling product tours now clears the cached tours blob, preventing stale data from persisting and broadcasting across tabs.
Prevents active rrweb capture from being silently torn down after session-id rotation, restoring replay event production and listener registration.
Seeking past pages and full snapshot rebuilds now apply scrolls instantly, preventing smooth-scroll animations from leaving revealed content out of view during fast-forwarding.
Session IDs remain stable across tabs, reducing spurious session fragmentation and correcting over-counted sessions.
The support widget now re-attaches after SPA navigations replace document.body, preventing it from disappearing until a full page reload.
Sampled-in session replay decisions are refreshed after the configured replay sample rate changes.
Snapshots are never recorded or flushed without a sampling decision, preventing junk recordings and stale decisions across session changes.
Resting scroll offset is captured on scrollend when reveal scrolling clamps to 0 before its target is scrollable, without duplicating normal scroll events.
Past events are applied synchronously only in live mode, preventing on-demand playback seeks and exports from using corrupted recording data.
In cookieless on_reject mode, opting out now respects capture_pageview: false.
Heatmap rageclick markers now apply the same suppression rules as the
$rageclickevent.Survey rendering no longer uses a WebKit-crashing :has selector; empty headers now use a JavaScript-set class and sibling selector.
The tracing header now reads the distinct ID at request time, reflecting bootstrap, identify, reset, and other identity changes.
The console-log integration now suppresses log events after opt-out and resumes emitting them after opt-in.
Replay now reapplies the last scroll position after layout settles, preventing content from remaining scrolled out of view after fast-forward or seek.
Same-origin iframe documents, observers, serialized nodes, and cleanup handlers are released when iframes are removed, preventing session recording memory leaks.
Safari no longer exposes internally-created Request bodies to downstream fetch wrappers.
Initialization paths no longer throw or send requests when PostHog project tokens are missing or blank.
Takes a fresh full replay snapshot after session ID rotation, preventing new sessions from receiving only incremental mutations.
Enables the request queue when opting out in on_reject cookieless mode, allowing batched events to flush over the network.
Publishes the replay fix for absolutely positioned elements marked with ph-no-capture.
Session recorder no longer polls preload-as-style CSS links forever, preventing leaked load listeners, main-thread saturation, and tab freezes on refocus.
Stylesheet URLs are captured from link.sheet.href and link.sheet is tried directly for inlining, preserving recordings across SPA route changes.
PostHogProvider no longer throws or initializes when no API key or client is provided.
Tracing headers are now applied to matching XMLHttpRequest requests.
Preserves session-recording remote config across reset, allowing new sessions to start with recording metadata and a FullSnapshot.
posthog.capture now respects transport overrides passed to it.
Clicks on anchors are no longer flagged as dead clicks, while direct clicks on previously skipped form controls are now eligible for detection.
Gzip request bodies are validated at the browser send boundary and fall back to JSON when the outgoing body is not gzip data.
Native gzip output is validated before requests, with fallback when CompressionStream returns malformed data.
Prevents browser log capture from throwing when console arguments contain unreadable properties.
Invalid persisted session replay configuration JSON is handled gracefully.
Background refreshes are skipped when no document is available.
Session recording now stops before sessionManager destruction, preventing late rrweb events from throwing in cookieless rejection mode.
Original style text is preserved when CSSOM serialization produces empty longhands from var() shorthands, preventing layout rules from being dropped during replay.
Canvas recording now skips snapshots during WebGL context loss and catches getCanvas traversal errors, preventing recording from silently stopping for the session.
Fixes copy autocapture when copying or cutting text from Shadow DOM or document fragment contexts.
Fixes autofocus behavior for developers using posthog-js.
Native async gzip compression no longer uses Blob.stream(), preventing Safari NotReadableError stream failures.
Fixed session recording in the full no-external browser bundles.
NaN and ±Infinity attribute values are preserved during JSON encoding instead of being silently dropped.
Guards survey seen localStorage access to prevent access-related issues.
When opt_out_capturing_by_default is set, PostHog now starts in cookieless mode.
Reinstated in captured event properties, making feature flag payload data available again.
Reinstated in captured event properties, making survey activation data available again.
Unnecessary persisted config and activation properties are no longer added to captured events, including product tours, surveys, and session recording config.
Recording triggers for V2 triggers now account for property filters on events.
Browser SDK disables native gzip compression after a NotReadableError.
Bootstrapped feature flags are no longer overwritten by a partial /flags response when this option is enabled.
IframeManager destroy now handles SecurityError.
IframeManager removeIframeById now handles SecurityError.
The mutation buffer is cleared on iframe pagehide to prevent recording corruption.
Unchanged setAttribute calls are skipped to prevent replay flicker.
Preserves $set_once semantics in the local flag evaluation cache.
Sends $groupidentify for new groups even when no properties are provided.
Fixes crashes in slim and extension bundles caused by inconsistent property mangling.
Canvas FPS snapshots now recover from createImageBitmap or worker errors instead of permanently stopping canvas recording.
Avoids an infinite recursion crash when resetting or restarting the recorder on pages containing shadow DOM elements.
Snapshot and exception events skip deep copying to prevent stack overflow on deeply nested DOM trees.
Wraps the sendBeacon body in a Blob so the Content-Type header is set correctly.
Adopted stylesheets can now be cleared with empty strings.
Stop handler cleanup now handles cross-origin iframe errors.
Nested CSS rule handling is improved for replay behavior.
Object reference mutation no longer breaks remote CSS replay.
Stop handler cleanup now catches all SecurityError variants.
WebGLRenderingContext access is guarded for iOS compatibility.
Document visibility changes no longer capture dead clicks.
Logs a warning instead of throwing an error when ad blockers block the session recording script.
Bootstrap no longer causes a silent identity switch, making user identity behavior more predictable.
overrideFeatureFlags now handles plain array and object forms.
Initial person properties are now included with $identify calls even after being sent in a prior anonymous event, improving identification across subdomains.
Preserved from terser mangling so wrapper SDKs can call it.
Debug mode now persists across page navigations.
Restarts when the session rotates externally while idle, preventing Recording not found errors.
Legacy persisted configs without cache_timestamp are treated as fresh, preventing them from being cleared before recording starts.
PostHogFeatureFlags now uses a TreeShakeable<T> type.
When remote config fetch fails, session recording falls back to persisted config or disables recording for first-ever visits instead of remaining stuck in pending_config.
Tablet detection now occurs in detectDeviceType, providing consistent device classification across all call sites.
Reuses a single OffscreenCanvas in the canvas recording worker, fixing a Safari memory leak.
Canvas FPS recording is skipped on browsers without OffscreenCanvas instead of running a loop that cannot produce data.
Canvas mutation data now includes displayHeight for correct replay sizing.
Canvas mutation data now includes displayWidth for correct replay sizing.
Canvas recording now closes ImageBitmaps on Safari versions without OffscreenCanvas, preventing a memory leak.
Recording initialization failures now report rrweb_error instead of appearing active while capturing no data.
Improves tablet and mobile classification when Chrome on Android tablets sends desktop-like user-agent strings.
Adds a re-entrancy guard for configurations combining ALL, regex, and event trigger matching.
Added additional legacy exports for fully qualified dist and lib exports, improving compatibility for existing imports.
All package export paths are exposed, allowing developers to access the intended package entry points.
Fixed an autofill bug in hosted surveys.
Fixed an issue where the toolbar interfered with distinct id handling in conversations.
Prevents an infinite recursion bug when using a 3rd party proxy with posthog.
Markdown is stripped in the tickets list.
Retries starting session recording when persisted remote configuration is stale.
Tree shaking configuration was reverted, potentially changing how application bundles are optimized.
Added the missing featureFlags property to the PostHog interface.
Restored set_config to the loaded callback type.
Session replay now respects the network_timing remote configuration, allowing network timing behavior to be controlled as intended.
Dead Clicks no longer continue being captured after being disabled via remote config.
Remote config cache invalidation is no longer too aggressive.
The replay remote config cache is now invalidated periodically.
The identification form is no longer shown when the user is already identified.
Legacy persistence entries with sampled: true are now ignored.
Fixed console error capturing so captured console errors behave correctly for developers using the library.
Tour manual click triggers now use preventDefault instead of stopPropagation.
Tours now infer elements more precisely and wait to mark a tour as shown until the first step renders successfully.
Fixed stale element references in multi-page product tours.
Fixed contrast colors in the support widget.
Failed flags are filtered before cached values merge, preventing transient backend errors from overwriting previously evaluated states.
Element clicks are no longer intercepted when a product tour fails to show.
Undefined and null configuration values are treated identically when config is received.
Fixes the color of the survey close button.
Survey cancel buttons are now black.
Reduces memory leaks in SPAs by upgrading web-vitals and removing duplicate observers on URL changes.
Fixed product tour tooltips on mobile devices.
Rate limiting configuration changes are now respected.
Logging objects with null or undefined property values no longer throws a TypeError.
Fetch wrappers were restored to the most recent working version.
Fetch wrappers no longer reconsume request bodies or generate mismatched FormData boundaries.
Wrapped fetch now always receives a RequestInit object, ensuring consistent fetch initialization behavior.
Wrapped fetch() now passes the duplex option when required.
Fixed an issue with _currentTicketId.
Product tour tooltips now use more robust element-based positioning.
Typing inside the loaded callback was fixed, improving type checking for callback implementations.
Missing public definitions were added to @posthog/types, improving the available type surface for developers.
Activity timestamp detection no longer compares null to numbers, preventing incorrect activity handling.
Adds missing sessionRecording types for developers using session recording APIs.
Survey responses prefilled from URL parameters now respect branching and skip logic instead of always advancing sequentially.
$prev_pageview_duration no longer spans session boundaries after session rotation, preventing inflated page duration values.
$device_id is persisted to cookies so it survives localStorage clears.
Callbacks are queued while a survey fetch is in progress instead of returning an error.
Hosted survey auto-submit behavior now only submits skipped questions.
Updated which network masking function is used.
Includes initial person properties in $identify when group() is called first.
Session recording restarts after opt_in_capture is called.
Prefilled questions now work for hosted surveys.
Session ID rotation no longer relies on stale in-memory cache after idle periods, especially when multiple windows are in use.
Clicks with CTRL, ALT, CMD, or Windows modifier keys no longer count as dead clicks.
Fixed session replay on React Native Web.
Corrects the frame platform property for $exception events.
No longer relies on the order of method calls to gate calling url.
Popover surveys are now cleaned up from the DOM when closed.
Fixes a bug in survey HTML rendering.
Rageclick detection now uses the event timestamp instead of the current time.
Session recording configuration overrides are now applied even while the recorder module is still loading.
Session ending payloads are now allowed when recording is idle.
Token calculation can now occur without a timer.
Surveys are no longer polled while the page is hidden.
The retry count URL parameter is now updated correctly.
Polling now stops when the retry queue is empty.
Stops the heatmap buffer interval when the page is hidden.
Adds a warning and extra examples explaining what advanced_disable_flags disables.