npm / posthog-node
posthog-node
What changed in posthog-node 5, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-18.
15 breaking10 deprecations58 new APIs and options3 performance37 behavior and defaults62 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli initposthog-node 5185 changes
Breaking changes 15
Returns a snapshot, so changing individual keys no longer affects deduplication; the cache evicts only the least recently used distinct IDs instead of clearing entirely.
Server-side feature flags now resolve in posthog-node even when a proxy rewrites the request's User-Agent; flags restricted to the client runtime resolve to undefined.
Bigint attributes on logs, metrics, and spans are now sent as int64 rather than as strings.
Local evaluation now honors evaluationContexts; flags whose evaluation contexts do not overlap the configured list resolve to undefined instead of being evaluated locally.
Events are dropped when the before-send hook throws, rather than being sent unmodified.
Replaces the internal AI capture options; when set, wrappers route through the AI endpoint and skip redaction and truncation, while privacy mode still takes precedence.
Shutdown timeouts are logged without rejecting, so callers do not receive a rejection for a timeout.
No longer suppresses Node's default crash on unhandled promise rejections; fatal rejections in strict or warn-with-error-code mode and rejections handled by another unhandledRejection listener are no longer captured.
Semver values with leading zeros are rejected in both flag and override values; invalid inputs surface as InconclusiveMatchError and do not match targeting conditions.
An inactive flag now short-circuits to false even when ensure_experience_continuity is true, instead of throwing InconclusiveMatchError and resolving to undefined.
Cohort property groups containing a flag-type property now mark cohort evaluation inconclusive, so the flag returns undefined instead of a wrong definitive answer.
is_set now returns true when a property key is present, even if its value is null or undefined.
Use evaluationContexts in posthog.init to specify evaluation contexts instead of deployment environments.
The minimum supported Node.js version is now ^20.20.0 || >=22.22.0 due to an async-hooks DoS vulnerability.
Contexts inherit by default, changing how context values are passed to child contexts.
Deprecations 10
The Node SDK Sentry integration is deprecated; users are directed to PostHog Error Tracking for Node.
Imports from posthog-node/experimental are deprecated.
The sendFeatureFlags option is deprecated; it continues to work but logs a deduped warning the first time it is used, and removal is planned for the next major version.
Deprecated; it continues to work but logs a deduped warning the first time it is used, and removal is planned for the next major version.
Deprecated; it continues to work but logs a deduped warning the first time it is used, and removal is planned for the next major version.
Deprecated; it continues to work but logs a deduped warning the first time it is used, and removal is planned for the next major version.
Manual capture('$exception') now emits a warning.
The posthog.init option is deprecated in favor of evaluationContexts; it continues to work and logs a deprecation warning.
A warning is emitted when local evaluation encounters flags with experience continuity enabled, explaining that they cause server requests on every evaluation.
The package is deprecated.
New APIs and options 58
Local feature flag evaluation can use a shared definition cache without a secret or personal API key.
Feature flag evaluation reasons are exposed and preserved in OpenFeature resolution metadata.
Adds an API to read a feature flag's evaluation runtime.
Adds an API to get feature flag keys by evaluation runtime.
Adds a hook that sees every span before export and may edit or drop it.
Adds experimental distributed tracing that records spans using the traces client option.
Bounds how many attributes a single span may hold.
Bounds attribute value length for spans.
Bounds how many events a single span may hold.
Bounds how many spans a single process may hold.
Bounds how long a span may be held by a single process.
Adds experimental distributed tracing that records spans using the traces client option.
Adds a client option for recording experimental distributed tracing spans.
Adds experimental distributed tracing that records spans using the traces client option.
Exception capture methods are now exposed through the IPostHog interface.
Accepts an optional defaultValue returned when a flag has no value; present flag values still take precedence, and omitting the option preserves false-on-miss behavior.
Public beta API for sending AI events to a dedicated isolated endpoint and receiving the event UUID.
Public beta API for sending AI events to a dedicated isolated endpoint and receiving the event UUID.
The property is added to $feature_flag_called events when the server explicitly reports has_experiment; it is omitted when the value is unknown.
Adds an alpha metrics API for recording count, gauge, and histogram metrics from backend services, with in-memory aggregation and OTLP/JSON flushing.
Exposes the error tracking rate-limiter bucket size so customers with high-cardinality exception types can tune the per-type allowance.
Exposes the error tracking rate-limiter refill rate so customers with high-cardinality exception types can tune the per-type allowance.
Dropped and undelivered Capture V1 events are surfaced on the client error channel as CaptureV1Error.
Set POSTHOG_CAPTURE_MODE=v1 to send analytics events to Capture V1 instead of the legacy /batch/ endpoint. Capture V1 uses Bearer auth and per-event partial retries; the default remains v0.
Adds secretKey as the canonical alias for personalApiKey; it accepts a Personal API Key or Project Secret API Key.
Adds groupIdentifyImmediate() to await the network request when identifying a group, useful in edge/serverless environments where the background queue may not flush.
Adds a helper to manage person properties from the Node.js SDK.
Adds a helper to manage person properties from the Node.js SDK.
Local evaluation now supports the early_exit condition option, stopping with false when matching property filters are excluded by the rollout percentage instead of falling through to later groups.
Adds configurable isServer behavior, defaulting to true, to set the $is_server event property; set it to false for client or CLI use so the device OS is attributed normally.
Exposes UUID and cookie helpers from posthog-node so users can manage distinct_id outside the browser SDK.
Accepts a flags snapshot so the same flag evaluations used for branching can enrich a captured event.
Accepts a flags argument so $exception events carry the same flag context as the rest of the request's events.
Accepts a flags argument so $exception events carry the same flag context as the rest of the request's events.
Evaluates feature flags in one /flags request and returns a FeatureFlagEvaluations snapshot with methods for branching and filtering flags attached to captured events.
Pass flagKeys to scope the underlying /flags request to selected flags.
Adds Express and NestJS request context support for PostHog tracing headers.
Adds a NestJS integration with an interceptor for context propagation.
Local feature flag evaluation now supports semver_caret for semantic version comparisons.
Local feature flag evaluation now supports semver_eq for semantic version comparisons.
Local feature flag evaluation now supports semver_gt for semantic version comparisons.
Local feature flag evaluation now supports semver_gte for semantic version comparisons.
Local feature flag evaluation now supports semver_lt for semantic version comparisons.
Local feature flag evaluation now supports semver_lte for semantic version comparisons.
Local feature flag evaluation now supports semver_neq for semantic version comparisons.
Local feature flag evaluation now supports semver_tilde for semantic version comparisons.
Local feature flag evaluation now supports semver_wildcard for semantic version comparisons.
Accepts a waitUntil method for serverless environments.
Adds enterContext() to attach a context to the current async execution context.
Adds an /edge subpath export for use with non-standard edge runtimes.
Adds a method to retrieve a feature flag value and payload in a single API call.
Set strictLocalEvaluation: true at client init to prevent server fallback for flag evaluations; flags that cannot be evaluated locally return undefined.
Adds the overrideFeatureFlags() method for local testing and development.
Adds $feature_flag_error to $feature_flag_called events to track flag evaluation failures.
Context support was added.
Adds a client configuration option for the flag definition cache provider.
Adds the FlagDefinitionCacheProvider interface for providing a flag definition cache.
Enables tracking bot traffic as $bot_pageview events when enabled.
Performance 3
Node SDK payloads use Node's zlib gzip implementation to avoid sustained memory growth from frequent Web Streams compression.
Local evaluation polling sends the latest etag in an If-None-Match header to reduce bandwidth when no flags have changed.
Cache initialization performance was improved.
Behavior and default changes 37
Captured exceptions are linked to active OpenTelemetry traces when the API is available.
Metrics recorded inside sampled spans now have trace exemplars attached.
Setting featureFlagsPollingInterval to null disables automatic local flag polling while retaining initialization and manual refresh.
Feature flag cache payloads now support snake_case while preserving compatibility with camelCase providers and cached data.
Error capture now includes causes and AggregateError members with relationship metadata and individual stacks, limited to 50 entries and 1,000 member inspections.
Batches over 10 MiB or too large to serialize are stopped before making a request.
Logs and metrics retries honor Retry-After, extend waits up to five minutes, add jitter, and metrics back off exponentially across consecutive failures.
A false value means a conclusive off evaluation, while undefined means no evaluation is available. Remote evaluation omits globally inactive flags; backend local evaluation can resolve cached inactive definitions to false.
When a requested flag is missing from loaded local definitions, scoped calls now fall back to remote evaluation instead of omitting the flag without making a request.
Feature flag local evaluation now supports ends_with property filters, with case-insensitive matching, so matching flags no longer fall back to remote evaluation.
Feature flag local evaluation now supports not_ends_with property filters, with case-insensitive matching, so matching flags no longer fall back to remote evaluation.
Feature flag local evaluation now supports not_starts_with property filters, with case-insensitive matching, so matching flags no longer fall back to remote evaluation.
Feature flag local evaluation now supports starts_with property filters, with case-insensitive matching, so matching flags no longer fall back to remote evaluation.
Local feature flag polls are scheduled after each request settles.
Feature flag methods now accept numeric and boolean group property values through the shared Properties type, matching local evaluation.
Feature flag methods now accept numeric and boolean person property values through the shared Properties type, matching local evaluation.
Exception events include the injected release id as $release_id when one can be read, allowing PostHog to attach exceptions to a release without joining through symbol sets.
When the server enables minimal events, evaluations of flags not linked to experiments emit events rebuilt from an allowlist; missing signals and experiment-linked flags retain the full event.
The default maxQueueSize increases from 1000 to 10000 to reduce silent event drops during bursty workloads; an explicit option still overrides the default.
Pending metrics are flushed when shutdown() is called.
In v1 mode, $ai_* events continue to use the legacy submitter and an isolated in-memory queue, flushed independently so the transports do not share batches.
before_send is now called for identify, group identify, and alias events.
Feature flag requests are retried only after transient network errors. The retry count defaults to 1 and can be set to 0 to disable retries.
Batch payloads no longer send the top-level type, library, and library_version fields. SDK metadata uses properties.$lib and properties.$lib_version, falling back to legacy queued values when those properties are missing.
Feature flag definition cache provider types are now available from the main posthog-node export.
Local evaluation now supports mixed targeting.
Frames are sent with relative file paths.
Sends $device_id as a top-level field in /flags requests, enabling device-based bucketing during remote evaluation.
The config query parameter is omitted by default so requests retrieve only the necessary data.
Locally evaluated flags now include timing information in $feature_flag_called events, helping debug cache TTL and timing issues.
A context-sensitive override no longer requires distinctId as a parameter and instead reads it from the current context.
A context-sensitive override no longer requires distinctId as a parameter and instead reads it from the current context.
A context-sensitive override no longer requires distinctId as a parameter and instead reads it from the current context.
Traces now track the exception_id, helping correlate traces with exceptions.
Exceptions now track the LLM trace_id, helping correlate exceptions with traces.
Adds $feature_flag_evaluated_at properties to $feature_flag_called events.
The Express error handler now forwards session and distinct id.
Fixes and other changes 62
Types now accept non-null events while still allowing null returns to drop events.
Local feature flag evaluation now honors filters.holdout before release conditions, assigning held-out users the holdout variant and matching server evaluation.
Spans that run past the age limit and then end are exported; maxSpanAgeMs now evicts spans only once maxLiveSpans is reached, preventing their children from being orphaned.
Local feature flag evaluation respects the definitions response version: version 2 uses explicit boolean/string equality and per-member array matching, while missing or other versions retain service legacy matching.
Express exception events now report the final HTTP status instead of the initial response status.
Child spans now share their parent's clock, preventing them from appearing to start before or end after their parent, including when the system clock changes mid-trace.
A throwing getter no longer breaks every metrics export; its key is recorded as
[Unserializable]instead.Logs and metrics always send service.name and telemetry.sdk.* even when a resourceAttributes value is too large to encode in full.
Logs and metrics always send service.name and telemetry.sdk.* even when a resourceAttributes value is too large to encode in full.
Parsed stack traces now collapse repeated frame cycles to reduce grouping differences caused by recursion depth while preserving distinct throw locations.
Local feature flag evaluation now matches the flags service for string operators, exact-value coercion, and JSON stringification.
Narrows the bot-detection blocklist entry to pinterestbot so users of Pinterest's in-app browser are no longer misclassified as bots and excluded from analytics.
Omitted local evaluation properties are treated as inconclusive for is_not_set.
Empty feature flag evaluation key scopes are handled without running local or remote evaluation.
The Node SDK sends raw gzip bytes instead of wrapping them in a Blob, avoiding a native BlobReader leak on Node 24.16 and later. Compression behavior, headers, and wire format are unchanged.
Fixes remotely evaluated results to return an undefined variant instead of null.
Logs and metrics are no longer silently dropped for attributes containing certain unsupported or unusually large values; attributes are capped and excess content is marked as [Truncated].
OtlpAnyValue.intValue is typed as string | number, so code reading the field must handle both types.
Capture timestamp overrides are normalized to equivalent UTC ISO strings in the browser and Node.js SDKs and shared core.
The Node.js shutdown() return type is corrected to Promise<void>.
Configured request timeouts are now enforced while consuming Capture V1 response bodies.
Request timeouts remain active while the response body is consumed.
Minimal events retain $referring_domain and canonical utm_*/campaign parameters, preventing a flag-called event from setting session attribution and channel type to NULL.
Bounds stack source context reads and skips non-regular or oversized files.
Completed lifecycle timeout handles are cleared so successful shutdowns do not leave timers running.
Events added to a full queue are preserved while an earlier batch is being flushed.
The timeout remains active until the request settles, including while the response body is consumed.
When the supplied ID matches the persisted distinct ID, identify() now marks the user identified and captures a person-processed $set event.
NestJS request context is isolated per Observable subscription.
Normalizes V8 Promise combinator stack frames so input indexes are not treated as source filenames.
Avoids Edge runtime warnings related to native compression and fatal error handling.
The default Node.js event flush interval is fixed at 5 seconds.
Stops duplicating distinct_id inside /flags person properties.
Requests to /flags that receive HTTP 502 or 504 responses are retried across SDKs using the shared core flags client.
Node flush() waits for pending asynchronous SDK work before draining the event queue, so helper-produced events are not missed; pending work rejections no longer prevent queued events from flushing.
Event batches with circular property references are safely serialized instead of crashing during flush.
Local evaluation now applies the in/not_in operator to cohort membership, fixing inverted cohort-exclusion flags.
Only stamp $groups from the top-level groups when present.
Feature flag called events are deduplicated per returned flag value.
Respect disable_capture_url_hashes when capturing Express and NestJS request URLs.
Custom event UUID overrides are validated, and a new UUID is generated when an override is invalid.
Initialization paths with missing or blank PostHog project tokens now disable or no-op instead of throwing or sending requests.
captureException was unified in posthog core.
The deduplication key now includes group context, so events fire independently per group combination.
identifyImmediate now awaits the underlying network request, preventing the $identify event from being dropped when short-lived runtimes exit after await.
Local gt/gte/lt/lte evaluation now compares numerically when both sides parse as finite numbers, avoiding incorrect lexicographic comparisons.
Local evaluation resolves is_not_set as true when the property key is absent and false when present, rather than throwing InconclusiveMatchError.
Flag-level condition properties with negation: true are now inverted, matching the existing cohort-path behavior.
The fetch response body is consumed to prevent Cloudflare Workers runtime warnings.
Local evaluation polling now uses /flags/definitions instead of /api/feature_flag/local_evaluation.
Surrounding whitespace is trimmed from user-provided API keys, personal API keys, and host config values before they are used.
Local flag evaluation cache now preserves $set_once semantics.
captureException now uses distinctId from request context.
Fixed the return value of captureExceptionImmediate.
Client shutdown now awaits the feature flags poller stopping.
Super properties added with register now work.
In Node, before_send now infers its type as EventMessage or null instead of any.
getFeatureFlag() respects exponential backoff for HTTP 401, 403, and 429 responses.
Fixes the frame platform property for $exception events.
fetch is called without a bound context, preventing issues in edge runtimes such as Cloudflare.
Fixes a crash when calling getFeatureFlagPayloads for a flag that depends on a static cohort.
Fixes server fallback when a static cohort condition is followed by a matching condition.