Type definitions for the PostHog JavaScript SDK
Last release today
26 Aug 2026
Ships on a steady schedule
a new release about every 9 days
Some releases are documented
notes for 24 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
7 months old
242 releases · first in 2026
Release timeline
242 releases since 2026Releases
- 1.407.026 Aug 2026
- 1.406.226 Aug 2026
Release notes
Open source →1.406.2
Patch Changes
-
#4635
ab1383aThanks @robbie-c! - Capture paste interactions with clipboard autocapture without collecting pasted text.
(2026-08-26) -
#4640
0d2cf49Thanks @robbie-c! - Add opt-in Schema.org JSON-LD capture to session replay throughsession_recording.captureJsonLd. When enabled, the recorder emits sanitized JSON-LD as custom replay events and excludes all script elements from replay snapshots.
(2026-08-26)
-
- 1.406.125 Aug 2026
Nothing published for this version
- 1.406.025 Aug 2026
Nothing published for this version
- 1.405.324 Aug 2026
Nothing published for this version
- 1.405.224 Aug 2026
Nothing published for this version
- 1.405.121 Aug 2026
Nothing published for this version
- 1.405.018 Aug 2026
Nothing published for this version
- 1.404.114 Aug 2026
Release notes
Open source →1.404.1
Patch Changes
-
#4503
eb05237Thanks @pauldambra! - fix(dead-clicks): treat visibility and focus changes as liveness signals, not dead-click evidenceThe dead-click detector treated a
visibilitychangeas evidence a click was dead: it measuredMath.abs(clickTimestamp - lastVisibilityChange)and, once that exceeded the threshold, timed the click out as dead. Because it only recorded the tab becoming visible, any click in a session where the tab had ever been backgrounded (median gap ~1 minute) was flagged.A visibility or focus change near a click is the opposite — a sign the click did something (it woke/focused the tab, opened a new tab, or opened a new window/popup) — so these signals now only ever suppress a dead click, never cause one:
- Visibility changes are recorded in both directions (a click that opens a new tab sends the current tab to
hidden), and a windowfocus/blurobserver is added, since a click that opens a new window/popup may leave the tab visible and only surface as the current window losing focus. - A click within a wake-up/interaction window (1s, wide enough for a real "tab back, then click" gesture) of any such change is suppressed.
- The visibility signal no longer feeds the dead-marking path at all.
$dead_click_visibility_changed_timeoutstays in the payload (always false) for shape compatibility, and a new$dead_click_focus_changed_delay_msis emitted for observability. - Visibility/focus changes are now recorded onto each queued candidate the instant they fire (like scroll), instead of being read from a single shared timestamp when the click is checked ~1s later. A click that hides or blurs the tab (opening a new tab/window) suspends that check while the tab is backgrounded; by the time it resumes the tab has usually returned, and the shared timestamp would have been overwritten by that later transition — losing the click-correlated one and wrongly flagging the click dead. Stamping the candidate as the event fires makes delayed hide→show and blur→focus sequences suppress correctly. (2026-08-14)
- Visibility changes are recorded in both directions (a click that opens a new tab sends the current tab to
-
- 1.404.013 Aug 2026
Release notes
Open source →1.404.0
Minor Changes
- #4485
8bc63c3Thanks @dustinbyrne! - Default external dependency loading to versioned asset paths with automatic fallback to legacy paths, and add astrict_script_versioning: 'fallback'mode. (2026-08-13)
- #4485
- 1.403.113 Aug 2026
Release notes
Open source →1.403.1
Patch Changes
- #4443
b2c6830Thanks @arnohillen! - Harden the session replay stylesheet inlining budget (inlineStylesheetBudgetRules):- The default budget (10,000 rules) moves from the recorder chunk into posthog-js session recording options, so npm-pinned or cached bundles keep their configured override (including
0to disable) and directrrweb.record()consumers keep unbounded inlining unless they opt in. - Deferred inlining is bounded inside a sheet: a resumable cursor stringifies 200 rules per idle slice and emits a sheet's
_cssTextatomically, so monolithic sheets no longer produce one long task and partial CSS never reaches the wire. - Deferred sheets are flushed synchronously when recording stops and on
pagehide; residual failure modes are counted via$sdk_debug_replay_deferred_stylesheets_failed/_abandoned. - CSSOM-only styles (
insertRuleoutput,adoptedStyleSheets) no longer charge the budget, since deferring<link>sheets buys those pages nothing. - Telemetry fixes: full-snapshot duration wraps the whole synchronous task, deferred counts are cumulative per session, new gauges cover non-deferrable rules and idle stringification cost, and duration samples straddling tab suspension are discarded (
$sdk_debug_replay_discarded_duration_samples). (2026-08-13)
- The default budget (10,000 rules) moves from the recorder chunk into posthog-js session recording options, so npm-pinned or cached bundles keep their configured override (including
- #4443
- 1.403.012 Aug 2026
Release notes
Open source →1.403.0
Minor Changes
-
#4495
e4b9947Thanks @marandaneto! - feat(browser): addrewriteRequestPathto customize API, feature flag, and asset paths for reverse proxies (2026-08-12) -
#4493
e34ebf9Thanks @marandaneto! - Add reset options for applying bootstrapped identity, feature flag, and session values afterposthog.reset()while preserving the legacy boolean argument. (2026-08-12)
-
- 1.402.311 Aug 2026
Release notes
Open source →1.402.3
Patch Changes
- #4494
deb6bb0Thanks @marandaneto! - fix(types): accept current and legacy Segment Analytics SDK types in the Segment integration config (2026-08-11)
- #4494
- 1.402.26 Aug 2026
Release notes
Open source →1.402.2
Patch Changes
- #4434
75fb719Thanks @arnohillen! - Make the session replay attribute masking options mutually exclusive: when bothmaskAllElementAttributesandmaskAttributeFnare set, the coarse option wins and the callback is ignored (with a console warning), so a callback can no longer accidentally unmask whatmaskAllElementAttributeshides. (2026-08-06)
- #4434
- 1.402.15 Aug 2026
Release notes
Open source →1.402.1
Patch Changes
-
#4286
d108d66Thanks @posthog! - fix(replay): preserve privacy masking for initial network metadataInitial navigation and performance-timing entries are now passed through
maskCapturedNetworkRequestFn, including when they have no method. URL rewrites are respected. When the callback returns nullish for an initial entry, replay-required timing metadata is retained without its URL, headers, or body so method-gated callbacks do not drop the metadata or expose deliberately filtered customer data. Derived server-timing entries are also suppressed when this strict fallback is used. Enforced PostHog filtering and payload cleaning still run first. (2026-08-05)
-
- 1.402.05 Aug 2026
Release notes
Open source →1.402.0
Minor Changes
- #4376
2da12b8Thanks @posthog! - Add attribute-level masking to session replay:maskAttributeFnprovides per-attribute control over the final serialized value, whilemaskAllElementAttributesmasks all source DOM string attributes (including rendering attributes and synthesized form values) at the cost of replay fidelity. (2026-08-05)
- #4376
- 1.401.15 Aug 2026
Release notes
Open source →1.401.1
Patch Changes
- #4380
3c40b6cThanks @marandaneto! - Keep request timeouts active through response body consumption and clarify eventual event UUID deduplication semantics. (2026-08-05)
- #4380
- 1.401.04 Aug 2026
Release notes
Open source →1.401.0
Minor Changes
-
#4266
43d1850Thanks @posthog! - feat: add opt-incapture_performance.__preview_web_vitals_soft_navsto fix inflated web vitals on single-page appsClient-side route changes in SPAs previously left web vitals (LCP especially) accumulating against the original hard-navigation timestamp, inflating the top tail of Core Web Vitals. Setting
capture_performance: { __preview_web_vitals_soft_navs: true }now scopes metrics to the browser's Soft Navigation entries so each route change starts a fresh measurement window. It's a preview option because it relies on Chrome's experimental Soft Navigation Detection API and loads pinned stable web-vitals 6.x callbacks; when disabled (the default), the existing web-vitals 5.x behavior remains unchanged. (2026-08-04)
-
- 1.400.24 Aug 2026
- 1.400.14 Aug 2026
Release notes
Open source →1.400.1
Patch Changes
-
#4314
feb9e2aThanks @posthog! - fix: warn whenreset()silently opts the user back outreset()clears stored consent along with the rest of the user's state. Withopt_out_capturing_by_default, this returns the instance to the opted-out default, so callingreset()afteropt_in_capturing()would stop capturing without warning. It now logs a warning when that happens and documents the required ordering. (2026-08-04)
-
- 1.400.03 Aug 2026
Release notes
Open source →1.400.0
Minor Changes
- #4125
fde7145Thanks @DerGeraetK! - Addsession_recording.samplingto disable or throttle mousemove capture (and optionally mouseInteraction) in session replay. Canvas recording now merges its canvas sampling with user-provided sampling instead of overwriting it. (2026-08-03)
- #4125
- 1.399.029 Jul 2026
Release notes
Open source →1.399.0
Minor Changes
-
#4270
92427a1Thanks @turnipdabeets! - Add canvas mask regions to session replay canvas capture:session_recording.canvasCapture.maskRegionsFnis called once per canvas per captured frame, and the returned regions (CSS pixels, relative to the canvas) are painted black in the captured frame before it is encoded — letting apps that render into canvas (e.g. Flutter web via CanvasKit) mask content that DOM-based masking cannot see.The return value decides what happens to that canvas's frame:
[]— nothing to mask; the frame is recorded as is.null— regions could not be computed; the frame is skipped rather than recorded unmasked.maskRegionsFnnot set — canvases are recorded unmasked and canvas capture behavior is unchanged.
Configuring
maskRegionsFnalso disables canvas pixel serialization in DOM full snapshots (rr_dataURL) — that path never sees the mask regions, so skipping it closes the route that could otherwise embed unmasked canvas stills in a snapshot; the canvas repaints from the masked frame stream instead. Every canvas the provider answers — with regions or[]— re-sends an unchanged frame as a keyframe every 30s, so after a full snapshot or a seek an idle canvas repaints within at most 30s.An app whose real provider only exists once its runtime has booted chooses what happens in between by what it declares in
posthog.init: a function covering the whole canvas blacks those frames out,() => nullskips them, and declaring nothing records them. Client-side only, cannot be set via remote configuration. (2026-07-29)
-
- 1.398.022 Jul 2026
Release notes
Open source →1.398.0
Minor Changes
-
#4222
0f2407bThanks @turnipdabeets! - feat: add a default-value option toisFeatureEnabledisFeatureEnabled(key, { defaultValue: false })now returns the given default when the flag has no value — flags not loaded yet, or no flag with that key — and the return type narrows toboolean. The option name is the same in posthog-js, posthog-js-lite, and posthog-react-native. WithoutdefaultValue, behavior is unchanged:boolean | undefined. (2026-07-22)
-
- 1.397.120 Jul 2026
Release notes
Open source →1.397.1
Patch Changes
- #4198
fbfc84fThanks @pauldambra! - feat: make the pending session recording trigger buffer interval configurable (2026-07-20)
- #4198
- 1.397.016 Jul 2026
Release notes
Open source →1.397.0
Minor Changes
- #4149
607bf54Thanks @pauldambra! - Add dead swipe detection to dead clicks autocapture. When dead clicks autocapture is enabled, touch swipe gestures that produce no observable screen change (no scroll, mutation, selection or visibility change) are now captured as$dead_swipeevents, surfacing failed navigations on touch devices. Configurable viacapture_dead_swipes(defaulttrue) andswipe_threshold_px(default30) on thecapture_dead_clicksconfig. Swipes over surfaces whose response cannot be observed (canvas, video and other media elements under the finger) are skipped, and captures are limited per page load viamax_dead_swipes_per_page_load(default10). (2026-07-16)
- #4149
- 1.396.016 Jul 2026
Release notes
Open source →1.396.0
Minor Changes
-
#4159
fad6d9aThanks @haacked! - add$feature_flag_has_experimentto$feature_flag_calledevents$feature_flag_calledevents now carry a$feature_flag_has_experimentboolean sourced from the server'shas_experimentflag metadata (the/flags?v=2response for remote evaluation, the/api/feature_flag/local_evaluationdefinitions for posthog-node local evaluation). The property is only sent when the server explicitly reportshas_experiment; it is omitted entirely when the value is unknown (older servers, missing metadata, bootstrapped or locally injected flags). (2026-07-16)
-
- 1.395.015 Jul 2026
Release notes
Open source →1.395.0
Minor Changes
- #4129
800af7cThanks @pauldambra! - feat: addsession_recording.attributeFilteroption that passes an attribute allowlist through to the native MutationObserver, so mutations to unlisted attributes (e.g. animation-driven inlinestylechurn) never cost recording CPU (port of upstream rrweb #1873) (2026-07-15)
- #4129
- 1.394.014 Jul 2026
Release notes
Open source →1.394.0
Minor Changes
- #4101
dc2aa5bThanks @posthog! - Normalize the error tracking rate-limiter config to first-class options. The browser SDK now readsexceptionRateLimiterRefillRate/exceptionRateLimiterBucketSizeonerror_tracking, with the previous double-underscore__exceptionRateLimiterRefillRate/__exceptionRateLimiterBucketSizeoptions deprecated but still honoured as a fallback. The option shape (ExceptionRateLimiterConfig) and default-resolution logic (resolveExceptionRateLimiterConfig) now live in@posthog/coreand are shared between the browser and Node SDKs. (2026-07-14)
- #4101
- 1.393.08 Jul 2026
Release notes
Open source →1.393.0
Minor Changes
-
#4115
86bb3a5Thanks @DanielVisca! - add the posthog.metrics API (count, gauge, histogram) — alphaA statsd-style pre-aggregating metrics client for the PostHog Metrics product (alpha). Samples are folded into per-series aggregates in memory (counts sum, gauges keep the last value, histograms accumulate buckets) and flushed periodically as OTLP/JSON to
/i/v1/metrics— one data point per series per flush window, no matter how many calls. No OpenTelemetry SDK setup required:posthog.metrics.count('orders_created', 1) posthog.metrics.gauge('active_connections', 42) posthog.metrics.histogram('api_latency', 187, { unit: 'ms' })Configure via
metrics: { serviceName, environment, flushIntervalMs, maxSeriesPerFlush, beforeSend, ... }. (2026-07-08)
-
- 1.392.13 Jul 2026
Release notes
Open source →1.392.1
Patch Changes
- #4053
45d1b36Thanks @posthog! - feat(web): add a gracefulshutdown()to the browser client for parity with posthog-node, so isomorphic teardown code (e.g. the Nuxt module) that callsposthog.shutdown()on the client no longer throwsTypeError: shutdown is not a function. It best-effort flushes the queued events and always resolves. (2026-07-03)
- #4053
- 1.392.029 Jun 2026
Nothing published for this version
- 1.391.124 Jun 2026
Nothing published for this version
- 1.391.023 Jun 2026
Nothing published for this version
- 1.390.219 Jun 2026
Nothing published for this version
- 1.390.119 Jun 2026
Nothing published for this version
- 1.390.017 Jun 2026
Nothing published for this version
- 1.389.017 Jun 2026
Nothing published for this version
- 1.388.017 Jun 2026
Nothing published for this version
- 1.387.016 Jun 2026
Nothing published for this version
- 1.386.415 Jun 2026
Nothing published for this version
- 1.386.311 Jun 2026
Nothing published for this version
- 1.386.211 Jun 2026
Nothing published for this version
- 1.386.110 Jun 2026
Nothing published for this version
- 1.386.010 Jun 2026
Nothing published for this version
- 1.385.010 Jun 2026
Nothing published for this version
- 1.384.310 Jun 2026
Nothing published for this version
- 1.384.210 Jun 2026
Nothing published for this version
- 1.384.110 Jun 2026
Nothing published for this version
- 1.384.010 Jun 2026
Nothing published for this version
- 1.383.39 Jun 2026
Nothing published for this version
- 1.383.29 Jun 2026
Nothing published for this version
- 1.383.18 Jun 2026
Nothing published for this version
- 1.383.08 Jun 2026
Nothing published for this version
- 1.382.06 Jun 2026
Nothing published for this version
- 1.381.05 Jun 2026
Nothing published for this version
- 1.380.15 Jun 2026
Nothing published for this version
- 1.380.04 Jun 2026
Nothing published for this version
- 1.379.34 Jun 2026
Nothing published for this version
- 1.379.23 Jun 2026
Nothing published for this version
- 1.379.13 Jun 2026
Nothing published for this version