Skip to content

fix(browser): capture SPA pageviews on query string and hash changes - #4729

Draft
posthog[bot] wants to merge 2 commits into
mainfrom
posthog-self-driving/fixbrowser-capture-spa-pageviews-on-dee2de
Draft

fix(browser): capture SPA pageviews on query string and hash changes#4729
posthog[bot] wants to merge 2 commits into
mainfrom
posthog-self-driving/fixbrowser-capture-spa-pageviews-on-dee2de

Conversation

@posthog

@posthog posthog Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Problem

  • Single-page-app customers on the modern SDK defaults silently lose 10-15% of their $pageview events. Every number built on pageviews reads low.
  • capture_pageview: 'history_change' expanded to { path: true } only, so _hasLocationChanged compared location.pathname alone. A pushState, replaceState, or popstate that changed only the query string or only the hash captured nothing.
  • Search results, filters, pagination, and tab state all navigate that way.
  • This is the default for anyone who initializes with defaults of '2025-05-24' or later, so it hits every new SPA install.
  • $pageleave still fires from a real page unload, which is why an affected customer sees pageleaves match their old tracker while pageviews come up short.

Changes

  • 'history_change' now selects all three URL components instead of the path alone.
-            return { path: true }
+            return { path: true, search: true, hash: true }
capture_pageview path change query-only change hash-only change
'history_change' before
'history_change' after ✅ (unless disable_capture_url_hashes)
{ path: true }
  • disable_capture_url_hashes keeps priority: _shouldCaptureHashChanges already gates the hash component, and disable_capture_url_hashes is itself a default from '2026-06-25' onward. A test covers this combination.
  • Tests that asserted the old silence now assert the pageview, plus the doc comment on capture_pageview and a changeset.

Note

This raises the $pageview count for SPAs on 'history_change', which is the point, but it is a visible change in event volume. Anyone who wants the old behaviour can set capture_pageview: { path: true }. The granular { path, search, hash } shape is already public, so no new API is added.

Release info Sub-libraries affected

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react-native-plugin
  • @posthog/react
  • @posthog/ai
  • @posthog/convex
  • @posthog/next
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/openfeature-node-provider
  • @posthog/openfeature-web-provider
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin
  • @posthog/types
  • @posthog/browser-common

Checklist

  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!) — behaviour of 'history_change' changes on purpose; see the note above
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Fully autonomous

  • Written by Claude Code in PostHog Desktop, from the linked inbox report.
  • Considered making only search a default and leaving hash opt-in. Rejected it: hash routing is a normal SPA pattern, and disable_capture_url_hashes already gives the escape hatch, and it is on by default for '2026-06-25' defaults.
  • Considered normalizing the query string (ignore parameter order) so that a re-order does not capture a pageview. Rejected as out of scope; the existing granular path comparison does not normalize either.
  • Verified with the unit suite for history-autocapture, config, cookieless, and posthog-core-also: all pass. One unrelated suite (persistence key policy) fails on main in this environment as well. pnpm typecheck cannot finish here because the @posthog/rrweb* workspace packages are not built; CI covers it.
  • No manual browser test was run.

Created with PostHog Desktop from this inbox report.

`capture_pageview: 'history_change'` expanded to `{ path: true }`, so a pushState, replaceState, or popstate that changed only the query string or only the hash captured no `$pageview`. Single-page apps that navigate for search, filters, pagination, and tab state lost those pageviews. This is the default for any SDK initialized with `defaults` of '2025-05-24' or later.

`'history_change'` now expands to `{ path: true, search: true, hash: true }`. `disable_capture_url_hashes` still suppresses hash-only changes.

Generated-By: PostHog Desktop
Task-Id: ca7d1e51-64ae-42fc-9c7c-20c2eb623cf9
@posthog

posthog Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

🦔 PostHog Review reviewed this pull request

Found 2 must fix, 2 should fix, 2 consider.

Published 6 findings (view the review).

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

posthog-js Compliance Report

Date: 2026-09-01 17:48:54 UTC
Duration: 88642ms

✅ All Tests Passed!

26/26 tests passed


Capture Tests

26/26 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields Client 97ms
Format Validation.Event Has Uuid 14ms
Format Validation.Event Has Lib Properties 10ms
Format Validation.Distinct Id Is String Client 11ms
Format Validation.Token Is Present Client 12ms
Format Validation.Custom Properties Preserved 11ms
Format Validation.Event Has Timestamp 11ms
Retry Behavior.Retries On 503 5015ms
Retry Behavior.Does Not Retry On 400 2014ms
Retry Behavior.Does Not Retry On 401 2014ms
Retry Behavior.Respects Retry After Header 5013ms
Retry Behavior.Implements Backoff 15026ms
Retry Behavior.Retries On 500 5011ms
Retry Behavior.Retries On 502 5011ms
Retry Behavior.Retries On 504 5015ms
Retry Behavior.Max Retries Respected 15021ms
Deduplication.Generates Unique Uuids 16ms
Deduplication.Preserves Uuid On Retry 5010ms
Deduplication.Preserves Uuid And Timestamp On Retry 10021ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 5019ms
Deduplication.No Duplicate Events In Batch 15ms
Deduplication.Different Events Have Different Uuids 10ms
Batch Format.Flush With No Events Sends Nothing 4ms
Error Handling.Does Not Retry On 403 2012ms
Error Handling.Does Not Retry On 413 2012ms
Error Handling.Retries On 408 5015ms

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Size Change: -647 B (0%)

Total Size: 20.8 MB

📦 View Changed
Filename Size Change
packages/browser/dist/all-external-dependencies.js 362 kB -95 B (-0.03%)
packages/browser/dist/array.full.es5.js 493 kB +18 B (0%)
packages/browser/dist/array.full.js 603 kB -77 B (-0.01%)
packages/browser/dist/array.full.no-********.js 660 kB -77 B (-0.01%)
packages/browser/dist/array.js 279 kB +18 B (+0.01%)
packages/browser/dist/array.no-********.js 317 kB +18 B (+0.01%)
packages/browser/dist/default-extensions.js 276 kB +18 B (+0.01%)
packages/browser/dist/extension-bundles.js 155 kB +18 B (+0.01%)
packages/browser/dist/lazy-********.js 202 kB -95 B (-0.05%)
packages/browser/dist/main.js 283 kB +18 B (+0.01%)
packages/browser/dist/module.full.js 606 kB -77 B (-0.01%)
packages/browser/dist/module.full.no-********.js 663 kB -77 B (-0.01%)
packages/browser/dist/module.js 282 kB +18 B (+0.01%)
packages/browser/dist/module.no-********.js 321 kB +18 B (+0.01%)
packages/browser/dist/posthog-********.js 202 kB -95 B (-0.05%)
packages/browser/dist/recorder-v2.js 126 kB -95 B (-0.08%)
packages/browser/dist/recorder.js 126 kB -95 B (-0.08%)
packages/nuxt/dist/runtime/composables/useFeatureFlagPayload.js 690 B -8 B (-1.15%)
ℹ️ View Unchanged
Filename Size Change
packages/ai/dist/anthropic/index.cjs 42.5 kB 0 B
packages/ai/dist/anthropic/index.mjs 42.1 kB 0 B
packages/ai/dist/gemini/index.cjs 41.7 kB 0 B
packages/ai/dist/gemini/index.mjs 41.6 kB 0 B
packages/ai/dist/index.cjs 63.9 kB 0 B
packages/ai/dist/index.mjs 63.8 kB 0 B
packages/ai/dist/langchain/index.cjs 43.1 kB 0 B
packages/ai/dist/langchain/index.mjs 43.1 kB 0 B
packages/ai/dist/langchain/middleware/index.cjs 49.8 kB 0 B
packages/ai/dist/langchain/middleware/index.mjs 49.8 kB 0 B
packages/ai/dist/openai-agents/index.cjs 31.8 kB 0 B
packages/ai/dist/openai-agents/index.mjs 31.7 kB 0 B
packages/ai/dist/openai/index.cjs 94.9 kB 0 B
packages/ai/dist/openai/index.mjs 94.5 kB 0 B
packages/ai/dist/otel/index.cjs 18.4 kB 0 B
packages/ai/dist/otel/index.mjs 18.3 kB 0 B
packages/ai/dist/vercel/index.cjs 54 kB 0 B
packages/ai/dist/vercel/index.mjs 53.9 kB 0 B
packages/browser-common/dist/client.js 603 B 0 B
packages/browser-common/dist/client.mjs 0 B 0 B 🆕
packages/browser-common/dist/config.js 1.43 kB 0 B
packages/browser-common/dist/config.mjs 223 B 0 B
packages/browser-common/dist/constants.js 1.66 kB 0 B
packages/browser-common/dist/constants.mjs 219 B 0 B
packages/browser-common/dist/disposable.js 1.63 kB 0 B
packages/browser-common/dist/disposable.mjs 386 B 0 B
packages/browser-common/dist/extension-runtime.js 3.07 kB 0 B
packages/browser-common/dist/extension-runtime.mjs 1.83 kB 0 B
packages/browser-common/dist/extension.js 603 B 0 B
packages/browser-common/dist/extension.mjs 0 B 0 B 🆕
packages/browser-common/dist/index.js 3.08 kB 0 B
packages/browser-common/dist/index.mjs 170 B 0 B
packages/browser-common/dist/persistence.js 603 B 0 B
packages/browser-common/dist/persistence.mjs 0 B 0 B 🆕
packages/browser-common/dist/pubsub.js 2.53 kB 0 B
packages/browser-common/dist/pubsub.mjs 1.35 kB 0 B
packages/browser-common/dist/token.js 603 B 0 B
packages/browser-common/dist/token.mjs 0 B 0 B 🆕
packages/browser-common/dist/types/compression.js 1.28 kB 0 B
packages/browser-common/dist/types/compression.mjs 93 B 0 B
packages/browser-common/dist/types/index.js 4.11 kB 0 B
packages/browser-common/dist/types/index.mjs 144 B 0 B
packages/browser-common/dist/types/network-recording.js 603 B 0 B
packages/browser-common/dist/types/network-recording.mjs 0 B 0 B 🆕
packages/browser-common/dist/types/remote-config.js 603 B 0 B
packages/browser-common/dist/types/remote-config.mjs 0 B 0 B 🆕
packages/browser-common/dist/types/surveys.js 4.55 kB 0 B
packages/browser-common/dist/types/surveys.mjs 2.17 kB 0 B
packages/browser-common/dist/utils/array-at-********.js 628 B 0 B
packages/browser-common/dist/utils/array-at-********.mjs 425 B 0 B
packages/browser-common/dist/utils/autocapture-utils.js 24.2 kB 0 B
packages/browser-common/dist/utils/autocapture-utils.mjs 18.6 kB 0 B
packages/browser-common/dist/utils/blocked-uas.js 2.1 kB 0 B
packages/browser-common/dist/utils/blocked-uas.mjs 598 B 0 B
packages/browser-common/dist/utils/cookie-utils.js 1.89 kB 0 B
packages/browser-common/dist/utils/cookie-utils.mjs 673 B 0 B
packages/browser-common/dist/utils/device-model-utils.js 1.98 kB 0 B
packages/browser-common/dist/utils/device-model-utils.mjs 678 B 0 B
packages/browser-common/dist/utils/element-utils.js 2.46 kB 0 B
packages/browser-common/dist/utils/element-utils.mjs 804 B 0 B
packages/browser-common/dist/utils/elements-chain-utils.js 2.77 kB 0 B
packages/browser-common/dist/utils/elements-chain-utils.mjs 1.23 kB 0 B
packages/browser-common/dist/utils/encode-utils.js 1.4 kB 0 B
packages/browser-common/dist/utils/encode-utils.mjs 205 B 0 B
packages/browser-common/dist/utils/event-utils.js 15.7 kB 0 B
packages/browser-common/dist/utils/event-utils.mjs 10 kB 0 B
packages/browser-common/dist/utils/general-utils.js 7.31 kB 0 B
packages/browser-common/dist/utils/general-utils.mjs 4.49 kB 0 B
packages/browser-common/dist/utils/globals.js 2.78 kB 0 B
packages/browser-common/dist/utils/globals.mjs 860 B 0 B
packages/browser-common/dist/utils/logger.js 3.4 kB 0 B
packages/browser-common/dist/utils/logger.mjs 1.61 kB 0 B
packages/browser-common/dist/utils/matcher-utils.js 2.85 kB 0 B
packages/browser-common/dist/utils/matcher-utils.mjs 1.33 kB 0 B
packages/browser-common/dist/utils/promise-utils.js 1.36 kB 0 B
packages/browser-common/dist/utils/promise-utils.mjs 169 B 0 B
packages/browser-common/dist/utils/property-utils.js 3.53 kB 0 B
packages/browser-common/dist/utils/property-utils.mjs 1.6 kB 0 B
packages/browser-common/dist/utils/prototype-utils.js 3.51 kB 0 B
packages/browser-common/dist/utils/prototype-utils.mjs 1.86 kB 0 B
packages/browser-common/dist/utils/regex-utils.js 1.45 kB 0 B
packages/browser-common/dist/utils/regex-utils.mjs 113 B 0 B
packages/browser-common/dist/utils/request-utils.js 6.73 kB 0 B
packages/browser-common/dist/utils/request-utils.mjs 4.19 kB 0 B
packages/browser-common/dist/utils/simple-event-emitter.js 1.76 kB 0 B
packages/browser-common/dist/utils/simple-event-emitter.mjs 553 B 0 B
packages/browser-common/dist/utils/stylesheet-loader.js 2.13 kB 0 B
packages/browser-common/dist/utils/stylesheet-loader.mjs 823 B 0 B
packages/browser-common/dist/utils/type-utils.js 1.59 kB 0 B
packages/browser-common/dist/utils/type-utils.mjs 267 B 0 B
packages/browser-common/dist/utils/url-targeting-utils.js 2.35 kB 0 B
packages/browser-common/dist/utils/url-targeting-utils.mjs 863 B 0 B
packages/browser-common/dist/utils/uuidv7.js 6.66 kB 0 B
packages/browser-common/dist/utils/uuidv7.mjs 5.18 kB 0 B
packages/browser-next/dist/analytics-********.js 1.58 kB 0 B
packages/browser-next/dist/analytics-********.mjs 219 B 0 B
packages/browser-next/dist/analytics-options.js 603 B 0 B
packages/browser-next/dist/analytics-options.mjs 0 B 0 B 🆕
packages/browser-next/dist/analytics.js 6.52 kB 0 B
packages/browser-next/dist/analytics.mjs 5.15 kB 0 B
packages/browser-next/dist/bot-filter.js 2.28 kB 0 B
packages/browser-next/dist/bot-filter.mjs 1.09 kB 0 B
packages/browser-next/dist/capture-v1.js 27.7 kB 0 B
packages/browser-next/dist/capture-v1.mjs 25.3 kB 0 B
packages/browser-next/dist/core.js 1.59 kB 0 B
packages/browser-next/dist/core.mjs 194 B 0 B
packages/browser-next/dist/extensions/registry.js 3.32 kB 0 B
packages/browser-next/dist/extensions/registry.mjs 2.11 kB 0 B
packages/browser-next/dist/id.js 2.15 kB 0 B
packages/browser-next/dist/id.mjs 983 B 0 B
packages/browser-next/dist/index.js 3.38 kB 0 B
packages/browser-next/dist/index.mjs 1.19 kB 0 B
packages/browser-next/dist/lane.js 18 kB 0 B
packages/browser-next/dist/lane.mjs 16.9 kB 0 B
packages/browser-next/dist/logger.js 1.77 kB 0 B
packages/browser-next/dist/logger.mjs 581 B 0 B
packages/browser-next/dist/posthog.js 33.1 kB 0 B
packages/browser-next/dist/posthog.mjs 30.9 kB 0 B
packages/browser-next/dist/rate-limiter.js 2.79 kB 0 B
packages/browser-next/dist/rate-limiter.mjs 1.58 kB 0 B
packages/browser-next/dist/request.js 4.52 kB 0 B
packages/browser-next/dist/request.mjs 3.21 kB 0 B
packages/browser-next/dist/state.js 24.8 kB 0 B
packages/browser-next/dist/state.mjs 23.2 kB 0 B
packages/browser-next/dist/types.js 603 B 0 B
packages/browser-next/dist/types.mjs 0 B 0 B 🆕
packages/browser-next/dist/version.js 1.21 kB 0 B
packages/browser-next/dist/version.mjs 45 B 0 B
packages/browser/dist/conversations.js 69 kB 0 B
packages/browser/dist/crisp-chat-integration.js 2.03 kB 0 B
packages/browser/dist/customizations.full.js 16.1 kB 0 B
packages/browser/dist/customizations.js 16 kB 0 B
packages/browser/dist/dead-clicks-autocapture.js 18.3 kB 0 B
packages/browser/dist/element-inference.js 5.62 kB 0 B
packages/browser/dist/exception-autocapture.js 13.6 kB 0 B
packages/browser/dist/external-scripts-loader.js 3.6 kB 0 B
packages/browser/dist/intercom-integration.js 2.08 kB 0 B
packages/browser/dist/logs.js 5.83 kB 0 B
packages/browser/dist/module.slim.js 140 kB 0 B
packages/browser/dist/module.slim.no-********.js 154 kB 0 B
packages/browser/dist/product-tours-preview.js 82.4 kB 0 B
packages/browser/dist/product-tours.js 124 kB 0 B
packages/browser/dist/rrweb-plugin-console-record.js 7.05 kB 0 B
packages/browser/dist/rrweb-types.js 2.33 kB 0 B
packages/browser/dist/rrweb.js 318 kB 0 B
packages/browser/dist/surveys-preview.js 81.5 kB 0 B
packages/browser/dist/surveys.js 103 kB 0 B
packages/browser/dist/tracing-headers.js 3.76 kB 0 B
packages/browser/dist/web-vitals-soft-navs.js 9.96 kB 0 B
packages/browser/dist/web-vitals-with-attribution-soft-navs.js 25.4 kB 0 B
packages/browser/dist/web-vitals-with-attribution.js 25.3 kB 0 B
packages/browser/dist/web-vitals.js 9.94 kB 0 B
packages/browser/react/dist/esm/index.js 22.5 kB 0 B
packages/browser/react/dist/esm/slim/index.js 18.9 kB 0 B
packages/browser/react/dist/esm/surveys/index.js 4.75 kB 0 B
packages/browser/react/dist/umd/index.js 25.9 kB 0 B
packages/browser/react/dist/umd/slim/index.js 21.8 kB 0 B
packages/browser/react/dist/umd/surveys/index.js 5.52 kB 0 B
packages/convex/dist/client/feature-flags/crypto.js 76 B 0 B
packages/convex/dist/client/feature-flags/evaluator.js 14.9 kB 0 B
packages/convex/dist/client/feature-flags/index.js 196 B 0 B
packages/convex/dist/client/feature-flags/match-********.js 5.08 kB 0 B
packages/convex/dist/client/feature-flags/types.js 44 B 0 B
packages/convex/dist/client/index.js 14.8 kB 0 B
packages/convex/dist/component/_generated/api.js 712 B 0 B
packages/convex/dist/component/_generated/component.js 212 B 0 B
packages/convex/dist/component/_generated/dataModel.js 230 B 0 B
packages/convex/dist/component/_generated/server.js 3.74 kB 0 B
packages/convex/dist/component/convex.config.js 1.66 kB 0 B
packages/convex/dist/component/crons.js 969 B 0 B
packages/convex/dist/component/lib.js 24.8 kB 0 B
packages/convex/dist/component/schema.js 1.17 kB 0 B
packages/convex/dist/component/version.js 67 B 0 B
packages/core/dist/cookie.js 5.34 kB 0 B
packages/core/dist/cookie.mjs 3.12 kB 0 B
packages/core/dist/error-tracking/chunk-ids.js 2.54 kB 0 B
packages/core/dist/error-tracking/chunk-ids.mjs 1.31 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.js 2.3 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.mjs 993 B 0 B
packages/core/dist/error-tracking/coercers/error-coercer.js 2.13 kB 0 B
packages/core/dist/error-tracking/coercers/error-coercer.mjs 888 B 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.js 2.37 kB 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.mjs 1.07 kB 0 B
packages/core/dist/error-tracking/coercers/event-coercer.js 1.82 kB 0 B
packages/core/dist/error-tracking/coercers/event-coercer.mjs 548 B 0 B
packages/core/dist/error-tracking/coercers/index.js 6.79 kB 0 B
packages/core/dist/error-tracking/coercers/index.mjs 326 B 0 B
packages/core/dist/error-tracking/coercers/object-coercer.js 4.04 kB 0 B
packages/core/dist/error-tracking/coercers/object-coercer.mjs 2.53 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.js 1.67 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.mjs 419 B 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.js 2.59 kB 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.mjs 1.25 kB 0 B
packages/core/dist/error-tracking/coercers/string-coercer.js 2.01 kB 0 B
packages/core/dist/error-tracking/coercers/string-coercer.mjs 820 B 0 B
packages/core/dist/error-tracking/coercers/utils.js 2.06 kB 0 B
packages/core/dist/error-tracking/coercers/utils.mjs 716 B 0 B
packages/core/dist/error-tracking/error-properties-builder.js 5.56 kB 0 B
packages/core/dist/error-tracking/error-properties-builder.mjs 4.23 kB 0 B
packages/core/dist/error-tracking/exception-steps.js 6.01 kB 0 B
packages/core/dist/error-tracking/exception-steps.mjs 3.84 kB 0 B
packages/core/dist/error-tracking/index.js 5.32 kB 0 B
packages/core/dist/error-tracking/index.mjs 222 B 0 B
packages/core/dist/error-tracking/parsers/base.js 2 kB 0 B
packages/core/dist/error-tracking/parsers/base.mjs 627 B 0 B
packages/core/dist/error-tracking/parsers/chrome.js 2.73 kB 0 B
packages/core/dist/error-tracking/parsers/chrome.mjs 1.32 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.js 2.47 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.mjs 1.13 kB 0 B
packages/core/dist/error-tracking/parsers/index.js 4.75 kB 0 B
packages/core/dist/error-tracking/parsers/index.mjs 2.1 kB 0 B
packages/core/dist/error-tracking/parsers/node.js 4.21 kB 0 B
packages/core/dist/error-tracking/parsers/node.mjs 2.95 kB 0 B
packages/core/dist/error-tracking/parsers/opera.js 2.26 kB 0 B
packages/core/dist/error-tracking/parsers/opera.mjs 746 B 0 B
packages/core/dist/error-tracking/parsers/safari.js 1.88 kB 0 B
packages/core/dist/error-tracking/parsers/safari.mjs 574 B 0 B
packages/core/dist/error-tracking/parsers/winjs.js 1.72 kB 0 B
packages/core/dist/error-tracking/parsers/winjs.mjs 426 B 0 B
packages/core/dist/error-tracking/release.js 1.42 kB 0 B
packages/core/dist/error-tracking/release.mjs 203 B 0 B
packages/core/dist/error-tracking/types.js 1.33 kB 0 B
packages/core/dist/error-tracking/types.mjs 131 B 0 B
packages/core/dist/error-tracking/utils.js 1.8 kB 0 B
packages/core/dist/error-tracking/utils.mjs 604 B 0 B
packages/core/dist/eventemitter.js 1.78 kB 0 B
packages/core/dist/eventemitter.mjs 571 B 0 B
packages/core/dist/featureFlagLocalEvaluation.js 22.1 kB 0 B
packages/core/dist/featureFlagLocalEvaluation.mjs 19.6 kB 0 B
packages/core/dist/featureFlagUtils.js 8.52 kB 0 B
packages/core/dist/featureFlagUtils.mjs 5.48 kB 0 B
packages/core/dist/gzip.js 5.79 kB 0 B
packages/core/dist/gzip.mjs 3.87 kB 0 B
packages/core/dist/index.js 24.1 kB 0 B
packages/core/dist/index.mjs 2.6 kB 0 B
packages/core/dist/logs/index.js 10.8 kB 0 B
packages/core/dist/logs/index.mjs 9.17 kB 0 B
packages/core/dist/logs/logs-utils.js 6.59 kB 0 B
packages/core/dist/logs/logs-utils.mjs 4.51 kB 0 B
packages/core/dist/logs/types.js 603 B 0 B
packages/core/dist/logs/types.mjs 0 B 0 B 🆕
packages/core/dist/metrics/config.js 1.95 kB 0 B
packages/core/dist/metrics/config.mjs 735 B 0 B
packages/core/dist/metrics/index.js 14.4 kB 0 B
packages/core/dist/metrics/index.mjs 12 kB 0 B
packages/core/dist/metrics/metrics-utils.js 3.65 kB 0 B
packages/core/dist/metrics/metrics-utils.mjs 1.71 kB 0 B
packages/core/dist/metrics/types.js 603 B 0 B
packages/core/dist/metrics/types.mjs 0 B 0 B 🆕
packages/core/dist/posthog-core-stateless.js 46.9 kB 0 B
packages/core/dist/posthog-core-stateless.mjs 43.6 kB 0 B
packages/core/dist/posthog-core.js 49.5 kB 0 B
packages/core/dist/posthog-core.mjs 43.9 kB 0 B
packages/core/dist/surveys/activation.js 2.2 kB 0 B
packages/core/dist/surveys/activation.mjs 572 B 0 B
packages/core/dist/surveys/events.js 4.27 kB 0 B
packages/core/dist/surveys/events.mjs 2.05 kB 0 B
packages/core/dist/surveys/index.js 6.54 kB 0 B
packages/core/dist/surveys/index.mjs 1.4 kB 0 B
packages/core/dist/surveys/keys.js 1.7 kB 0 B
packages/core/dist/surveys/keys.mjs 350 B 0 B
packages/core/dist/surveys/property-********.js 3.69 kB 0 B
packages/core/dist/surveys/property-********.mjs 2.14 kB 0 B
packages/core/dist/surveys/translations.js 9.09 kB 0 B
packages/core/dist/surveys/translations.mjs 6.83 kB 0 B
packages/core/dist/surveys/validation.js 3.06 kB 0 B
packages/core/dist/surveys/validation.mjs 1.51 kB 0 B
packages/core/dist/testing/index.js 2.93 kB 0 B
packages/core/dist/testing/index.mjs 79 B 0 B
packages/core/dist/testing/PostHogCoreTestClient.js 3.24 kB 0 B
packages/core/dist/testing/PostHogCoreTestClient.mjs 1.83 kB 0 B
packages/core/dist/testing/test-utils.js 2.83 kB 0 B
packages/core/dist/testing/test-utils.mjs 1.15 kB 0 B
packages/core/dist/tracing-headers.js 3.38 kB 0 B
packages/core/dist/tracing-headers.mjs 2.08 kB 0 B
packages/core/dist/types.js 8.35 kB 0 B
packages/core/dist/types.mjs 5.23 kB 0 B
packages/core/dist/utils/bot-detection.js 3.28 kB 0 B
packages/core/dist/utils/bot-detection.mjs 1.96 kB 0 B
packages/core/dist/utils/browser-utils.js 1.48 kB 0 B
packages/core/dist/utils/browser-utils.mjs 182 B 0 B
packages/core/dist/utils/bucketed-rate-limiter.js 4.23 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.mjs 2.22 kB 0 B
packages/core/dist/utils/index.js 16.6 kB 0 B
packages/core/dist/utils/index.mjs 3.36 kB 0 B
packages/core/dist/utils/json-utils.js 6.67 kB 0 B
packages/core/dist/utils/json-utils.mjs 4.45 kB 0 B
packages/core/dist/utils/logger.js 2.58 kB 0 B
packages/core/dist/utils/logger.mjs 1.29 kB 0 B
packages/core/dist/utils/number-utils.js 3.32 kB 0 B
packages/core/dist/utils/number-utils.mjs 1.68 kB 0 B
packages/core/dist/utils/otlp-********.js 2.66 kB 0 B
packages/core/dist/utils/otlp-********.mjs 1.18 kB 0 B
packages/core/dist/utils/otlp-any-value.js 7.87 kB 0 B
packages/core/dist/utils/otlp-any-value.mjs 5.78 kB 0 B
packages/core/dist/utils/promise-queue.js 2.48 kB 0 B
packages/core/dist/utils/promise-queue.mjs 1.25 kB 0 B
packages/core/dist/utils/string-utils.js 3.73 kB 0 B
packages/core/dist/utils/string-utils.mjs 1.97 kB 0 B
packages/core/dist/utils/type-utils.js 7.43 kB 0 B
packages/core/dist/utils/type-utils.mjs 3.28 kB 0 B
packages/core/dist/utils/user-agent-utils.js 18.4 kB 0 B
packages/core/dist/utils/user-agent-utils.mjs 14.7 kB 0 B
packages/core/dist/vendor/uuidv7.js 8.3 kB 0 B
packages/core/dist/vendor/uuidv7.mjs 6.72 kB 0 B
packages/mcp/dist/extensions/analytics-parameters.js 6.53 kB 0 B
packages/mcp/dist/extensions/analytics-parameters.mjs 4.27 kB 0 B
packages/mcp/dist/extensions/capture.js 3.94 kB 0 B
packages/mcp/dist/extensions/capture.mjs 2.58 kB 0 B
packages/mcp/dist/extensions/client-********.js 6.23 kB 0 B
packages/mcp/dist/extensions/client-********.mjs 3.71 kB 0 B
packages/mcp/dist/extensions/compatibility.js 5.36 kB 0 B
packages/mcp/dist/extensions/compatibility.mjs 3.4 kB 0 B
packages/mcp/dist/extensions/constants.js 5.39 kB 0 B
packages/mcp/dist/extensions/constants.mjs 2.95 kB 0 B
packages/mcp/dist/extensions/context-parameters.js 2.75 kB 0 B
packages/mcp/dist/extensions/context-parameters.mjs 893 B 0 B
packages/mcp/dist/extensions/conversation-id.js 6.31 kB 0 B
packages/mcp/dist/extensions/conversation-id.mjs 3.58 kB 0 B
packages/mcp/dist/extensions/detect.js 3.77 kB 0 B
packages/mcp/dist/extensions/detect.mjs 1.49 kB 0 B
packages/mcp/dist/extensions/event-types.js 1.68 kB 0 B
packages/mcp/dist/extensions/event-types.mjs 459 B 0 B
packages/mcp/dist/extensions/exceptions.js 2.57 kB 0 B
packages/mcp/dist/extensions/exceptions.mjs 1.19 kB 0 B
packages/mcp/dist/extensions/headers.js 1.98 kB 0 B
packages/mcp/dist/extensions/headers.mjs 643 B 0 B
packages/mcp/dist/extensions/ids.js 2.01 kB 0 B
packages/mcp/dist/extensions/ids.mjs 637 B 0 B
packages/mcp/dist/extensions/instrument-********.js 4.92 kB 0 B
packages/mcp/dist/extensions/instrument-********.mjs 3.18 kB 0 B
packages/mcp/dist/extensions/instrument-highlevel.js 12.7 kB 0 B
packages/mcp/dist/extensions/instrument-highlevel.mjs 10.2 kB 0 B
packages/mcp/dist/extensions/instrumentation.js 27.8 kB 0 B
packages/mcp/dist/extensions/instrumentation.mjs 21.9 kB 0 B
packages/mcp/dist/extensions/intent.js 3.2 kB 0 B
packages/mcp/dist/extensions/intent.mjs 1.64 kB 0 B
packages/mcp/dist/extensions/internal.js 7.54 kB 0 B
packages/mcp/dist/extensions/internal.mjs 5.23 kB 0 B
packages/mcp/dist/extensions/lib-********.js 1.6 kB 0 B
packages/mcp/dist/extensions/lib-********.mjs 267 B 0 B
packages/mcp/dist/extensions/logger.js 1.72 kB 0 B
packages/mcp/dist/extensions/logger.mjs 380 B 0 B
packages/mcp/dist/extensions/mcp-********.js 4.68 kB 0 B
packages/mcp/dist/extensions/mcp-********.mjs 3.3 kB 0 B
packages/mcp/dist/extensions/mcp-sdk-compat.js 5.04 kB 0 B
packages/mcp/dist/extensions/mcp-sdk-compat.mjs 2.9 kB 0 B
packages/mcp/dist/extensions/model-parameters.js 3.49 kB 0 B
packages/mcp/dist/extensions/model-parameters.mjs 1.41 kB 0 B
packages/mcp/dist/extensions/output-instructions.js 6.11 kB 0 B
packages/mcp/dist/extensions/output-instructions.mjs 3.91 kB 0 B
packages/mcp/dist/extensions/posthog-events.js 11.7 kB 0 B
packages/mcp/dist/extensions/posthog-events.mjs 7.98 kB 0 B
packages/mcp/dist/extensions/posthog-mcp.js 6.94 kB 0 B
packages/mcp/dist/extensions/posthog-mcp.mjs 4.93 kB 0 B
packages/mcp/dist/extensions/request-headers.js 2.17 kB 0 B
packages/mcp/dist/extensions/request-headers.mjs 963 B 0 B
packages/mcp/dist/extensions/sanitization.js 4.49 kB 0 B
packages/mcp/dist/extensions/sanitization.mjs 2.86 kB 0 B
packages/mcp/dist/extensions/session-token.js 5.39 kB 0 B
packages/mcp/dist/extensions/session-token.mjs 3.62 kB 0 B
packages/mcp/dist/extensions/session.js 6.64 kB 0 B
packages/mcp/dist/extensions/session.mjs 4.12 kB 0 B
packages/mcp/dist/extensions/sink.js 4.37 kB 0 B
packages/mcp/dist/extensions/sink.mjs 2.67 kB 0 B
packages/mcp/dist/extensions/tools.js 3.51 kB 0 B
packages/mcp/dist/extensions/tools.mjs 1.63 kB 0 B
packages/mcp/dist/extensions/tracing-helpers.js 2.41 kB 0 B
packages/mcp/dist/extensions/tracing-helpers.mjs 772 B 0 B
packages/mcp/dist/extensions/transport-********.js 2.91 kB 0 B
packages/mcp/dist/extensions/transport-********.mjs 1.09 kB 0 B
packages/mcp/dist/extensions/truncation.js 11.5 kB 0 B
packages/mcp/dist/extensions/truncation.mjs 9.79 kB 0 B
packages/mcp/dist/index.js 8.78 kB 0 B
packages/mcp/dist/index.mjs 4.96 kB 0 B
packages/mcp/dist/types.js 603 B 0 B
packages/mcp/dist/types.mjs 0 B 0 B 🆕
packages/mcp/dist/version.js 1.21 kB 0 B
packages/mcp/dist/version.mjs 46 B 0 B
packages/next/dist/app/PostHogProvider.js 5.37 kB 0 B
packages/next/dist/client/ClientPostHogProvider.js 2.28 kB 0 B
packages/next/dist/client/hooks.js 172 B 0 B
packages/next/dist/client/PostHogPageView.js 4.23 kB 0 B
packages/next/dist/index.client.js 401 B 0 B
packages/next/dist/index.edge.js 570 B 0 B
packages/next/dist/index.js 554 B 0 B
packages/next/dist/index.react-server.js 420 B 0 B
packages/next/dist/middleware/postHogMiddleware.js 4.08 kB 0 B
packages/next/dist/pages.client.js 225 B 0 B
packages/next/dist/pages.edge.js 294 B 0 B
packages/next/dist/pages.js 347 B 0 B
packages/next/dist/pages/createPostHog.js 1.48 kB 0 B
packages/next/dist/pages/getServerSidePostHog.js 1.48 kB 0 B
packages/next/dist/pages/PostHogPageView.js 1.77 kB 0 B
packages/next/dist/pages/PostHogProvider.js 1.58 kB 0 B
packages/next/dist/server.edge.js 795 B 0 B
packages/next/dist/server/captureRequestError.js 5.26 kB 0 B
packages/next/dist/server/clientCache.edge.js 305 B 0 B
packages/next/dist/server/clientCache.js 1.54 kB 0 B
packages/next/dist/server/clientCache.node.js 305 B 0 B
packages/next/dist/server/createPostHog.js 1.44 kB 0 B
packages/next/dist/server/getPostHog.js 3.45 kB 0 B
packages/next/dist/server/onRequestError.js 1.39 kB 0 B
packages/next/dist/server/onRequestError.types.js 59 B 0 B
packages/next/dist/shared/browser.js 195 B 0 B
packages/next/dist/shared/config.js 2.23 kB 0 B
packages/next/dist/shared/constants.js 201 B 0 B
packages/next/dist/shared/cookie.js 540 B 0 B
packages/next/dist/shared/identity.js 2.56 kB 0 B
packages/next/dist/shared/tracing-headers.js 2.18 kB 0 B
packages/nextjs-config/dist/config.js 6.1 kB 0 B
packages/nextjs-config/dist/config.mjs 4.53 kB 0 B
packages/nextjs-config/dist/index.js 2.24 kB 0 B
packages/nextjs-config/dist/index.mjs 30 B 0 B
packages/nextjs-config/dist/strip-sourcemap-********.js 3.63 kB 0 B
packages/nextjs-config/dist/strip-sourcemap-********.mjs 1.77 kB 0 B
packages/nextjs-config/dist/utils.js 2.94 kB 0 B
packages/nextjs-config/dist/utils.mjs 826 B 0 B
packages/node/dist/ai-capture/batching.js 2.61 kB 0 B
packages/node/dist/ai-capture/batching.mjs 1.21 kB 0 B
packages/node/dist/ai-capture/routing.js 1.87 kB 0 B
packages/node/dist/ai-capture/routing.mjs 264 B 0 B
packages/node/dist/capture-v1/config.js 1.5 kB 0 B
packages/node/dist/capture-v1/config.mjs 292 B 0 B
packages/node/dist/capture-v1/errors.js 1.89 kB 0 B
packages/node/dist/capture-v1/errors.mjs 694 B 0 B
packages/node/dist/capture-v1/routing.js 1.68 kB 0 B
packages/node/dist/capture-v1/routing.mjs 279 B 0 B
packages/node/dist/capture-v1/sender.js 11.4 kB 0 B
packages/node/dist/capture-v1/sender.mjs 9.94 kB 0 B
packages/node/dist/capture-v1/transform.js 5.13 kB 0 B
packages/node/dist/capture-v1/transform.mjs 3.65 kB 0 B
packages/node/dist/capture-v1/types.js 603 B 0 B
packages/node/dist/capture-v1/types.mjs 0 B 0 B 🆕
packages/node/dist/client.js 59.5 kB 0 B
packages/node/dist/client.mjs 56.2 kB 0 B
packages/node/dist/entrypoints/index.edge.js 3.85 kB 0 B
packages/node/dist/entrypoints/index.edge.mjs 720 B 0 B
packages/node/dist/entrypoints/index.node.js 6.05 kB 0 B
packages/node/dist/entrypoints/index.node.mjs 1.43 kB 0 B
packages/node/dist/entrypoints/nestjs.js 2.31 kB 0 B
packages/node/dist/entrypoints/nestjs.mjs 42 B 0 B
packages/node/dist/experimental.js 870 B 0 B
packages/node/dist/experimental.mjs 267 B 0 B
packages/node/dist/exports.js 6.75 kB 0 B
packages/node/dist/exports.mjs 582 B 0 B
packages/node/dist/extensions/context/context.js 2.13 kB 0 B
packages/node/dist/extensions/context/context.mjs 863 B 0 B
packages/node/dist/extensions/context/types.js 603 B 0 B
packages/node/dist/extensions/context/types.mjs 0 B 0 B 🆕
packages/node/dist/extensions/error-tracking/autocapture.js 5.19 kB 0 B
packages/node/dist/extensions/error-tracking/autocapture.mjs 3.62 kB 0 B
packages/node/dist/extensions/error-tracking/index.js 4.38 kB 0 B
packages/node/dist/extensions/error-tracking/index.mjs 3.17 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.js 11.6 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs 9.64 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.js 2.78 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.mjs 1.45 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.js 1.97 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.mjs 624 B 0 B
packages/node/dist/extensions/express.js 4.97 kB 0 B
packages/node/dist/extensions/express.mjs 2.78 kB 0 B
packages/node/dist/extensions/feature-flags/cache.js 603 B 0 B
packages/node/dist/extensions/feature-flags/cache.mjs 0 B 0 B 🆕
packages/node/dist/extensions/feature-flags/crypto.js 1.27 kB 0 B
packages/node/dist/extensions/feature-flags/crypto.mjs 63 B 0 B
packages/node/dist/extensions/feature-flags/feature-flags.js 32.2 kB 0 B
packages/node/dist/extensions/feature-flags/feature-flags.mjs 29.8 kB 0 B
packages/node/dist/extensions/nestjs.js 5.62 kB 0 B
packages/node/dist/extensions/nestjs.mjs 3.42 kB 0 B
packages/node/dist/extensions/sentry-integration.js 4.88 kB 0 B
packages/node/dist/extensions/sentry-integration.mjs 3.36 kB 0 B
packages/node/dist/extensions/tracing-headers.js 3.31 kB 0 B
packages/node/dist/extensions/tracing-headers.mjs 1.53 kB 0 B
packages/node/dist/extensions/url-utils.js 2.22 kB 0 B
packages/node/dist/extensions/url-utils.mjs 785 B 0 B
packages/node/dist/feature-flag-evaluations.js 6.12 kB 0 B
packages/node/dist/feature-flag-evaluations.mjs 4.77 kB 0 B
packages/node/dist/gzip.node.js 1.74 kB 0 B
packages/node/dist/gzip.node.mjs 416 B 0 B
packages/node/dist/storage-memory.js 1.52 kB 0 B
packages/node/dist/storage-memory.mjs 297 B 0 B
packages/node/dist/types.js 1.43 kB 0 B
packages/node/dist/types.mjs 224 B 0 B
packages/node/dist/version.js 1.21 kB 0 B
packages/node/dist/version.mjs 46 B 0 B
packages/nuxt/dist/module.mjs 5.92 kB 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagEnabled.js 566 B 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagVariantKey.js 591 B 0 B
packages/nuxt/dist/runtime/composables/usePostHog.js 128 B 0 B
packages/nuxt/dist/runtime/nitro-plugin-v2.js 480 B 0 B
packages/nuxt/dist/runtime/nitro-plugin-v3.js 574 B 0 B
packages/nuxt/dist/runtime/nitro-plugin.js 1.03 kB 0 B
packages/nuxt/dist/runtime/vue-plugin.js 1.13 kB 0 B
packages/openfeature-node-provider/dist/index.js 1.76 kB 0 B
packages/openfeature-node-provider/dist/index.mjs 190 B 0 B
packages/openfeature-node-provider/dist/mapping.js 5.32 kB 0 B
packages/openfeature-node-provider/dist/mapping.mjs 3.21 kB 0 B
packages/openfeature-node-provider/dist/provider.js 3.99 kB 0 B
packages/openfeature-node-provider/dist/provider.mjs 2.6 kB 0 B
packages/openfeature-web-provider/dist/index.js 1.75 kB 0 B
packages/openfeature-web-provider/dist/index.mjs 184 B 0 B
packages/openfeature-web-provider/dist/mapping.js 5.29 kB 0 B
packages/openfeature-web-provider/dist/mapping.mjs 3.18 kB 0 B
packages/openfeature-web-provider/dist/provider.js 4.41 kB 0 B
packages/openfeature-web-provider/dist/provider.mjs 3.06 kB 0 B
packages/plugin-utils/dist/chunk-ids.js 3.86 kB 0 B
packages/plugin-utils/dist/chunk-ids.mjs 2.05 kB 0 B
packages/plugin-utils/dist/cli.js 4.37 kB 0 B
packages/plugin-utils/dist/cli.mjs 2.72 kB 0 B
packages/plugin-utils/dist/config.js 3.5 kB 0 B
packages/plugin-utils/dist/config.mjs 2.26 kB 0 B
packages/plugin-utils/dist/index.js 4.98 kB 0 B
packages/plugin-utils/dist/index.mjs 250 B 0 B
packages/plugin-utils/dist/spawn-local.js 3.08 kB 0 B
packages/plugin-utils/dist/spawn-local.mjs 1.66 kB 0 B
packages/plugin-utils/dist/utils.js 3.27 kB 0 B
packages/plugin-utils/dist/utils.mjs 1.3 kB 0 B
packages/react-native/dist/autocapture.js 8.31 kB 0 B
packages/react-native/dist/error-tracking/index.js 9.97 kB 0 B
packages/react-native/dist/error-tracking/utils.js 2.58 kB 0 B
packages/react-native/dist/frameworks/wix-navigation.js 1.3 kB 0 B
packages/react-native/dist/hooks/useFeatureFlag.js 1.86 kB 0 B
packages/react-native/dist/hooks/useFeatureFlagResult.js 983 B 0 B
packages/react-native/dist/hooks/useFeatureFlags.js 941 B 0 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.45 kB 0 B
packages/react-native/dist/hooks/usePostHog.js 544 B 0 B
packages/react-native/dist/hooks/utils.js 988 B 0 B
packages/react-native/dist/index.js 4.33 kB 0 B
packages/react-native/dist/logs-********.js 3.66 kB 0 B
packages/react-native/dist/native-deps.js 8.73 kB 0 B
packages/react-native/dist/optional/OptionalAsyncStorage.js 299 B 0 B
packages/react-native/dist/optional/OptionalExpoApplication.js 377 B 0 B
packages/react-native/dist/optional/OptionalExpoDevice.js 347 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 386 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystemLegacy.js 423 B 0 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 383 B 0 B
packages/react-native/dist/optional/OptionalPlugin.js 891 B 0 B
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 303 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 443 B 0 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 644 B 0 B
packages/react-native/dist/optional/OptionalReactNativeSvg.js 872 B 0 B
packages/react-native/dist/posthog-rn.js 67.4 kB 0 B
packages/react-native/dist/PostHogContext.js 329 B 0 B
packages/react-native/dist/PostHogErrorBoundary.js 3.19 kB 0 B
packages/react-native/dist/PostHogMaskView.js 1.68 kB 0 B
packages/react-native/dist/PostHogProvider.js 6 kB 0 B
packages/react-native/dist/storage.js 5.76 kB 0 B
packages/react-native/dist/surveys/components/BottomSection.js 1.51 kB 0 B
packages/react-native/dist/surveys/components/Cancel.js 1.1 kB 0 B
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.76 kB 0 B
packages/react-native/dist/surveys/components/IntroMessage.js 1.65 kB 0 B
packages/react-native/dist/surveys/components/QuestionHeader.js 1.47 kB 0 B
packages/react-native/dist/surveys/components/QuestionTypes.js 14 kB 0 B
packages/react-native/dist/surveys/components/SurveyModal.js 7.24 kB 0 B
packages/react-native/dist/surveys/components/Surveys.js 6.58 kB 0 B
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 2.69 kB 0 B
packages/react-native/dist/surveys/icons.js 10 kB 0 B
packages/react-native/dist/surveys/index.js 600 B 0 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 6.73 kB 0 B
packages/react-native/dist/surveys/safeStyleSheet.js 448 B 0 B
packages/react-native/dist/surveys/survey-translations.js 1.11 kB 0 B
packages/react-native/dist/surveys/surveys-utils.js 11.5 kB 0 B
packages/react-native/dist/surveys/useActivatedSurveys.js 3.68 kB 0 B
packages/react-native/dist/surveys/useSurveyStorage.js 2.48 kB 0 B
packages/react-native/dist/tooling/expoconfig.js 23.6 kB 0 B
packages/react-native/dist/tooling/metroconfig.js 2.32 kB 0 B
packages/react-native/dist/tooling/posthogMetroSerializer.js 7.74 kB 0 B
packages/react-native/dist/tooling/utils.js 4.2 kB 0 B
packages/react-native/dist/tooling/vendor/expo/expoconfig.js 70 B 0 B
packages/react-native/dist/tooling/vendor/metro/countLines.js 237 B 0 B
packages/react-native/dist/tooling/vendor/metro/utils.js 3.51 kB 0 B
packages/react-native/dist/types.js 70 B 0 B
packages/react-native/dist/utils.js 1.3 kB 0 B
packages/react-native/dist/version.js 130 B 0 B
packages/react/dist/esm/index.js 22.5 kB 0 B
packages/react/dist/esm/slim/index.js 18.9 kB 0 B
packages/react/dist/esm/surveys/index.js 4.75 kB 0 B
packages/react/dist/umd/index.js 25.9 kB 0 B
packages/react/dist/umd/slim/index.js 21.8 kB 0 B
packages/react/dist/umd/surveys/index.js 5.52 kB 0 B
packages/rollup-plugin/dist/index.js 7.6 kB 0 B
packages/rrweb/all/dist/rrweb-all.cjs 705 kB 0 B
packages/rrweb/all/dist/rrweb-all.js 705 kB 0 B
packages/rrweb/all/dist/rrweb-all.umd.cjs 708 kB 0 B
packages/rrweb/all/dist/rrweb-all.umd.min.cjs 328 kB 0 B
packages/rrweb/packer/dist/base-********.cjs 18.3 kB 0 B
packages/rrweb/packer/dist/base-********.js 18.2 kB 0 B
packages/rrweb/packer/dist/base-********.umd.cjs 18.7 kB 0 B
packages/rrweb/packer/dist/base-********.umd.min.cjs 9.5 kB 0 B
packages/rrweb/packer/dist/pack.cjs 347 B 0 B
packages/rrweb/packer/dist/pack.js 285 B 0 B
packages/rrweb/packer/dist/pack.umd.cjs 1.63 kB 0 B
packages/rrweb/packer/dist/pack.umd.min.cjs 1.11 kB 0 B
packages/rrweb/packer/dist/packer.cjs 257 B 0 B
packages/rrweb/packer/dist/packer.js 136 B 0 B
packages/rrweb/packer/dist/packer.umd.cjs 662 B 0 B
packages/rrweb/packer/dist/packer.umd.min.cjs 626 B 0 B
packages/rrweb/packer/dist/unpack.cjs 769 B 0 B
packages/rrweb/packer/dist/unpack.js 702 B 0 B
packages/rrweb/packer/dist/unpack.umd.cjs 1.17 kB 0 B
packages/rrweb/packer/dist/unpack.umd.min.cjs 955 B 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.cjs 37.6 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.js 37.5 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.cjs 38 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.min.cjs 22.2 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.cjs 34.3 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.js 34.2 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.cjs 34.7 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.min.cjs 20.5 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.cjs 15.8 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.js 15.7 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.cjs 16.3 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.min.cjs 7.66 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.cjs 5.01 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.js 4.9 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.cjs 5.44 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.min.cjs 2.64 kB 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.cjs 681 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.js 548 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.cjs 1.12 kB 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.min.cjs 829 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.cjs 933 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.js 820 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.cjs 1.37 kB 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.min.cjs 968 B 0 B
packages/rrweb/record/dist/rrweb-record.cjs 234 kB 0 B
packages/rrweb/record/dist/rrweb-record.js 233 kB 0 B
packages/rrweb/record/dist/rrweb-record.umd.cjs 234 kB 0 B
packages/rrweb/record/dist/rrweb-record.umd.min.cjs 107 kB 0 B
packages/rrweb/replay/dist/rrweb-replay.cjs 476 kB 0 B
packages/rrweb/replay/dist/rrweb-replay.js 476 kB 0 B
packages/rrweb/replay/dist/rrweb-replay.umd.cjs 479 kB 0 B
packages/rrweb/replay/dist/rrweb-replay.umd.min.cjs 225 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.cjs 160 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.js 160 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.cjs 162 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.min.cjs 74.9 kB 0 B
packages/rrweb/rrdom/dist/rrdom.cjs 186 kB 0 B
packages/rrweb/rrdom/dist/rrdom.js 185 kB 0 B
packages/rrweb/rrdom/dist/rrdom.umd.cjs 187 kB 0 B
packages/rrweb/rrdom/dist/rrdom.umd.min.cjs 85.5 kB 0 B
packages/rrweb/rrweb-snapshot/dist/record.cjs 39 kB 0 B
packages/rrweb/rrweb-snapshot/dist/record.js 37.3 kB 0 B
packages/rrweb/rrweb-snapshot/dist/record.umd.cjs 83.2 kB 0 B
packages/rrweb/rrweb-snapshot/dist/record.umd.min.cjs 37.4 kB 0 B
packages/rrweb/rrweb-snapshot/dist/replay.cjs 149 kB 0 B
packages/rrweb/rrweb-snapshot/dist/replay.js 149 kB 0 B
packages/rrweb/rrweb-snapshot/dist/replay.umd.cjs 194 kB 0 B
packages/rrweb/rrweb-snapshot/dist/replay.umd.min.cjs 86.2 kB 0 B
packages/rrweb/rrweb-snapshot/dist/rrweb-********.cjs 3.95 kB 0 B
packages/rrweb/rrweb-snapshot/dist/rrweb-********.js 2.32 kB 0 B
packages/rrweb/rrweb-snapshot/dist/rrweb-********.umd.cjs 261 kB 0 B
packages/rrweb/rrweb-snapshot/dist/rrweb-********.umd.min.cjs 109 kB 0 B
packages/rrweb/rrweb-snapshot/dist/types-********.cjs 37.6 kB 0 B
packages/rrweb/rrweb-snapshot/dist/types-********.js 36.5 kB 0 B
packages/rrweb/rrweb-snapshot/dist/types-********.umd.cjs 39 kB 0 B
packages/rrweb/rrweb-snapshot/dist/types-********.umd.min.cjs 17.3 kB 0 B
packages/rrweb/rrweb/dist/rrweb.cjs 689 kB 0 B
packages/rrweb/rrweb/dist/rrweb.js 689 kB 0 B
packages/rrweb/rrweb/dist/rrweb.umd.cjs 689 kB 0 B
packages/rrweb/rrweb/dist/rrweb.umd.min.cjs 318 kB 0 B
packages/rrweb/types/dist/rrweb-types.cjs 5.75 kB 0 B
packages/rrweb/types/dist/rrweb-types.js 5.46 kB 0 B
packages/rrweb/types/dist/rrweb-types.umd.cjs 6.16 kB 0 B
packages/rrweb/types/dist/rrweb-types.umd.min.cjs 2.86 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.cjs 7.76 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.js 7.3 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.umd.cjs 8.24 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.umd.min.cjs 4.09 kB 0 B
packages/types/dist/capture-log.js 603 B 0 B
packages/types/dist/capture-log.mjs 0 B 0 B 🆕
packages/types/dist/capture-metric.js 1.37 kB 0 B
packages/types/dist/capture-metric.mjs 93 B 0 B
packages/types/dist/capture.js 603 B 0 B
packages/types/dist/capture.mjs 0 B 0 B 🆕
packages/types/dist/common.js 603 B 0 B
packages/types/dist/common.mjs 0 B 0 B 🆕
packages/types/dist/feature-flags.js 603 B 0 B
packages/types/dist/feature-flags.mjs 0 B 0 B 🆕
packages/types/dist/index.js 1.45 kB 0 B
packages/types/dist/index.mjs 122 B 0 B
packages/types/dist/posthog-config.js 603 B 0 B
packages/types/dist/posthog-config.mjs 0 B 0 B 🆕
packages/types/dist/posthog.js 603 B 0 B
packages/types/dist/posthog.mjs 0 B 0 B 🆕
packages/types/dist/request.js 603 B 0 B
packages/types/dist/request.mjs 0 B 0 B 🆕
packages/types/dist/segment.js 603 B 0 B
packages/types/dist/segment.mjs 0 B 0 B 🆕
packages/types/dist/session-recording.js 603 B 0 B
packages/types/dist/session-recording.mjs 0 B 0 B 🆕
packages/types/dist/survey.js 603 B 0 B
packages/types/dist/survey.mjs 0 B 0 B 🆕
packages/types/dist/toolbar.js 603 B 0 B
packages/types/dist/toolbar.mjs 0 B 0 B 🆕
packages/types/dist/tree-shakeable.js 603 B 0 B
packages/types/dist/tree-shakeable.mjs 0 B 0 B 🆕
packages/web/dist/index.cjs 11.2 kB 0 B
packages/web/dist/index.mjs 11.1 kB 0 B
packages/webpack-plugin/dist/config.js 1.47 kB 0 B
packages/webpack-plugin/dist/config.mjs 480 B 0 B
packages/webpack-plugin/dist/index.js 7.39 kB 0 B
packages/webpack-plugin/dist/index.mjs 3.58 kB 0 B
tooling/changelog/dist/index.js 3.31 kB 0 B
tooling/rollup-utils/dist/index.js 1.17 kB 0 B

compressed-size-action

The versioning check requires a patch bump for a `fix:` title, and this is a bug fix, so the changeset drops from minor to patch. The public API reference file picks up the reworded `capture_pageview` doc comment.

Generated-By: PostHog Desktop
Task-Id: ca7d1e51-64ae-42fc-9c7c-20c2eb623cf9
@posthog

posthog Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

PostHog Review alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review

Found 2 must fix, 2 should fix, 2 consider.

'@posthog/types': minor
---

`capture_pageview: 'history_change'` now captures a `$pageview` when a single-page-app navigation changes the query string or the hash, not only the path. Before this change, navigation to search results, filters, pagination, and tab state captured no pageview, so these apps undercounted pageviews. `disable_capture_url_hashes` still suppresses hash-only changes. To keep the old behaviour, set `capture_pageview: { path: true }`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

State when modern defaults disable hash capture

consider documentation

Why we think it's a valid issue
  • Checked: the default resolution in packages/browser/src/posthog-core.ts, the hash gate in packages/browser/src/extensions/history-autocapture.ts, the doc comment the PR edits in packages/types/src/posthog-config.ts, and the changeset text itself.
  • Found: packages/browser/src/posthog-core.ts:251 sets disable_capture_url_hashes: !!(defaults && defaults >= '2026-06-25'), and line 244 sets capture_pageview: 'history_change' for defaults >= '2025-05-24'. A project on '2026-06-25' defaults therefore gets 'history_change' and hash stripping at the same time.
  • Found: packages/browser/src/extensions/history-autocapture.ts:127-129 returns false from _shouldCaptureHashChanges in that state, so _hasLocationChanged (line 139) ignores hash-only navigation and monitorHistoryChanges (line 73) never adds the hashchange listener. The test at packages/browser/src/__tests__/extensions/history-autocapture.test.ts:214-222 confirms the silence.
  • Found: the changeset (line 6) and the doc comment (packages/types/src/posthog-config.ts:1371-1372) both name disable_capture_url_hashes, but neither says the SDK turns it on from '2026-06-25' defaults. So the premise of the finding is correct: the note promises hash pageviews to a cohort that will not receive them.
  • Impact: the omission is real but small. The note already names the exact option that suppresses hash capture, and a project on '2026-06-25' defaults opted into hash stripping through a change that its own release note called a breaking change for hash-routing apps. Such a project already collapses hash routes in $current_url, so no hash-only pageview is the consistent result, not a surprise. The added clause improves the note; its absence misleads few readers.
  • Priority: lowered to consider. No code behavior is wrong, the escape hatch is already named in the same paragraph, and the fix is one clause of release-note text.
Issue description

The release note names disable_capture_url_hashes, but it does not state when the SDK enables that option automatically. Users with defaults: '2026-06-25' or later still receive no hash-only pageviews.

Suggested fix

State that modern defaults enable disable_capture_url_hashes. Tell users to set disable_capture_url_hashes: false if they want hash-only navigation pageviews.

Prompt to fix with AI (copy-paste)
## Context
@.changeset/history-change-captures-search-and-hash.md#L6

<issue_description>
The release note names `disable_capture_url_hashes`, but it does not state when the SDK enables that option automatically. Users with `defaults: '2026-06-25'` or later still receive no hash-only pageviews.
</issue_description>

<issue_validation>
- **Checked:** the default resolution in `packages/browser/src/posthog-core.ts`, the hash gate in `packages/browser/src/extensions/history-autocapture.ts`, the doc comment the PR edits in `packages/types/src/posthog-config.ts`, and the changeset text itself.
- **Found:** `packages/browser/src/posthog-core.ts:251` sets `disable_capture_url_hashes: !!(defaults && defaults >= '2026-06-25')`, and line 244 sets `capture_pageview: 'history_change'` for `defaults >= '2025-05-24'`. A project on `'2026-06-25'` defaults therefore gets `'history_change'` and hash stripping at the same time.
- **Found:** `packages/browser/src/extensions/history-autocapture.ts:127-129` returns false from `_shouldCaptureHashChanges` in that state, so `_hasLocationChanged` (line 139) ignores hash-only navigation and `monitorHistoryChanges` (line 73) never adds the hashchange listener. The test at `packages/browser/src/__tests__/extensions/history-autocapture.test.ts:214-222` confirms the silence.
- **Found:** the changeset (line 6) and the doc comment (`packages/types/src/posthog-config.ts:1371-1372`) both name `disable_capture_url_hashes`, but neither says the SDK turns it on from `'2026-06-25'` defaults. So the premise of the finding is correct: the note promises hash pageviews to a cohort that will not receive them.
- **Impact:** the omission is real but small. The note already names the exact option that suppresses hash capture, and a project on `'2026-06-25'` defaults opted into hash stripping through a change that its own release note called a breaking change for hash-routing apps. Such a project already collapses hash routes in `$current_url`, so no hash-only pageview is the consistent result, not a surprise. The added clause improves the note; its absence misleads few readers.
- **Priority:** lowered to `consider`. No code behavior is wrong, the escape hatch is already named in the same paragraph, and the fix is one clause of release-note text.
</issue_validation>

## Task
Investigate the issue and solve it

<potential_solution>
State that modern defaults enable `disable_capture_url_hashes`. Tell users to set `disable_capture_url_hashes: false` if they want hash-only navigation pageviews.
</potential_solution>


if (capturePageview === 'history_change') {
return { path: true }
return { path: true, search: true, hash: true }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Startup query changes can send duplicate pageviews

consider bug

Why we think it's a valid issue
  • Checked: the init order in packages/browser/src/posthog-core.ts, every reference to _initialPageviewCaptured, the $pageview capture sites, and the capture path in packages/browser/src/extensions/history-autocapture.ts.
  • Found: the race window is real in the default configuration. posthog-core.ts:902 calls _initExtensions synchronously, so HistoryAutocapture snapshots _lastLocation (history-autocapture.ts:25) and patches pushState/replaceState (history-autocapture.ts:69-70, 98) before _loaded() runs at posthog-core.ts:1018. _loaded() then defers the initial pageview with setTimeout(..., 1) at posthog-core.ts:1293-1301. Any history call in the same task, or in a microtask, runs before that timer.
  • Found: the two capture paths share no state. _initialPageviewCaptured appears only at posthog-core.ts:463, 661, and 4670-4671, so the history capture at history-autocapture.ts:151-152 never sets it. The $pageview handling in capture() (posthog-core.ts:1902, 1911) adds properties but does not deduplicate. Two $pageview events therefore reach the queue with the same $current_url.
  • Found: the defect class already exists on main. Before this PR 'history_change' expanded to { path: true }, so a bootstrap redirect that changes the path (for example / to /login) already produced the same pair of events, and the granular { path, search, hash } config was already public. Line 121 widens the trigger to query-only and hash-only startup changes; it does not create the coordination gap.
  • Impact: confirmed duplicate pageviews, but only for a narrow window. The URL mutation must happen inside the init task or a microtask, before the 1 ms timer. The OAuth cleanup named in the finding usually runs after an await, so it lands after the initial pageview and then reports a genuinely different URL, which is the intended new behavior and not a duplicate. Hash-routing apps on defaults of '2026-06-25' or later are also unaffected, because disable_capture_url_hashes suppresses the hash capture (posthog-core.ts:251, history-autocapture.ts:127-129).
  • Priority: lowered to consider. The mechanism is verified, but the trigger is a sub-millisecond startup window, the same double capture already occurs on main for the far more common path redirect, and the suggested fix redesigns initial-pageview coordination well beyond this one-line change.
Issue description

Line 121 enables search and hash captures as soon as HistoryAutocapture initializes. PostHog initializes this extension before config.loaded, but _loaded() defers the initial pageview with a timer. If startup code changes only the query or hash, the history hook sends a pageview for the final URL. The timer then sends another pageview for that same URL because the history capture does not set _initialPageviewCaptured. This creates duplicate pageviews during common router or OAuth URL normalization.

Suggested fix

Coordinate history capture with the initial pageview state. Before the initial pageview fires, make a history capture satisfy it or suppress the history capture. Add an integration test that changes the query and hash during loaded, advances the timer, and expects exactly one pageview.

Prompt to fix with AI (copy-paste)
## Context
@packages/browser/src/extensions/history-autocapture.ts#L121

<issue_description>
Line 121 enables search and hash captures as soon as `HistoryAutocapture` initializes. PostHog initializes this extension before `config.loaded`, but `_loaded()` defers the initial pageview with a timer. If startup code changes only the query or hash, the history hook sends a pageview for the final URL. The timer then sends another pageview for that same URL because the history capture does not set `_initialPageviewCaptured`. This creates duplicate pageviews during common router or OAuth URL normalization.
</issue_description>

<issue_validation>
- **Checked:** the init order in `packages/browser/src/posthog-core.ts`, every reference to `_initialPageviewCaptured`, the `$pageview` capture sites, and the capture path in `packages/browser/src/extensions/history-autocapture.ts`.
- **Found:** the race window is real in the default configuration. `posthog-core.ts:902` calls `_initExtensions` synchronously, so `HistoryAutocapture` snapshots `_lastLocation` (`history-autocapture.ts:25`) and patches `pushState`/`replaceState` (`history-autocapture.ts:69-70, 98`) before `_loaded()` runs at `posthog-core.ts:1018`. `_loaded()` then defers the initial pageview with `setTimeout(..., 1)` at `posthog-core.ts:1293-1301`. Any history call in the same task, or in a microtask, runs before that timer.
- **Found:** the two capture paths share no state. `_initialPageviewCaptured` appears only at `posthog-core.ts:463`, `661`, and `4670-4671`, so the history capture at `history-autocapture.ts:151-152` never sets it. The `$pageview` handling in `capture()` (`posthog-core.ts:1902`, `1911`) adds properties but does not deduplicate. Two `$pageview` events therefore reach the queue with the same `$current_url`.
- **Found:** the defect class already exists on `main`. Before this PR `'history_change'` expanded to `{ path: true }`, so a bootstrap redirect that changes the path (for example `/` to `/login`) already produced the same pair of events, and the granular `{ path, search, hash }` config was already public. Line 121 widens the trigger to query-only and hash-only startup changes; it does not create the coordination gap.
- **Impact:** confirmed duplicate pageviews, but only for a narrow window. The URL mutation must happen inside the init task or a microtask, before the 1 ms timer. The OAuth cleanup named in the finding usually runs after an `await`, so it lands after the initial pageview and then reports a genuinely different URL, which is the intended new behavior and not a duplicate. Hash-routing apps on `defaults` of `'2026-06-25'` or later are also unaffected, because `disable_capture_url_hashes` suppresses the hash capture (`posthog-core.ts:251`, `history-autocapture.ts:127-129`).
- **Priority:** lowered to `consider`. The mechanism is verified, but the trigger is a sub-millisecond startup window, the same double capture already occurs on `main` for the far more common path redirect, and the suggested fix redesigns initial-pageview coordination well beyond this one-line change.
</issue_validation>

## Task
Investigate the issue and solve it

<potential_solution>
Coordinate history capture with the initial pageview state. Before the initial pageview fires, make a history capture satisfy it or suppress the history capture. Add an integration test that changes the query and hash during `loaded`, advances the timer, and expects exactly one pageview.
</potential_solution>

Comment on lines +1371 to +1372
* - `'history_change'`: Capture the initial pageview and pageviews when the path, query string, or hash changes.
* `disable_capture_url_hashes` still suppresses hash-only changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regenerate the public API reference

must_fix documentation

Why we think it's a valid issue
  • Checked: the committed reference JSON, the source of the doc text, the generate-references job in .github/workflows/library-ci.yml, the scripts/check-public-api.js gate it calls, and .github/workflows/generated-files-notice.yml.
  • Found: the committed artifact is stale. packages/browser/references/posthog-js-references-latest.json still carries the pre-PR sentence "Capture the initial pageview and pageviews when the pathname changes", next to the unchanged bullet "An object: Capture the initial pageview and pageviews when any selected URL component changes" — the same doc block the PR edits at packages/types/src/posthog-config.ts:1369-1373. A grep across packages/**/*.ts finds the old wording in no source file, so regeneration will rewrite that string.
  • Found: the check runs on this PR and fails deterministically. .github/workflows/library-ci.yml:3-4 triggers on every pull_request, and the generate-references job at line 474 runs pnpm generate-references then pnpm check:public-api with no needs or if gate. scripts/check-public-api.js:10-56 runs git status --porcelain over packages/browser/references/posthog-js-references-latest.json and calls process.exit(1) on any diff, with the message "Run pnpm generate-references and commit the updated latest reference files." The suggested action matches the repo's own instruction.
  • Found: the working tree shows the file clean, so the stale copy is what the PR carries. The PR touches 4 files and none is a reference file.
  • Found: .github/workflows/generated-files-notice.yml does not contradict this. It only prints a non-blocking warning when a human PR edits generated paths, and it states that it "does not fail the workflow and does not block merge".
  • Impact: confirmed red CI job on this PR, plus a published API reference that states the superseded 'history_change' contract for consumers who read the reference rather than the source.
  • Priority: raised to must_fix. The failure is deterministic and the author must land the regenerated file before this PR can merge, which is a harder blocker than should_fix implies.
Issue description

The checked-in browser API reference still says that history_change watches only the pathname. CI regenerates this reference and fails when it finds the difference. The published reference also retains the old contract.

Suggested fix

Run pnpm generate-references. Commit the updated packages/browser/references/posthog-js-references-latest.json.

Prompt to fix with AI (copy-paste)
## Context
@packages/types/src/posthog-config.ts#L1371-1372

<issue_description>
The checked-in browser API reference still says that `history_change` watches only the pathname. CI regenerates this reference and fails when it finds the difference. The published reference also retains the old contract.
</issue_description>

<issue_validation>
- **Checked:** the committed reference JSON, the source of the doc text, the `generate-references` job in `.github/workflows/library-ci.yml`, the `scripts/check-public-api.js` gate it calls, and `.github/workflows/generated-files-notice.yml`.
- **Found:** the committed artifact is stale. `packages/browser/references/posthog-js-references-latest.json` still carries the pre-PR sentence "Capture the initial pageview and pageviews when the pathname changes", next to the unchanged bullet "An object: Capture the initial pageview and pageviews when any selected URL component changes" — the same doc block the PR edits at `packages/types/src/posthog-config.ts:1369-1373`. A grep across `packages/**/*.ts` finds the old wording in no source file, so regeneration will rewrite that string.
- **Found:** the check runs on this PR and fails deterministically. `.github/workflows/library-ci.yml:3-4` triggers on every `pull_request`, and the `generate-references` job at line 474 runs `pnpm generate-references` then `pnpm check:public-api` with no `needs` or `if` gate. `scripts/check-public-api.js:10-56` runs `git status --porcelain` over `packages/browser/references/posthog-js-references-latest.json` and calls `process.exit(1)` on any diff, with the message "Run `pnpm generate-references` and commit the updated latest reference files." The suggested action matches the repo's own instruction.
- **Found:** the working tree shows the file clean, so the stale copy is what the PR carries. The PR touches 4 files and none is a reference file.
- **Found:** `.github/workflows/generated-files-notice.yml` does not contradict this. It only prints a non-blocking warning when a human PR edits generated paths, and it states that it "does not fail the workflow and does not block merge".
- **Impact:** confirmed red CI job on this PR, plus a published API reference that states the superseded `'history_change'` contract for consumers who read the reference rather than the source.
- **Priority:** raised to `must_fix`. The failure is deterministic and the author must land the regenerated file before this PR can merge, which is a harder blocker than `should_fix` implies.
</issue_validation>

## Task
Investigate the issue and solve it

<potential_solution>
Run `pnpm generate-references`. Commit the updated `packages/browser/references/posthog-js-references-latest.json`.
</potential_solution>

Comment on lines +1371 to +1372
* - `'history_change'`: Capture the initial pageview and pageviews when the path, query string, or hash changes.
* `disable_capture_url_hashes` still suppresses hash-only changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the JavaScript SDK config guide

should_fix documentation

Why we think it's a valid issue
  • Checked: the live public guide at posthog.com/docs/libraries/js/config, the generated reference artifact in this repo, and the repo's own convention comment about website docs.
  • Found: the premise holds. The published config guide describes the option as "If the special string history_change is provided, PostHog will capture pageviews based on path changes by listening to the browser's history API which is useful for single page apps." It names no query string, search, or hash component. After this PR that sentence states the wrong contract, not merely an incomplete one.
  • Found: the guide text is hand-written, so no generation step fixes it. Its wording ("path changes", "useful for single page apps") differs from the api-extractor output in packages/browser/references/posthog-js-references-latest.json, which uses "Capture the initial pageview and pageviews when the pathname changes". The two artifacts are separate: regenerating the reference JSON leaves the guide unchanged, so this does not duplicate the stale-reference finding.
  • Found: the repo asks contributors to do this. packages/browser/src/posthog-core.ts:255-256 states "Remember to update types.ts when changing a default value / to guarantee documentation is up to date, make sure to also update our website docs." The request follows a house rule rather than inventing one.
  • Impact: confirmed. This PR raises $pageview volume for every project on 'history_change', and the guide customers read to explain that number still documents path-only capture. A reader cannot connect the volume change to the SDK behavior from the current text.
  • Impact: the fix lands in the posthog.com repository, so it cannot block this PR and reads as a follow-up. I verified the rendered page, not the exact source path contents/docs/libraries/js/config.mdx, so the author should confirm the file name when they make that change.
Issue description

The public JavaScript config guide still says that history_change captures path changes only. Users who read that guide will expect the old behavior and event volume.

Suggested fix

Update contents/docs/libraries/js/config.mdx in the posthog.com repository. List path, query string, and hash changes. Also explain the disable_capture_url_hashes interaction.

Prompt to fix with AI (copy-paste)
## Context
@packages/types/src/posthog-config.ts#L1371-1372

<issue_description>
The public JavaScript config guide still says that `history_change` captures path changes only. Users who read that guide will expect the old behavior and event volume.
</issue_description>

<issue_validation>
- **Checked:** the live public guide at `posthog.com/docs/libraries/js/config`, the generated reference artifact in this repo, and the repo's own convention comment about website docs.
- **Found:** the premise holds. The published config guide describes the option as "If the special string history_change is provided, PostHog will capture pageviews based on **path changes** by listening to the browser's history API which is useful for single page apps." It names no query string, search, or hash component. After this PR that sentence states the wrong contract, not merely an incomplete one.
- **Found:** the guide text is hand-written, so no generation step fixes it. Its wording ("path changes", "useful for single page apps") differs from the api-extractor output in `packages/browser/references/posthog-js-references-latest.json`, which uses "Capture the initial pageview and pageviews when the pathname changes". The two artifacts are separate: regenerating the reference JSON leaves the guide unchanged, so this does not duplicate the stale-reference finding.
- **Found:** the repo asks contributors to do this. `packages/browser/src/posthog-core.ts:255-256` states "Remember to update `types.ts` when changing a default value / to guarantee documentation is up to date, make sure to also update our website docs." The request follows a house rule rather than inventing one.
- **Impact:** confirmed. This PR raises `$pageview` volume for every project on `'history_change'`, and the guide customers read to explain that number still documents path-only capture. A reader cannot connect the volume change to the SDK behavior from the current text.
- **Impact:** the fix lands in the `posthog.com` repository, so it cannot block this PR and reads as a follow-up. I verified the rendered page, not the exact source path `contents/docs/libraries/js/config.mdx`, so the author should confirm the file name when they make that change.
</issue_validation>

## Task
Investigate the issue and solve it

<potential_solution>
Update `contents/docs/libraries/js/config.mdx` in the `posthog.com` repository. List path, query string, and hash changes. Also explain the `disable_capture_url_hashes` interaction.
</potential_solution>


if (capturePageview === 'history_change') {
return { path: true }
return { path: true, search: true, hash: true }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preserve the pinned history_change contract

must_fix compatibility

Why we think it's a valid issue
  • Checked: the defaults contract in packages/types/src/posthog-config.ts, the date-gated default map in packages/browser/src/posthog-core.ts, the runtime expansion in history-autocapture.ts, the shipped CHANGELOG history, and the versioned reference snapshots in packages/browser/references/.
  • Found: a pinned defaults date cannot freeze this behavior. posthog-core.ts:244 pins only the value 'history_change'; history-autocapture.ts:117-125 expands that string at runtime with no reference to defaults. Every project pinned from '2025-05-24' through '2026-08-30' therefore changes behavior on a minor upgrade with no config edit. posthog-config.ts:1737-1739 documents defaults as "Configuration defaults for breaking changes. When set to a specific date, enables new default behaviors that were introduced on that date" — the mechanism this change routes around.
  • Found: the team made the opposite decision nine days ago and told customers so. packages/browser/CHANGELOG.md:287 (release 1.418.13, PR feat(browser): add granular SPA pageview options #4418, dated 2026-08-24) shipped the granular { path, search, hash } object and states "The existing 'history_change' option continues to capture pathname changes." The object form was published as the opt-in for search and hash. This PR reverses that promise in the next minor.
  • Found: direct precedent for gating. posthog-core.ts:251 gates disable_capture_url_hashes at '2026-06-25', and packages/core/CHANGELOG.md:508 calls that URL-capture change "a breaking behavior change" that is "disabled by default for backwards compatibility." Eight dated revisions exist, so adding one is the idiomatic and cheap path the suggestion proposes.
  • Found: one point cuts the other way, and the author should weigh it. Before 1.418.13 the reference described 'history_change' as "Capture pageviews on the initial page load and on history API changes (pushState, replaceState, popstate)", which supports reading path-only capture as an under-implementation rather than a promise. The explicit pathname wording is recent; the path-only behavior is about a year old.
  • Impact: confirmed contract break for existing installs. Extra $pageview events land in every SPA on 'history_change' after a minor bump, which shifts pageview counts, funnel and conversion baselines, and billable event volume without any customer action. The changeset marks posthog-js as minor, and the PR leaves the backwards-compatibility checklist item unticked.
Issue description

This mapping changes the documented meaning of the public history_change option. It also changes every pinned defaults snapshot from 2025-05-24 onward. Existing apps will send new query-only and hash-only $pageview events after a minor upgrade. This can change analytics, billing volume, and captured URL data without a configuration change.

Suggested fix

Keep history_change mapped to { path: true }. Add a new dated defaults revision that uses { path: true, search: true, hash: true }. Customers can also opt in with the existing object form. Update the type comment and changeset to explain the gated behavior.

Prompt to fix with AI (copy-paste)
## Context
@packages/browser/src/extensions/history-autocapture.ts#L121

<issue_description>
This mapping changes the documented meaning of the public `history_change` option. It also changes every pinned defaults snapshot from `2025-05-24` onward. Existing apps will send new query-only and hash-only `$pageview` events after a minor upgrade. This can change analytics, billing volume, and captured URL data without a configuration change.
</issue_description>

<issue_validation>
- **Checked:** the `defaults` contract in `packages/types/src/posthog-config.ts`, the date-gated default map in `packages/browser/src/posthog-core.ts`, the runtime expansion in `history-autocapture.ts`, the shipped `CHANGELOG` history, and the versioned reference snapshots in `packages/browser/references/`.
- **Found:** a pinned `defaults` date cannot freeze this behavior. `posthog-core.ts:244` pins only the *value* `'history_change'`; `history-autocapture.ts:117-125` expands that string at runtime with no reference to `defaults`. Every project pinned from `'2025-05-24'` through `'2026-08-30'` therefore changes behavior on a minor upgrade with no config edit. `posthog-config.ts:1737-1739` documents `defaults` as "Configuration defaults for **breaking changes**. When set to a specific date, enables new default behaviors that were introduced on that date" — the mechanism this change routes around.
- **Found:** the team made the opposite decision nine days ago and told customers so. `packages/browser/CHANGELOG.md:287` (release 1.418.13, PR #4418, dated 2026-08-24) shipped the granular `{ path, search, hash }` object and states "The existing `'history_change'` option continues to capture pathname changes." The object form was published as the opt-in for search and hash. This PR reverses that promise in the next minor.
- **Found:** direct precedent for gating. `posthog-core.ts:251` gates `disable_capture_url_hashes` at `'2026-06-25'`, and `packages/core/CHANGELOG.md:508` calls that URL-capture change "a breaking behavior change" that is "disabled by default for backwards compatibility." Eight dated revisions exist, so adding one is the idiomatic and cheap path the suggestion proposes.
- **Found:** one point cuts the other way, and the author should weigh it. Before 1.418.13 the reference described `'history_change'` as "Capture pageviews on the initial page load and on history API changes (pushState, replaceState, popstate)", which supports reading path-only capture as an under-implementation rather than a promise. The explicit pathname wording is recent; the path-only behavior is about a year old.
- **Impact:** confirmed contract break for existing installs. Extra `$pageview` events land in every SPA on `'history_change'` after a minor bump, which shifts pageview counts, funnel and conversion baselines, and billable event volume without any customer action. The changeset marks `posthog-js` as `minor`, and the PR leaves the backwards-compatibility checklist item unticked.
</issue_validation>

## Task
Investigate the issue and solve it

<potential_solution>
Keep `history_change` mapped to `{ path: true }`. Add a new dated defaults revision that uses `{ path: true, search: true, hash: true }`. Customers can also opt in with the existing object form. Update the type comment and changeset to explain the gated behavior.
</potential_solution>


if (capturePageview === 'history_change') {
return { path: true }
return { path: true, search: true, hash: true }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not count PostHog's URL cleanup as a pageview

should_fix bug

Why we think it's a valid issue
  • Checked: Whether any SDK-owned code calls the patched replaceState with a URL that differs only in the query string. Searched packages/browser/src and packages/browser-common/src for replaceState outside tests.
  • Found: clearRestoreTokenFromUrl at packages/browser/src/extensions/conversations/external/url-utils.ts:63-78 deletes ph_conv_restore from the URL and calls the global window.history.replaceState(window.history.state, '', newUrl). It uses the global method, so the patch installed by _patchHistoryMethod (packages/browser/src/extensions/history-autocapture.ts:78-101) intercepts it. The path and the hash do not change; only location.search changes.
  • Found: The changed line makes options.search true for history_change, so the search clause in _hasLocationChanged (packages/browser/src/extensions/history-autocapture.ts:130-140) now fires. _capturePageview then sends $pageview with navigation_type: 'replaceState' (packages/browser/src/extensions/history-autocapture.ts:151). Before this change history_change compared pathname alone, so the same cleanup was silent. The regression is introduced by this line.
  • Checked: The order of installation, to confirm the patch is live when the cleanup runs. Read the extension registration in packages/browser/src/posthog-core.ts:1102-1103 and :1131-1132, and the conversations load path.
  • Found: historyAutocapture is registered before conversations, and the conversations manager loads lazily on remote config through loadExternalDependency (packages/browser/src/extensions/conversations/posthog-conversations.ts:51 and :155). The patch is therefore always in place first. _lastLocation is set in the constructor while the token is still in the URL, so the cleanup produces a genuine search difference.
  • Checked: The downstream effect of an extra $pageview.
  • Found: doPageView at packages/browser/src/page-view.ts:77-84 resets the scroll context and closes the previous pageview segment. The synthetic pageview therefore ends the real pageview's duration and scroll measurement almost immediately, and emits $prev_pageview_max_scroll and related properties for a segment of near-zero length.
  • Found: The repeat-cleanup concern is supported by the code's own comment at packages/browser/src/extensions/conversations/external/index.tsx:480-484: cleanup runs three times, because "SPA routers (Next.js, React Router, etc.) maintain their own URL state and can overwrite a single replaceState call." Each overwrite and re-clean pair changes search again, so a router that restores the parameter multiplies the synthetic pageviews.
  • Impact: A user who opens a conversations restore link on any install with capture_pageview: 'history_change' gets at least one $pageview that represents no navigation, plus corrupted scroll and duration attribution on the real pageview. The trigger is a designed product path, not a rare edge case. The same class of problem also reaches the toolbar hash cleanup at packages/browser/src/extensions/toolbar.ts:109, which now changes a captured URL component when disable_capture_url_hashes is false. This is a correctness defect that works against the accuracy goal of the change itself.
Issue description

This enables search capture for every wrapped replaceState call. Conversations uses replaceState to remove its ph_conv_restore parameter after remote configuration loads. That cleanup now sends a $pageview, although the user did not navigate. It also resets pageview duration and scroll state. Routers can restore the parameter between cleanup attempts, which can create more synthetic pageviews.

Suggested fix

Add an internal way to call replaceState without history autocapture. Use it for SDK-owned URL cleanup. Add an integration test with ?ph_conv_restore=.... Assert that cleanup sends no pageview after the initial pageview.

Prompt to fix with AI (copy-paste)
## Context
@packages/browser/src/extensions/history-autocapture.ts#L121

<issue_description>
This enables search capture for every wrapped `replaceState` call. Conversations uses `replaceState` to remove its `ph_conv_restore` parameter after remote configuration loads. That cleanup now sends a `$pageview`, although the user did not navigate. It also resets pageview duration and scroll state. Routers can restore the parameter between cleanup attempts, which can create more synthetic pageviews.
</issue_description>

<issue_validation>
- **Checked:** Whether any SDK-owned code calls the patched `replaceState` with a URL that differs only in the query string. Searched `packages/browser/src` and `packages/browser-common/src` for `replaceState` outside tests.
- **Found:** `clearRestoreTokenFromUrl` at `packages/browser/src/extensions/conversations/external/url-utils.ts:63-78` deletes `ph_conv_restore` from the URL and calls the global `window.history.replaceState(window.history.state, '', newUrl)`. It uses the global method, so the patch installed by `_patchHistoryMethod` (`packages/browser/src/extensions/history-autocapture.ts:78-101`) intercepts it. The path and the hash do not change; only `location.search` changes.
- **Found:** The changed line makes `options.search` true for `history_change`, so the search clause in `_hasLocationChanged` (`packages/browser/src/extensions/history-autocapture.ts:130-140`) now fires. `_capturePageview` then sends `$pageview` with `navigation_type: 'replaceState'` (`packages/browser/src/extensions/history-autocapture.ts:151`). Before this change `history_change` compared `pathname` alone, so the same cleanup was silent. The regression is introduced by this line.
- **Checked:** The order of installation, to confirm the patch is live when the cleanup runs. Read the extension registration in `packages/browser/src/posthog-core.ts:1102-1103` and `:1131-1132`, and the conversations load path.
- **Found:** `historyAutocapture` is registered before `conversations`, and the conversations manager loads lazily on remote config through `loadExternalDependency` (`packages/browser/src/extensions/conversations/posthog-conversations.ts:51` and `:155`). The patch is therefore always in place first. `_lastLocation` is set in the constructor while the token is still in the URL, so the cleanup produces a genuine search difference.
- **Checked:** The downstream effect of an extra `$pageview`.
- **Found:** `doPageView` at `packages/browser/src/page-view.ts:77-84` resets the scroll context and closes the previous pageview segment. The synthetic pageview therefore ends the real pageview's duration and scroll measurement almost immediately, and emits `$prev_pageview_max_scroll` and related properties for a segment of near-zero length.
- **Found:** The repeat-cleanup concern is supported by the code's own comment at `packages/browser/src/extensions/conversations/external/index.tsx:480-484`: cleanup runs three times, because "SPA routers (Next.js, React Router, etc.) maintain their own URL state and can overwrite a single replaceState call." Each overwrite and re-clean pair changes `search` again, so a router that restores the parameter multiplies the synthetic pageviews.
- **Impact:** A user who opens a conversations restore link on any install with `capture_pageview: 'history_change'` gets at least one `$pageview` that represents no navigation, plus corrupted scroll and duration attribution on the real pageview. The trigger is a designed product path, not a rare edge case. The same class of problem also reaches the toolbar hash cleanup at `packages/browser/src/extensions/toolbar.ts:109`, which now changes a captured URL component when `disable_capture_url_hashes` is false. This is a correctness defect that works against the accuracy goal of the change itself.
</issue_validation>

## Task
Investigate the issue and solve it

<potential_solution>
Add an internal way to call `replaceState` without history autocapture. Use it for SDK-owned URL cleanup. Add an integration test with `?ph_conv_restore=...`. Assert that cleanup sends no pageview after the initial pageview.
</potential_solution>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants