Skip to content

fix(browser): cut per-capture storage reads for Meta identifiers - #5433

Merged
ioannisj merged 10 commits into
mainfrom
fix/meta-identifier-storage-event
Nov 9, 2026
Merged

ioannisj merged 10 commits into
mainfrom
fix/meta-identifier-storage-event

Conversation

@ioannisj

@ioannisj ioannisj commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Problem

#5429 stopped parsing the persistence entry on every capture() for the Meta $fbc and $fbp identifiers, but the refresh is still on the capture path: three refreshMetaIdentifiers() calls per event, each reading document.cookie twice and copying the whole localStorage value on localStorage+cookie. With a 310 KB entry (570 flags with details and payloads) that is 5 to 6 entry reads and 10 to 14 cookie reads per click.

The entry only changes when a sibling writes it, and the browser already reports that through the storage event, while the write path already re-reads the entry once, gated on the text having changed.

Changes

Replaces the three refreshMetaIdentifiers() calls per capture() with one gated read before $set is built, so neither a debounced write nor a storage event that hasn't arrived yet can hide a sibling's identifier. Where the main entry is already parsed (the storage event handler and the pre-write reconciliation), sibling updates go through a shared _mergeMetaIdentifierProperties with the same rules refreshKey used: a pending local change wins, set when present and different, delete when absent, and a sibling removing the whole entry (reset(), opt-out) clears the keys.

How each store picks up a sibling:

  • localStorage and localStorage+cookie: the storage event is queued behind the write, so a sibling's value is readable before this tab hears about it. Before capture, the raw entry text is compared against the last text seen, and the Meta keys are only re-read when it changed, so a newer value or a removal reaches the event being built.
  • localStorage+cookie without cookieWinsOnConflict: a cookie compare before capture and before each write parses the 4 KB cookie only when its text changed and fills a key this tab lacks, so a subdomain that writes only the cookie is still seen.
  • localStorage+cookie with cookieWinsOnConflict: the localStorage merge skips cookie-persisted keys and leaves them to syncCookieProperties, so an older sibling value can't overwrite a newer subdomain cookie.
  • cookie and sessionStorage: our listener only handles localStorage events, and same-origin frames share sessionStorage, so both keep the snapshot-gated refreshMetaIdentifiers(), which parses only when the raw text changed.
  • memory has no siblings and refreshes nothing.

The delivery callback refreshes from storage before marking an identifier delivered, so an older response can't confirm over a newer sibling value. On localStorage stores that refresh always parses, but only while the value is unconfirmed, so later responses in a batch skip it. _rawText is removed, nothing calls it any more.

I benchmarked main against this branch in jsdom with the 310 KB entry. Per capture(), as parses / entry reads / cookie reads:

Persistence main this branch
localStorage+cookie 0 / 6 / 10 0 / 4 / 5
localStorage+cookie, cookieWinsOnConflict 0 / 5 / 14 0 / 4 / 8
localStorage 0 / 6 / 2 0 / 4 / 2
sessionStorage 0 / 4 / 2 0 / 3 / 2

With a 250 ms persistence_save_debounce_ms this branch does 1 entry read per capture on every store. A sibling write costs one parse on localStorage and two on localStorage+cookie, because that store's _parse writes the merged entry back, then parsing stops.

The two cookie reads left in every mode are the _fbc and _fbp reads in _readMetaCookie. Most of what remains per capture is the stringify and setItem of the main entry for the session activity write, untouched here.

Timings come from real browsers, since the jsdom medians moved too much between runs. On localStorage+cookie with a 269 KB entry and a 250 ms debounce, capture() went from 0.200 to 0.110 ms on Chromium 136, 0.400 to 0.200 ms on Firefox 137 and 0.250 to 0.167 ms on WebKit 18.4. Plain localStorage on Chromium barely moved. These are headless runs of unminified bundles, so read them as relative numbers.

capture-hot-path.test.ts keeps the parse-count matrix from #5429 and covers each path above, including a debounced capture, a sibling write readable before its storage event, a response racing a sibling write, two frames sharing sessionStorage, and a sibling reset(). The sibling orderings were also forced in real tabs on the same three browsers, and all 24 match the merge base. One difference showed up in a free-running tab loop: the merge base stops re-sending an in-flight value and this branch keeps sending it. It's the same value and I haven't traced why. No sdk-specs capability covers the Meta identifiers.

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

  • All commits are signed (see Commit signing)
  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

DRI: @ioannisj
Autonomy: Human-driven (agent-assisted)

@ioannisj ioannisj self-assigned this Oct 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Replay incident risk check

This diff touches code involved in past incidents. This is a heads-up, not a verdict: read the matched sections of INCIDENTS.md and answer their review questions before merging.

For a judgment on whether this diff has the same failure mode, run the replay-incident-risk skill locally: open a Claude session in the repo root and ask it to review your diff with that skill. Or run node .agents/skills/replay-incident-risk/check.mjs and answer the review questions for each matched class yourself.

Matched 1 past incident pattern(s) (diff vs origin/main):

## Version skew across the lazy-load boundary [path match]
Lazy-loaded bundles (recorder, surveys, web vitals, tracing headers) are served unversioned from the CDN: this change deploys instantly to every SDK version, including npm-pinned ones. Cross-boundary signature changes and persisted-state shape changes have caused fleet-wide recording loss (Mar 2026), broken surveys (Jul 2025, Oct 2025), and a six-day web-vitals gap (Jan 2026).
  Touched paths:
    - packages/browser/src/posthog-persistence.ts
  Read: .agents/skills/replay-incident-risk/INCIDENTS.md#class-1-version-skew-across-the-lazy-load-boundary

This check is advisory. It flags resemblance to past incidents, not correctness.
For a judgment pass on whether this diff has the same failure mode, run the
`replay-incident-risk` skill in a Claude session from the repo root, or answer the
review questions in the matched sections of .agents/skills/replay-incident-risk/INCIDENTS.md yourself.

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PostHog Review · Standard · reviewed a8b0781: 2 Should fix.

This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.

See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Coherence

📄 0 spec file errors · ⛔ 0 broken rules · 🚪 2 unchecked inputs · 🐛 0 bugs that came back

What is Coherence?

Coherence compares the code with its spec files (*.spec.md). A spec file lists the rules for one part of the code.

This check read 44 parts of the code and 7 rules.

Note

These findings do not make this check fail.

None of these findings are in files that this pull request changes. You do not need to fix them in this pull request.

🚪 Unchecked inputs (2)

  • public api in packages/web/Web.spec.md. The input comes from: host-app.
  • webpack plugin in packages/webpack-plugin/Webpack-plugin.spec.md. The input comes from: build.
What this means and how to fix it

Input from outside this code comes in at these places. The spec does not say what checks that input. 10 more places were already like this when Coherence was added. This list does not show them.

To close one of these, find the place by its name in the ## entrances section of its spec file. Add one line under it:

  • If all of the input goes through one function that a rule in the spec protects, add guard: <function>.
  • If a rule in the spec already checks input from the same source, add the place's name to the entrances: line of that rule.
  • If the input needs no check, add control: none - <reason>.

To get the line to add, run npx --no -- coherence scaffold control "<name>".

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Size Change: +23.1 kB (+0.09%)

Total Size: 26.5 MB

📦 View Changed
Filename Size Change
packages/browser/dist/array.full.es5.js 587 kB +1.95 kB (+0.33%)
packages/browser/dist/array.full.js 725 kB +894 B (+0.12%)
packages/browser/dist/array.full.no-external.js 793 kB +1.88 kB (+0.24%)
packages/browser/dist/array.js 375 kB +893 B (+0.24%)
packages/browser/dist/array.no-external.js 423 kB +1.88 kB (+0.45%)
packages/browser/dist/default-extensions.js 372 kB +894 B (+0.24%)
packages/browser/dist/main.js 380 kB +894 B (+0.24%)
packages/browser/dist/module.full.cjs 729 kB +894 B (+0.12%)
packages/browser/dist/module.full.js 729 kB +894 B (+0.12%)
packages/browser/dist/module.full.no-external.cjs 797 kB +1.88 kB (+0.24%)
packages/browser/dist/module.full.no-external.js 797 kB +1.88 kB (+0.24%)
packages/browser/dist/module.js 379 kB +893 B (+0.24%)
packages/browser/dist/module.mjs 379 kB +893 B (+0.24%)
packages/browser/dist/module.no-external.cjs 427 kB +1.88 kB (+0.44%)
packages/browser/dist/module.no-external.js 426 kB +1.88 kB (+0.44%)
packages/browser/dist/module.slim.js 159 kB +879 B (+0.56%)
packages/browser/dist/module.slim.no-external.js 174 kB +1.86 kB (+1.08%)
ℹ️ View Unchanged
Filename Size
packages/ai/dist/adk/index.cjs 41.9 kB
packages/ai/dist/adk/index.mjs 41.6 kB
packages/ai/dist/anthropic/index.cjs 47.8 kB
packages/ai/dist/anthropic/index.mjs 46.3 kB
packages/ai/dist/claude-agent-sdk/index.cjs 50.3 kB
packages/ai/dist/claude-agent-sdk/index.mjs 49.9 kB
packages/ai/dist/evaluations/index.cjs 59.1 kB
packages/ai/dist/evaluations/index.mjs 58.7 kB
packages/ai/dist/gemini/index.cjs 60.8 kB
packages/ai/dist/gemini/index.mjs 60.5 kB
packages/ai/dist/genkit/index.cjs 36.3 kB
packages/ai/dist/genkit/index.mjs 36.1 kB
packages/ai/dist/index.cjs 66.5 kB
packages/ai/dist/index.mjs 66.2 kB
packages/ai/dist/langchain/index.cjs 43.1 kB
packages/ai/dist/langchain/index.mjs 42.9 kB
packages/ai/dist/langchain/middleware/index.cjs 49.6 kB
packages/ai/dist/langchain/middleware/index.mjs 49.2 kB
packages/ai/dist/openai-agents/index.cjs 34.9 kB
packages/ai/dist/openai-agents/index.mjs 34.7 kB
packages/ai/dist/openai/index.cjs 92.3 kB
packages/ai/dist/openai/index.mjs 91.7 kB
packages/ai/dist/otel/index.browser.cjs 38.1 kB
packages/ai/dist/otel/index.browser.mjs 37.7 kB
packages/ai/dist/otel/index.cjs 38.2 kB
packages/ai/dist/otel/index.mjs 37.8 kB
packages/ai/dist/vercel/index.cjs 48.4 kB
packages/ai/dist/vercel/index.mjs 48.2 kB
packages/browser-common/dist/autocapture-config.js 585 B
packages/browser-common/dist/autocapture-config.mjs 12 B
packages/browser-common/dist/autocapture.js 29.9 kB
packages/browser-common/dist/autocapture.mjs 23.9 kB
packages/browser-common/dist/client.js 585 B
packages/browser-common/dist/client.mjs 12 B
packages/browser-common/dist/config.js 1.52 kB
packages/browser-common/dist/config.mjs 217 B
packages/browser-common/dist/console-logs.js 13 kB
packages/browser-common/dist/console-logs.mjs 11.3 kB
packages/browser-common/dist/constants.js 6.37 kB
packages/browser-common/dist/constants.mjs 1.94 kB
packages/browser-common/dist/disposable.js 1.72 kB
packages/browser-common/dist/disposable.mjs 386 B
packages/browser-common/dist/extension-runtime.js 3.17 kB
packages/browser-common/dist/extension-runtime.mjs 1.83 kB
packages/browser-common/dist/extension-tokens.js 1.44 kB
packages/browser-common/dist/extension-tokens.mjs 98 B
packages/browser-common/dist/extension.js 585 B
packages/browser-common/dist/extension.mjs 12 B
packages/browser-common/dist/feature-flags-config.js 585 B
packages/browser-common/dist/feature-flags-config.mjs 12 B
packages/browser-common/dist/feature-flags.js 64.7 kB
packages/browser-common/dist/feature-flags.mjs 58.4 kB
packages/browser-common/dist/index.js 5.87 kB
packages/browser-common/dist/index.mjs 447 B
packages/browser-common/dist/logs-config.js 3.35 kB
packages/browser-common/dist/logs-config.mjs 1.99 kB
packages/browser-common/dist/logs-types.js 1.46 kB
packages/browser-common/dist/logs-types.mjs 133 B
packages/browser-common/dist/logs.js 20 kB
packages/browser-common/dist/logs.mjs 18.1 kB
packages/browser-common/dist/persistence.js 585 B
packages/browser-common/dist/persistence.mjs 12 B
packages/browser-common/dist/pubsub.js 2.63 kB
packages/browser-common/dist/pubsub.mjs 1.35 kB
packages/browser-common/dist/rageclick.js 2.51 kB
packages/browser-common/dist/rageclick.mjs 1.21 kB
packages/browser-common/dist/survey-action-matcher.js 7.81 kB
packages/browser-common/dist/survey-action-matcher.mjs 5.96 kB
packages/browser-common/dist/survey-constants.js 4.61 kB
packages/browser-common/dist/survey-constants.mjs 2.17 kB
packages/browser-common/dist/survey-event-host.js 585 B
packages/browser-common/dist/survey-event-host.mjs 12 B
packages/browser-common/dist/survey-event-receiver-base.js 15.2 kB
packages/browser-common/dist/survey-event-receiver-base.mjs 13.5 kB
packages/browser-common/dist/survey-event-receiver.js 5.84 kB
packages/browser-common/dist/survey-event-receiver.mjs 3.7 kB
packages/browser-common/dist/survey-render-context.js 1.59 kB
packages/browser-common/dist/survey-render-context.mjs 285 B
packages/browser-common/dist/surveys-config.js 2.82 kB
packages/browser-common/dist/surveys-config.mjs 619 B
packages/browser-common/dist/surveys-renderer.js 71.1 kB
packages/browser-common/dist/surveys-renderer.mjs 60.7 kB
packages/browser-common/dist/surveys.js 28 kB
packages/browser-common/dist/surveys.mjs 23 kB
packages/browser-common/dist/surveys/components/BottomSection.js 3.4 kB
packages/browser-common/dist/surveys/components/BottomSection.mjs 1.74 kB
packages/browser-common/dist/surveys/components/ConfirmationMessage.js 4 kB
packages/browser-common/dist/surveys/components/ConfirmationMessage.mjs 2.09 kB
packages/browser-common/dist/surveys/components/IntroScreen.js 3.48 kB
packages/browser-common/dist/surveys/components/IntroScreen.mjs 1.68 kB
packages/browser-common/dist/surveys/components/PostHogLogo.js 2 kB
packages/browser-common/dist/surveys/components/PostHogLogo.mjs 614 B
packages/browser-common/dist/surveys/components/QuestionHeader.js 3.48 kB
packages/browser-common/dist/surveys/components/QuestionHeader.mjs 1.64 kB
packages/browser-common/dist/surveys/components/QuestionTypes.js 25.9 kB
packages/browser-common/dist/surveys/components/QuestionTypes.mjs 21 kB
packages/browser-common/dist/surveys/icons.js 15.5 kB
packages/browser-common/dist/surveys/icons.mjs 12.3 kB
packages/browser-common/dist/surveys/survey-branching.js 5.99 kB
packages/browser-common/dist/surveys/survey-branching.mjs 3.9 kB
packages/browser-common/dist/surveys/survey-html-sanitizer.js 5.18 kB
packages/browser-common/dist/surveys/survey-html-sanitizer.mjs 3.47 kB
packages/browser-common/dist/surveys/survey-styles.js 14.7 kB
packages/browser-common/dist/surveys/survey-styles.mjs 13.4 kB
packages/browser-common/dist/surveys/survey-translations.js 2.69 kB
packages/browser-common/dist/surveys/survey-translations.mjs 1.08 kB
packages/browser-common/dist/surveys/survey-url-prefill.js 7.99 kB
packages/browser-common/dist/surveys/survey-url-prefill.mjs 5.62 kB
packages/browser-common/dist/surveys/surveys-extension-utils.js 34.6 kB
packages/browser-common/dist/surveys/surveys-extension-utils.mjs 26.1 kB
packages/browser-common/dist/token.js 585 B
packages/browser-common/dist/token.mjs 12 B
packages/browser-common/dist/types/compression.js 1.37 kB
packages/browser-common/dist/types/compression.mjs 93 B
packages/browser-common/dist/types/feature-flags.js 585 B
packages/browser-common/dist/types/feature-flags.mjs 12 B
packages/browser-common/dist/types/index.js 4.16 kB
packages/browser-common/dist/types/index.mjs 181 B
packages/browser-common/dist/types/network-recording.js 585 B
packages/browser-common/dist/types/network-recording.mjs 12 B
packages/browser-common/dist/types/remote-config.js 585 B
packages/browser-common/dist/types/remote-config.mjs 12 B
packages/browser-common/dist/types/surveys.js 585 B
packages/browser-common/dist/types/surveys.mjs 12 B
packages/browser-common/dist/utils/array-at-polyfill.js 619 B
packages/browser-common/dist/utils/array-at-polyfill.mjs 437 B
packages/browser-common/dist/utils/array-find-last-polyfill.js 604 B
packages/browser-common/dist/utils/array-find-last-polyfill.mjs 422 B
packages/browser-common/dist/utils/autocapture-utils.js 26.5 kB
packages/browser-common/dist/utils/autocapture-utils.mjs 20.4 kB
packages/browser-common/dist/utils/blocked-uas.js 2.2 kB
packages/browser-common/dist/utils/blocked-uas.mjs 598 B
packages/browser-common/dist/utils/console-original.js 1.49 kB
packages/browser-common/dist/utils/console-original.mjs 171 B
packages/browser-common/dist/utils/convert-to-url.js 1.62 kB
packages/browser-common/dist/utils/convert-to-url.mjs 298 B
packages/browser-common/dist/utils/cookie-utils.js 1.99 kB
packages/browser-common/dist/utils/cookie-utils.mjs 673 B
packages/browser-common/dist/utils/device-model-utils.js 2.08 kB
packages/browser-common/dist/utils/device-model-utils.mjs 678 B
packages/browser-common/dist/utils/element-utils.js 2.56 kB
packages/browser-common/dist/utils/element-utils.mjs 804 B
packages/browser-common/dist/utils/elements-chain-utils.js 2.86 kB
packages/browser-common/dist/utils/elements-chain-utils.mjs 1.23 kB
packages/browser-common/dist/utils/encode-utils.js 1.49 kB
packages/browser-common/dist/utils/encode-utils.mjs 205 B
packages/browser-common/dist/utils/event-utils.js 16.1 kB
packages/browser-common/dist/utils/event-utils.mjs 10.2 kB
packages/browser-common/dist/utils/general-utils.js 7.83 kB
packages/browser-common/dist/utils/general-utils.mjs 4.77 kB
packages/browser-common/dist/utils/globals.js 2.83 kB
packages/browser-common/dist/utils/globals.mjs 842 B
packages/browser-common/dist/utils/logger.js 3.46 kB
packages/browser-common/dist/utils/logger.mjs 1.67 kB
packages/browser-common/dist/utils/matcher-utils.js 2.78 kB
packages/browser-common/dist/utils/matcher-utils.mjs 1.3 kB
packages/browser-common/dist/utils/patch.js 2.94 kB
packages/browser-common/dist/utils/patch.mjs 1.62 kB
packages/browser-common/dist/utils/promise-utils.js 1.45 kB
packages/browser-common/dist/utils/promise-utils.mjs 169 B
packages/browser-common/dist/utils/property-utils.js 3.63 kB
packages/browser-common/dist/utils/property-utils.mjs 1.6 kB
packages/browser-common/dist/utils/prototype-utils.js 3.61 kB
packages/browser-common/dist/utils/prototype-utils.mjs 1.86 kB
packages/browser-common/dist/utils/regex-utils.js 1.55 kB
packages/browser-common/dist/utils/regex-utils.mjs 71 B
packages/browser-common/dist/utils/request-reachability.js 2.55 kB
packages/browser-common/dist/utils/request-reachability.mjs 996 B
packages/browser-common/dist/utils/request-utils.js 6.5 kB
packages/browser-common/dist/utils/request-utils.mjs 3.68 kB
packages/browser-common/dist/utils/sanitize-url.js 1.76 kB
packages/browser-common/dist/utils/sanitize-url.mjs 475 B
packages/browser-common/dist/utils/simple-event-emitter.js 1.86 kB
packages/browser-common/dist/utils/simple-event-emitter.mjs 553 B
packages/browser-common/dist/utils/stylesheet-loader.js 2.23 kB
packages/browser-common/dist/utils/stylesheet-loader.mjs 823 B
packages/browser-common/dist/utils/survey-utils.js 5.74 kB
packages/browser-common/dist/utils/survey-utils.mjs 2.05 kB
packages/browser-common/dist/utils/timezone.js 1.44 kB
packages/browser-common/dist/utils/timezone.mjs 163 B
packages/browser-common/dist/utils/type-utils.js 1.68 kB
packages/browser-common/dist/utils/type-utils.mjs 258 B
packages/browser-common/dist/utils/url-targeting-utils.js 2.4 kB
packages/browser-common/dist/utils/url-targeting-utils.mjs 823 B
packages/browser-common/dist/utils/uuidv7.js 6.81 kB
packages/browser-common/dist/utils/uuidv7.mjs 5.26 kB
packages/browser-next/dist/analytics-buffer.js 7.69 kB
packages/browser-next/dist/analytics-buffer.mjs 6.03 kB
packages/browser-next/dist/analytics-delivery.js 8.79 kB
packages/browser-next/dist/analytics-delivery.mjs 7.11 kB
packages/browser-next/dist/analytics-internal.js 1.95 kB
packages/browser-next/dist/analytics-internal.mjs 273 B
packages/browser-next/dist/analytics-options.js 585 B
packages/browser-next/dist/analytics-options.mjs 12 B
packages/browser-next/dist/analytics.js 1.67 kB
packages/browser-next/dist/analytics.mjs 259 B
packages/browser-next/dist/autocapture-options.js 1.85 kB
packages/browser-next/dist/autocapture-options.mjs 513 B
packages/browser-next/dist/autocapture.js 4.44 kB
packages/browser-next/dist/autocapture.mjs 3.01 kB
packages/browser-next/dist/automatic-analytics.js 1.64 kB
packages/browser-next/dist/automatic-analytics.mjs 298 B
packages/browser-next/dist/automatic-surveys.js 1.54 kB
packages/browser-next/dist/automatic-surveys.mjs 189 B
packages/browser-next/dist/bot-filter.js 2.38 kB
packages/browser-next/dist/bot-filter.mjs 1.09 kB
packages/browser-next/dist/browser-client.js 585 B
packages/browser-next/dist/browser-client.mjs 12 B
packages/browser-next/dist/capture-summary.js 2.14 kB
packages/browser-next/dist/capture-summary.mjs 647 B
packages/browser-next/dist/capture-v1.js 29.9 kB
packages/browser-next/dist/capture-v1.mjs 27.2 kB
packages/browser-next/dist/core.js 1.96 kB
packages/browser-next/dist/core.mjs 244 B
packages/browser-next/dist/event-buffer.js 5.32 kB
packages/browser-next/dist/event-buffer.mjs 4.04 kB
packages/browser-next/dist/extensions/registry.js 4.42 kB
packages/browser-next/dist/extensions/registry.mjs 3.12 kB
packages/browser-next/dist/flags-internal.js 585 B
packages/browser-next/dist/flags-internal.mjs 12 B
packages/browser-next/dist/flags-options.js 585 B
packages/browser-next/dist/flags-options.mjs 12 B
packages/browser-next/dist/flags-token.js 1.4 kB
packages/browser-next/dist/flags-token.mjs 80 B
packages/browser-next/dist/flags.js 6.61 kB
packages/browser-next/dist/flags.mjs 5.02 kB
packages/browser-next/dist/id.js 2.25 kB
packages/browser-next/dist/id.mjs 983 B
packages/browser-next/dist/index.js 5.46 kB
packages/browser-next/dist/index.mjs 3.38 kB
packages/browser-next/dist/lane.js 15.1 kB
packages/browser-next/dist/lane.mjs 13.8 kB
packages/browser-next/dist/logger.js 2.08 kB
packages/browser-next/dist/logger.mjs 742 B
packages/browser-next/dist/logs-internal.js 585 B
packages/browser-next/dist/logs-internal.mjs 12 B
packages/browser-next/dist/logs-options.js 1.84 kB
packages/browser-next/dist/logs-options.mjs 529 B
packages/browser-next/dist/logs.js 5.33 kB
packages/browser-next/dist/logs.mjs 3.83 kB
packages/browser-next/dist/named-error.js 1.57 kB
packages/browser-next/dist/named-error.mjs 271 B
packages/browser-next/dist/posthog.js 34.7 kB
packages/browser-next/dist/posthog.mjs 32.3 kB
packages/browser-next/dist/rate-limiter.js 3.06 kB
packages/browser-next/dist/rate-limiter.mjs 1.75 kB
packages/browser-next/dist/remote-config.js 1.85 kB
packages/browser-next/dist/remote-config.mjs 483 B
packages/browser-next/dist/request.js 4.99 kB
packages/browser-next/dist/request.mjs 3.58 kB
packages/browser-next/dist/state.js 24.9 kB
packages/browser-next/dist/state.mjs 23.1 kB
packages/browser-next/dist/surveys-extension.js 11.3 kB
packages/browser-next/dist/surveys-extension.mjs 9.73 kB
packages/browser-next/dist/surveys-internal.js 585 B
packages/browser-next/dist/surveys-internal.mjs 12 B
packages/browser-next/dist/surveys-options.js 1.44 kB
packages/browser-next/dist/surveys-options.mjs 112 B
packages/browser-next/dist/surveys.js 1.77 kB
packages/browser-next/dist/surveys.mjs 258 B
packages/browser-next/dist/types.js 585 B
packages/browser-next/dist/types.mjs 12 B
packages/browser-next/dist/version.js 1.31 kB
packages/browser-next/dist/version.mjs 45 B
packages/browser/dist/all-external-dependencies.js 428 kB
packages/browser/dist/conversations.js 75.1 kB
packages/browser/dist/crisp-chat-integration.js 1.67 kB
packages/browser/dist/customizations.full.js 19.5 kB
packages/browser/dist/customizations.js 19.1 kB
packages/browser/dist/dead-clicks-autocapture.js 24 kB
packages/browser/dist/element-inference.js 5.28 kB
packages/browser/dist/exception-autocapture.js 17.8 kB
packages/browser/dist/extension-bundles.js 223 kB
packages/browser/dist/external-scripts-loader.js 3.7 kB
packages/browser/dist/intercom-integration.js 1.72 kB
packages/browser/dist/lazy-recorder.js 221 kB
packages/browser/dist/loader-bootstrap.js 4.93 kB
packages/browser/dist/loader.js 6.67 kB
packages/browser/dist/logs.js 7.21 kB
packages/browser/dist/posthog-recorder.js 220 kB
packages/browser/dist/product-tours-preview.js 78.1 kB
packages/browser/dist/product-tours.js 122 kB
packages/browser/dist/recorder-v2.js 140 kB
packages/browser/dist/recorder.js 140 kB
packages/browser/dist/rrweb-plugin-console-record.js 7.63 kB
packages/browser/dist/rrweb-types.js 2.41 kB
packages/browser/dist/rrweb.js 333 kB
packages/browser/dist/surveys-preview.js 120 kB
packages/browser/dist/surveys.js 144 kB
packages/browser/dist/tracing-headers.js 4.71 kB
packages/browser/dist/web-vitals-soft-navs.js 11.1 kB
packages/browser/dist/web-vitals-with-attribution-soft-navs.js 27 kB
packages/browser/dist/web-vitals-with-attribution.js 27 kB
packages/browser/dist/web-vitals.js 11 kB
packages/browser/react/dist/esm/index.js 23.3 kB
packages/browser/react/dist/esm/slim/index.js 19.5 kB
packages/browser/react/dist/esm/surveys/index.js 4.22 kB
packages/browser/react/dist/umd/index.js 27.8 kB
packages/browser/react/dist/umd/slim/index.js 23.5 kB
packages/browser/react/dist/umd/surveys/index.js 6.33 kB
packages/convex/dist/client/feature-flags/crypto.js 76 B
packages/convex/dist/client/feature-flags/evaluator.js 16.2 kB
packages/convex/dist/client/feature-flags/index.js 196 B
packages/convex/dist/client/feature-flags/match-property.js 5.7 kB
packages/convex/dist/client/feature-flags/types.js 44 B
packages/convex/dist/client/index.js 14.8 kB
packages/convex/dist/component/_generated/api.js 712 B
packages/convex/dist/component/_generated/component.js 212 B
packages/convex/dist/component/_generated/dataModel.js 230 B
packages/convex/dist/component/_generated/server.js 3.74 kB
packages/convex/dist/component/convex.config.js 1.66 kB
packages/convex/dist/component/crons.js 969 B
packages/convex/dist/component/lib.js 24.9 kB
packages/convex/dist/component/schema.js 1.17 kB
packages/convex/dist/component/version.js 67 B
packages/core/dist/cookie.js 5.71 kB
packages/core/dist/cookie.mjs 3.4 kB
packages/core/dist/error-tracking/chunk-ids.js 3.44 kB
packages/core/dist/error-tracking/chunk-ids.mjs 2.11 kB
packages/core/dist/error-tracking/coercers/dom-exception-coercer.js 2.4 kB
packages/core/dist/error-tracking/coercers/dom-exception-coercer.mjs 993 B
packages/core/dist/error-tracking/coercers/error-coercer.js 2.58 kB
packages/core/dist/error-tracking/coercers/error-coercer.mjs 1.24 kB
packages/core/dist/error-tracking/coercers/error-event-coercer.js 2.45 kB
packages/core/dist/error-tracking/coercers/error-event-coercer.mjs 1.05 kB
packages/core/dist/error-tracking/coercers/event-coercer.js 1.92 kB
packages/core/dist/error-tracking/coercers/event-coercer.mjs 548 B
packages/core/dist/error-tracking/coercers/index.js 5.82 kB
packages/core/dist/error-tracking/coercers/index.mjs 326 B
packages/core/dist/error-tracking/coercers/object-coercer.js 4.13 kB
packages/core/dist/error-tracking/coercers/object-coercer.mjs 2.53 kB
packages/core/dist/error-tracking/coercers/primitive-coercer.js 1.76 kB
packages/core/dist/error-tracking/coercers/primitive-coercer.mjs 419 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.js 2.69 kB
packages/core/dist/error-tracking/coercers/promise-rejection-event.mjs 1.25 kB
packages/core/dist/error-tracking/coercers/string-coercer.js 2.11 kB
packages/core/dist/error-tracking/coercers/string-coercer.mjs 820 B
packages/core/dist/error-tracking/coercers/utils.js 2.16 kB
packages/core/dist/error-tracking/coercers/utils.mjs 716 B
packages/core/dist/error-tracking/error-properties-builder.js 10.1 kB
packages/core/dist/error-tracking/error-properties-builder.mjs 8.58 kB
packages/core/dist/error-tracking/exception-steps.js 6.1 kB
packages/core/dist/error-tracking/exception-steps.mjs 3.83 kB
packages/core/dist/error-tracking/index.js 4.62 kB
packages/core/dist/error-tracking/index.mjs 222 B
packages/core/dist/error-tracking/parsers/base.js 2.43 kB
packages/core/dist/error-tracking/parsers/base.mjs 961 B
packages/core/dist/error-tracking/parsers/chrome.js 2.83 kB
packages/core/dist/error-tracking/parsers/chrome.mjs 1.32 kB
packages/core/dist/error-tracking/parsers/gecko.js 2.57 kB
packages/core/dist/error-tracking/parsers/gecko.mjs 1.13 kB
packages/core/dist/error-tracking/parsers/index.js 8.87 kB
packages/core/dist/error-tracking/parsers/index.mjs 6.03 kB
packages/core/dist/error-tracking/parsers/node.js 4.33 kB
packages/core/dist/error-tracking/parsers/node.mjs 2.96 kB
packages/core/dist/error-tracking/parsers/opera.js 2.35 kB
packages/core/dist/error-tracking/parsers/opera.mjs 746 B
packages/core/dist/error-tracking/parsers/safari.js 1.98 kB
packages/core/dist/error-tracking/parsers/safari.mjs 574 B
packages/core/dist/error-tracking/parsers/winjs.js 1.82 kB
packages/core/dist/error-tracking/parsers/winjs.mjs 426 B
packages/core/dist/error-tracking/release.js 1.68 kB
packages/core/dist/error-tracking/release.mjs 366 B
packages/core/dist/error-tracking/types.js 1.42 kB
packages/core/dist/error-tracking/types.mjs 131 B
packages/core/dist/error-tracking/utils.js 1.9 kB
packages/core/dist/error-tracking/utils.mjs 604 B
packages/core/dist/eventemitter.js 1.88 kB
packages/core/dist/eventemitter.mjs 571 B
packages/core/dist/featureFlagLocalEvaluation.js 28.9 kB
packages/core/dist/featureFlagLocalEvaluation.mjs 26.1 kB
packages/core/dist/featureFlagUtils.js 8.61 kB
packages/core/dist/featureFlagUtils.mjs 5.52 kB
packages/core/dist/gzip.js 5.88 kB
packages/core/dist/gzip.mjs 3.87 kB
packages/core/dist/index.js 27.9 kB
packages/core/dist/index.mjs 2.02 kB
packages/core/dist/logs/index.js 11.8 kB
packages/core/dist/logs/index.mjs 9.83 kB
packages/core/dist/logs/logs-utils.js 6.68 kB
packages/core/dist/logs/logs-utils.mjs 4.53 kB
packages/core/dist/logs/types.js 585 B
packages/core/dist/logs/types.mjs 12 B
packages/core/dist/metrics/config.js 2.05 kB
packages/core/dist/metrics/config.mjs 735 B
packages/core/dist/metrics/index.js 19.7 kB
packages/core/dist/metrics/index.mjs 16.6 kB
packages/core/dist/metrics/metrics-utils.js 3.67 kB
packages/core/dist/metrics/metrics-utils.mjs 1.68 kB
packages/core/dist/metrics/types.js 585 B
packages/core/dist/metrics/types.mjs 12 B
packages/core/dist/posthog-core-stateless.js 49.3 kB
packages/core/dist/posthog-core-stateless.mjs 45.9 kB
packages/core/dist/posthog-core.js 50.4 kB
packages/core/dist/posthog-core.mjs 44.7 kB
packages/core/dist/privacy.js 15.6 kB
packages/core/dist/privacy.mjs 14 kB
packages/core/dist/surveys/activation.js 2.29 kB
packages/core/dist/surveys/activation.mjs 572 B
packages/core/dist/surveys/events.js 5.82 kB
packages/core/dist/surveys/events.mjs 3.14 kB
packages/core/dist/surveys/index.js 7.48 kB
packages/core/dist/surveys/index.mjs 921 B
packages/core/dist/surveys/keys.js 1.8 kB
packages/core/dist/surveys/keys.mjs 350 B
packages/core/dist/surveys/property-matching.js 3.8 kB
packages/core/dist/surveys/property-matching.mjs 2.15 kB
packages/core/dist/surveys/shuffling.js 2.53 kB
packages/core/dist/surveys/shuffling.mjs 1.07 kB
packages/core/dist/surveys/translations.js 9.18 kB
packages/core/dist/surveys/translations.mjs 6.83 kB
packages/core/dist/surveys/validation.js 3.15 kB
packages/core/dist/surveys/validation.mjs 1.51 kB
packages/core/dist/testing/index.js 2.76 kB
packages/core/dist/testing/index.mjs 79 B
packages/core/dist/testing/PostHogCoreTestClient.js 3.35 kB
packages/core/dist/testing/PostHogCoreTestClient.mjs 1.85 kB
packages/core/dist/testing/test-utils.js 2.9 kB
packages/core/dist/testing/test-utils.mjs 1.11 kB
packages/core/dist/traces/config.js 4.62 kB
packages/core/dist/traces/config.mjs 3.27 kB
packages/core/dist/traces/context.js 1.64 kB
packages/core/dist/traces/context.mjs 318 B
packages/core/dist/traces/ids.js 3.2 kB
packages/core/dist/traces/ids.mjs 1.52 kB
packages/core/dist/traces/index.js 26.7 kB
packages/core/dist/traces/index.mjs 24 kB
packages/core/dist/traces/otlp.js 6.33 kB
packages/core/dist/traces/otlp.mjs 4.14 kB
packages/core/dist/traces/sanitize.js 3.59 kB
packages/core/dist/traces/sanitize.mjs 1.88 kB
packages/core/dist/traces/span.js 20 kB
packages/core/dist/traces/span.mjs 16.7 kB
packages/core/dist/traces/traceparent.js 4.54 kB
packages/core/dist/traces/traceparent.mjs 2.54 kB
packages/core/dist/traces/types.js 585 B
packages/core/dist/traces/types.mjs 12 B
packages/core/dist/tracing-headers.js 3.48 kB
packages/core/dist/tracing-headers.mjs 2.08 kB
packages/core/dist/types.js 8.53 kB
packages/core/dist/types.mjs 5.37 kB
packages/core/dist/utils/backoff.js 2.36 kB
packages/core/dist/utils/backoff.mjs 611 B
packages/core/dist/utils/bot-detection.js 4.19 kB
packages/core/dist/utils/bot-detection.mjs 2.59 kB
packages/core/dist/utils/browser-utils.js 1.57 kB
packages/core/dist/utils/browser-utils.mjs 182 B
packages/core/dist/utils/bucketed-rate-limiter.js 4.32 kB
packages/core/dist/utils/bucketed-rate-limiter.mjs 2.22 kB
packages/core/dist/utils/flush-timer.js 2.06 kB
packages/core/dist/utils/flush-timer.mjs 725 B
packages/core/dist/utils/index.js 17.8 kB
packages/core/dist/utils/index.mjs 3.69 kB
packages/core/dist/utils/json-utils.js 7.44 kB
packages/core/dist/utils/json-utils.mjs 5.02 kB
packages/core/dist/utils/logger.js 2.68 kB
packages/core/dist/utils/logger.mjs 1.29 kB
packages/core/dist/utils/number-utils.js 3.42 kB
packages/core/dist/utils/number-utils.mjs 1.68 kB
packages/core/dist/utils/otlp-any-value.js 7.96 kB
packages/core/dist/utils/otlp-any-value.mjs 5.77 kB
packages/core/dist/utils/otlp-resource.js 3.94 kB
packages/core/dist/utils/otlp-resource.mjs 1.97 kB
packages/core/dist/utils/promise-queue.js 2.58 kB
packages/core/dist/utils/promise-queue.mjs 1.25 kB
packages/core/dist/utils/retry-after.js 3.5 kB
packages/core/dist/utils/retry-after.mjs 1.96 kB
packages/core/dist/utils/string-utils.js 3.83 kB
packages/core/dist/utils/string-utils.mjs 1.97 kB
packages/core/dist/utils/type-utils.js 7.52 kB
packages/core/dist/utils/type-utils.mjs 3.27 kB
packages/core/dist/utils/user-agent-utils.js 19 kB
packages/core/dist/utils/user-agent-utils.mjs 15.2 kB
packages/core/dist/utils/webview-app-utils.js 3.54 kB
packages/core/dist/utils/webview-app-utils.mjs 2.23 kB
packages/core/dist/vendor/uuidv7.js 8.36 kB
packages/core/dist/vendor/uuidv7.mjs 6.7 kB
packages/mcp/dist/extensions/analytics-parameters.js 6.65 kB
packages/mcp/dist/extensions/analytics-parameters.mjs 4.3 kB
packages/mcp/dist/extensions/capture.js 4.11 kB
packages/mcp/dist/extensions/capture.mjs 2.65 kB
packages/mcp/dist/extensions/client-identity.js 6.33 kB
packages/mcp/dist/extensions/client-identity.mjs 3.71 kB
packages/mcp/dist/extensions/compatibility.js 5.45 kB
packages/mcp/dist/extensions/compatibility.mjs 3.4 kB
packages/mcp/dist/extensions/constants.js 5.69 kB
packages/mcp/dist/extensions/constants.mjs 3.19 kB
packages/mcp/dist/extensions/context-parameters.js 2.85 kB
packages/mcp/dist/extensions/context-parameters.mjs 899 B
packages/mcp/dist/extensions/conversation-id.js 6.41 kB
packages/mcp/dist/extensions/conversation-id.mjs 3.58 kB
packages/mcp/dist/extensions/detect.js 3.87 kB
packages/mcp/dist/extensions/detect.mjs 1.49 kB
packages/mcp/dist/extensions/event-types.js 1.82 kB
packages/mcp/dist/extensions/event-types.mjs 498 B
packages/mcp/dist/extensions/exceptions.js 2.67 kB
packages/mcp/dist/extensions/exceptions.mjs 1.19 kB
packages/mcp/dist/extensions/feedback.js 12.1 kB
packages/mcp/dist/extensions/feedback.mjs 9.18 kB
packages/mcp/dist/extensions/headers.js 2.08 kB
packages/mcp/dist/extensions/headers.mjs 643 B
packages/mcp/dist/extensions/ids.js 2.11 kB
packages/mcp/dist/extensions/ids.mjs 637 B
packages/mcp/dist/extensions/instrument-highlevel.js 15.8 kB
packages/mcp/dist/extensions/instrument-highlevel.mjs 12.5 kB
packages/mcp/dist/extensions/instrument-lowlevel.js 8.44 kB
packages/mcp/dist/extensions/instrument-lowlevel.mjs 5.88 kB
packages/mcp/dist/extensions/instrumentation.js 37.9 kB
packages/mcp/dist/extensions/instrumentation.mjs 30.8 kB
packages/mcp/dist/extensions/intent.js 3.3 kB
packages/mcp/dist/extensions/intent.mjs 1.64 kB
packages/mcp/dist/extensions/internal.js 4.99 kB
packages/mcp/dist/extensions/internal.mjs 2.88 kB
packages/mcp/dist/extensions/lib-identity.js 1.7 kB
packages/mcp/dist/extensions/lib-identity.mjs 267 B
packages/mcp/dist/extensions/logger.js 1.81 kB
packages/mcp/dist/extensions/logger.mjs 380 B
packages/mcp/dist/extensions/mcp-payloads.js 3.96 kB
packages/mcp/dist/extensions/mcp-payloads.mjs 2.24 kB
packages/mcp/dist/extensions/mcp-sdk-compat.js 5.86 kB
packages/mcp/dist/extensions/mcp-sdk-compat.mjs 3.5 kB
packages/mcp/dist/extensions/model-parameters.js 4.6 kB
packages/mcp/dist/extensions/model-parameters.mjs 2.33 kB
packages/mcp/dist/extensions/output-instructions.js 6.21 kB
packages/mcp/dist/extensions/output-instructions.mjs 3.91 kB
packages/mcp/dist/extensions/posthog-events.js 12.5 kB
packages/mcp/dist/extensions/posthog-events.mjs 8.49 kB
packages/mcp/dist/extensions/posthog-mcp.js 17.2 kB
packages/mcp/dist/extensions/posthog-mcp.mjs 13.8 kB
packages/mcp/dist/extensions/request-headers.js 2.27 kB
packages/mcp/dist/extensions/request-headers.mjs 963 B
packages/mcp/dist/extensions/sanitization.js 4.82 kB
packages/mcp/dist/extensions/sanitization.mjs 2.92 kB
packages/mcp/dist/extensions/server-build.js 1.94 kB
packages/mcp/dist/extensions/server-build.mjs 482 B
packages/mcp/dist/extensions/session-token.js 5.47 kB
packages/mcp/dist/extensions/session-token.mjs 3.6 kB
packages/mcp/dist/extensions/session.js 6.79 kB
packages/mcp/dist/extensions/session.mjs 4.16 kB
packages/mcp/dist/extensions/sink.js 4.47 kB
packages/mcp/dist/extensions/sink.mjs 2.67 kB
packages/mcp/dist/extensions/tool-input.js 4.82 kB
packages/mcp/dist/extensions/tool-input.mjs 3.27 kB
packages/mcp/dist/extensions/tools.js 3.81 kB
packages/mcp/dist/extensions/tools.mjs 1.68 kB
packages/mcp/dist/extensions/tracing-helpers.js 2.51 kB
packages/mcp/dist/extensions/tracing-helpers.mjs 772 B
packages/mcp/dist/extensions/transport-identity.js 3 kB
packages/mcp/dist/extensions/transport-identity.mjs 1.09 kB
packages/mcp/dist/extensions/truncation.js 11.9 kB
packages/mcp/dist/extensions/truncation.mjs 10 kB
packages/mcp/dist/index.js 10.2 kB
packages/mcp/dist/index.mjs 5.54 kB
packages/mcp/dist/types.js 585 B
packages/mcp/dist/types.mjs 12 B
packages/mcp/dist/version.js 1.31 kB
packages/mcp/dist/version.mjs 45 B
packages/next/dist/app/PostHogProvider.js 5.37 kB
packages/next/dist/client/ClientPostHogProvider.js 2.28 kB
packages/next/dist/client/hooks.js 172 B
packages/next/dist/client/PostHogPageView.js 4.23 kB
packages/next/dist/index.client.js 401 B
packages/next/dist/index.edge.js 588 B
packages/next/dist/index.js 572 B
packages/next/dist/index.react-server.js 420 B
packages/next/dist/middleware/postHogMiddleware.js 4.08 kB
packages/next/dist/otel.js 1.12 kB
packages/next/dist/otel.unsupported.js 181 B
packages/next/dist/pages.client.js 225 B
packages/next/dist/pages.edge.js 294 B
packages/next/dist/pages.js 347 B
packages/next/dist/pages/createPostHog.js 1.48 kB
packages/next/dist/pages/getServerSidePostHog.js 1.48 kB
packages/next/dist/pages/PostHogPageView.js 1.77 kB
packages/next/dist/pages/PostHogProvider.js 1.58 kB
packages/next/dist/server.edge.js 1.65 kB
packages/next/dist/server/captureRequestError.js 16.4 kB
packages/next/dist/server/clientCache.edge.js 305 B
packages/next/dist/server/clientCache.js 1.53 kB
packages/next/dist/server/clientCache.node.js 828 B
packages/next/dist/server/createPostHog.js 1.44 kB
packages/next/dist/server/getPostHog.js 3.89 kB
packages/next/dist/server/onRequestError.js 2.55 kB
packages/next/dist/server/onRequestError.types.js 59 B
packages/next/dist/server/withPostHogProxy.js 4.03 kB
packages/next/dist/shared/browser.js 195 B
packages/next/dist/shared/config.js 2.23 kB
packages/next/dist/shared/constants.js 201 B
packages/next/dist/shared/cookie.js 540 B
packages/next/dist/shared/identity.js 2.56 kB
packages/next/dist/shared/tracing-headers.js 2.18 kB
packages/nextjs-config/dist/config.js 13.6 kB
packages/nextjs-config/dist/config.mjs 11.9 kB
packages/nextjs-config/dist/index.js 2.21 kB
packages/nextjs-config/dist/index.mjs 30 B
packages/nextjs-config/dist/inject-server-release.js 4.51 kB
packages/nextjs-config/dist/inject-server-release.mjs 2.68 kB
packages/nextjs-config/dist/strip-sourcemap-comments.js 5.46 kB
packages/nextjs-config/dist/strip-sourcemap-comments.mjs 3.37 kB
packages/nextjs-config/dist/utils.js 4.81 kB
packages/nextjs-config/dist/utils.mjs 2.33 kB
packages/node/dist/ai-capture/batching.js 2.71 kB
packages/node/dist/ai-capture/batching.mjs 1.21 kB
packages/node/dist/ai-capture/routing.js 1.96 kB
packages/node/dist/ai-capture/routing.mjs 264 B
packages/node/dist/capture-v1/config.js 1.59 kB
packages/node/dist/capture-v1/config.mjs 283 B
packages/node/dist/capture-v1/errors.js 1.99 kB
packages/node/dist/capture-v1/errors.mjs 694 B
packages/node/dist/capture-v1/routing.js 1.77 kB
packages/node/dist/capture-v1/routing.mjs 279 B
packages/node/dist/capture-v1/sender.js 11.5 kB
packages/node/dist/capture-v1/sender.mjs 9.94 kB
packages/node/dist/capture-v1/transform.js 5.22 kB
packages/node/dist/capture-v1/transform.mjs 3.65 kB
packages/node/dist/capture-v1/types.js 585 B
packages/node/dist/capture-v1/types.mjs 12 B
packages/node/dist/client.js 67.2 kB
packages/node/dist/client.mjs 63.3 kB
packages/node/dist/emails/emails.js 19.9 kB
packages/node/dist/emails/emails.mjs 17.6 kB
packages/node/dist/emails/errors.js 2.79 kB
packages/node/dist/emails/errors.mjs 1.52 kB
packages/node/dist/emails/types.js 585 B
packages/node/dist/emails/types.mjs 12 B
packages/node/dist/entrypoints/index.edge.js 3.66 kB
packages/node/dist/entrypoints/index.edge.mjs 720 B
packages/node/dist/entrypoints/index.node.js 6.45 kB
packages/node/dist/entrypoints/index.node.mjs 1.77 kB
packages/node/dist/entrypoints/nestjs.js 2.27 kB
packages/node/dist/entrypoints/nestjs.mjs 42 B
packages/node/dist/entrypoints/otel.js 3.93 kB
packages/node/dist/entrypoints/otel.mjs 2.35 kB
packages/node/dist/experimental.js 852 B
packages/node/dist/experimental.mjs 279 B
packages/node/dist/exports.js 7.2 kB
packages/node/dist/exports.mjs 510 B
packages/node/dist/extensions/context/context.js 2.62 kB
packages/node/dist/extensions/context/context.mjs 1.14 kB
packages/node/dist/extensions/context/event-context.js 1.93 kB
packages/node/dist/extensions/context/event-context.mjs 501 B
packages/node/dist/extensions/context/lifetime.js 2.01 kB
packages/node/dist/extensions/context/lifetime.mjs 571 B
packages/node/dist/extensions/context/listeners.js 2.35 kB
packages/node/dist/extensions/context/listeners.mjs 788 B
packages/node/dist/extensions/context/span-context.node.js 1.8 kB
packages/node/dist/extensions/context/span-context.node.mjs 355 B
packages/node/dist/extensions/context/types.js 585 B
packages/node/dist/extensions/context/types.mjs 12 B
packages/node/dist/extensions/error-tracking/autocapture.js 17.6 kB
packages/node/dist/extensions/error-tracking/autocapture.mjs 15.7 kB
packages/node/dist/extensions/error-tracking/index.js 5.5 kB
packages/node/dist/extensions/error-tracking/index.mjs 4.1 kB
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.js 11.7 kB
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs 9.64 kB
packages/node/dist/extensions/error-tracking/modifiers/module.node.js 2.87 kB
packages/node/dist/extensions/error-tracking/modifiers/module.node.mjs 1.45 kB
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.js 2.07 kB
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.mjs 624 B
packages/node/dist/extensions/error-tracking/trace-context.js 2.25 kB
packages/node/dist/extensions/error-tracking/trace-context.mjs 913 B
packages/node/dist/extensions/express.js 6.42 kB
packages/node/dist/extensions/express.mjs 4.07 kB
packages/node/dist/extensions/feature-flags/cache.js 585 B
packages/node/dist/extensions/feature-flags/cache.mjs 12 B
packages/node/dist/extensions/feature-flags/crypto.js 1.37 kB
packages/node/dist/extensions/feature-flags/crypto.mjs 42 B
packages/node/dist/extensions/feature-flags/feature-flags.js 44.7 kB
packages/node/dist/extensions/feature-flags/feature-flags.mjs 42 kB
packages/node/dist/extensions/nestjs.js 5.97 kB
packages/node/dist/extensions/nestjs.mjs 3.62 kB
packages/node/dist/extensions/sentry-integration.js 4.99 kB
packages/node/dist/extensions/sentry-integration.mjs 3.37 kB
packages/node/dist/extensions/tracing-headers.js 6.85 kB
packages/node/dist/extensions/tracing-headers.mjs 4.61 kB
packages/node/dist/extensions/url-utils.js 2.32 kB
packages/node/dist/extensions/url-utils.mjs 785 B
packages/node/dist/feature-flag-evaluations.js 6.72 kB
packages/node/dist/feature-flag-evaluations.mjs 5.24 kB
packages/node/dist/gzip.node.js 1.83 kB
packages/node/dist/gzip.node.mjs 416 B
packages/node/dist/host-os.node.js 1.8 kB
packages/node/dist/host-os.node.mjs 349 B
packages/node/dist/storage-memory.js 1.61 kB
packages/node/dist/storage-memory.mjs 297 B
packages/node/dist/types.js 1.59 kB
packages/node/dist/types.mjs 292 B
packages/node/dist/version.js 1.31 kB
packages/node/dist/version.mjs 46 B
packages/nuxt/dist/module.mjs 8.05 kB
packages/nuxt/dist/runtime/composables/useFeatureFlagEnabled.js 566 B
packages/nuxt/dist/runtime/composables/useFeatureFlagPayload.js 690 B
packages/nuxt/dist/runtime/composables/useFeatureFlagVariantKey.js 591 B
packages/nuxt/dist/runtime/composables/usePostHog.js 128 B
packages/nuxt/dist/runtime/nitro-plugin-v2.js 817 B
packages/nuxt/dist/runtime/nitro-plugin-v3.js 893 B
packages/nuxt/dist/runtime/nitro-plugin.js 3.14 kB
packages/nuxt/dist/runtime/server-client.js 32 B
packages/nuxt/dist/runtime/server.js 127 B
packages/nuxt/dist/runtime/vue-plugin.js 1.13 kB
packages/openfeature-node-provider/dist/index.js 1.86 kB
packages/openfeature-node-provider/dist/index.mjs 122 B
packages/openfeature-node-provider/dist/mapping.js 5.66 kB
packages/openfeature-node-provider/dist/mapping.mjs 3.5 kB
packages/openfeature-node-provider/dist/provider.js 4.08 kB
packages/openfeature-node-provider/dist/provider.mjs 2.59 kB
packages/openfeature-web-provider/dist/index.js 1.84 kB
packages/openfeature-web-provider/dist/index.mjs 119 B
packages/openfeature-web-provider/dist/mapping.js 5.38 kB
packages/openfeature-web-provider/dist/mapping.mjs 3.18 kB
packages/openfeature-web-provider/dist/provider.js 4.51 kB
packages/openfeature-web-provider/dist/provider.mjs 3.06 kB
packages/plugin-utils/dist/chunk-ids.js 3.96 kB
packages/plugin-utils/dist/chunk-ids.mjs 2.11 kB
packages/plugin-utils/dist/cli.js 4.47 kB
packages/plugin-utils/dist/cli.mjs 2.72 kB
packages/plugin-utils/dist/config.js 3.6 kB
packages/plugin-utils/dist/config.mjs 2.25 kB
packages/plugin-utils/dist/index.js 4.5 kB
packages/plugin-utils/dist/index.mjs 197 B
packages/plugin-utils/dist/spawn-local.js 3.17 kB
packages/plugin-utils/dist/spawn-local.mjs 1.66 kB
packages/plugin-utils/dist/utils.js 3.36 kB
packages/plugin-utils/dist/utils.mjs 1.3 kB
packages/react-native/dist/autocapture.js 8.42 kB
packages/react-native/dist/error-tracking/exception-context.js 2.25 kB
packages/react-native/dist/error-tracking/fatal-payload.js 6.61 kB
packages/react-native/dist/error-tracking/index.js 17.2 kB
packages/react-native/dist/error-tracking/utils.js 6.03 kB
packages/react-native/dist/frameworks/wix-navigation.js 1.35 kB
packages/react-native/dist/hooks/useFeatureFlag.js 1.9 kB
packages/react-native/dist/hooks/useFeatureFlagResult.js 1.03 kB
packages/react-native/dist/hooks/useFeatureFlags.js 985 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.31 kB
packages/react-native/dist/hooks/usePostHog.js 583 B
packages/react-native/dist/hooks/utils.js 1.02 kB
packages/react-native/dist/index.js 4.36 kB
packages/react-native/dist/logs-defaults.js 3.71 kB
packages/react-native/dist/native-deps.js 9.57 kB
packages/react-native/dist/optional/OptionalAsyncStorage.js 348 B
packages/react-native/dist/optional/OptionalExpoApplication.js 429 B
packages/react-native/dist/optional/OptionalExpoDevice.js 394 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 437 B
packages/react-native/dist/optional/OptionalExpoFileSystemLegacy.js 480 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 436 B
packages/react-native/dist/optional/OptionalExpoUpdates.js 382 B
packages/react-native/dist/optional/OptionalPlugin.js 1.36 kB
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 473 B
packages/react-native/dist/optional/OptionalReactNativeExceptionsManager.js 626 B
packages/react-native/dist/optional/OptionalReactNativeExceptionsManager.web.js 287 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 359 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 473 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 504 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 700 B
packages/react-native/dist/optional/OptionalReactNativeSvg.js 923 B
packages/react-native/dist/posthog-rn.js 97.6 kB
packages/react-native/dist/PostHogContext.js 372 B
packages/react-native/dist/PostHogErrorBoundary.js 3.98 kB
packages/react-native/dist/PostHogMaskView.js 1.72 kB
packages/react-native/dist/PostHogProvider.js 6.15 kB
packages/react-native/dist/storage.js 6.85 kB
packages/react-native/dist/surveys/components/BottomSection.js 1.69 kB
packages/react-native/dist/surveys/components/Cancel.js 1.19 kB
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.99 kB
packages/react-native/dist/surveys/components/IntroMessage.js 1.87 kB
packages/react-native/dist/surveys/components/QuestionHeader.js 1.69 kB
packages/react-native/dist/surveys/components/QuestionTypes.js 16.1 kB
packages/react-native/dist/surveys/components/SurveyModal.js 7.95 kB
packages/react-native/dist/surveys/components/Surveys.js 8.7 kB
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 3.42 kB
packages/react-native/dist/surveys/icons.js 10.1 kB
packages/react-native/dist/surveys/index.js 634 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 12.7 kB
packages/react-native/dist/surveys/safeStyleSheet.js 491 B
packages/react-native/dist/surveys/survey-progress.js 7.8 kB
packages/react-native/dist/surveys/survey-shuffling.js 2.38 kB
packages/react-native/dist/surveys/survey-translations.js 1.22 kB
packages/react-native/dist/surveys/surveys-utils.js 12 kB
packages/react-native/dist/surveys/useActivatedSurveys.js 3.89 kB
packages/react-native/dist/surveys/useSurveyStorage.js 3.07 kB
packages/react-native/dist/tooling/expoconfig.js 42.3 kB
packages/react-native/dist/tooling/metroconfig.js 2.36 kB
packages/react-native/dist/tooling/posthogMetroSerializer.js 7.5 kB
packages/react-native/dist/tooling/utils.js 4.49 kB
packages/react-native/dist/tooling/vendor/expo/expoconfig.js 109 B
packages/react-native/dist/tooling/vendor/metro/countLines.js 276 B
packages/react-native/dist/tooling/vendor/metro/utils.js 3.61 kB
packages/react-native/dist/types.js 104 B
packages/react-native/dist/utils.js 1.83 kB
packages/react-native/dist/version.js 166 B
packages/react/dist/esm/index.js 23.3 kB
packages/react/dist/esm/slim/index.js 19.5 kB
packages/react/dist/esm/surveys/index.js 4.22 kB
packages/react/dist/umd/index.js 27.8 kB
packages/react/dist/umd/slim/index.js 23.5 kB
packages/react/dist/umd/surveys/index.js 6.33 kB
packages/rollup-plugin/dist/chunk-fingerprint.js 2.77 kB
packages/rollup-plugin/dist/index.js 14.9 kB
packages/rrweb/all/dist/rrweb-all.cjs 670 kB
packages/rrweb/all/dist/rrweb-all.js 669 kB
packages/rrweb/all/dist/rrweb-all.umd.cjs 699 kB
packages/rrweb/all/dist/rrweb-all.umd.min.cjs 345 kB
packages/rrweb/packer/dist/browser-********.cjs 17.9 kB
packages/rrweb/packer/dist/browser-********.js 17.5 kB
packages/rrweb/packer/dist/pack.cjs 401 B
packages/rrweb/packer/dist/pack.js 301 B
packages/rrweb/packer/dist/pack.umd.cjs 1.67 kB
packages/rrweb/packer/dist/pack.umd.min.cjs 1.11 kB
packages/rrweb/packer/dist/packer.cjs 276 B
packages/rrweb/packer/dist/packer.js 133 B
packages/rrweb/packer/dist/packer.umd.cjs 694 B
packages/rrweb/packer/dist/packer.umd.min.cjs 626 B
packages/rrweb/packer/dist/unpack.cjs 737 B
packages/rrweb/packer/dist/unpack.js 637 B
packages/rrweb/packer/dist/unpack.umd.cjs 1.14 kB
packages/rrweb/packer/dist/unpack.umd.min.cjs 953 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.cjs 34.9 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.js 34.8 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.cjs 37 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.min.cjs 22.9 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.cjs 31.8 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.js 31.7 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.cjs 33.7 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.min.cjs 21.1 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.cjs 16.7 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.js 16.6 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.cjs 15.9 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.min.cjs 8.57 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.cjs 6.25 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.js 6.15 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.cjs 6.5 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.min.cjs 3.57 kB
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.cjs 663 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.js 540 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.cjs 1.1 kB
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.min.cjs 827 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.cjs 816 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.js 715 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.cjs 1.25 kB
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.min.cjs 966 B
packages/rrweb/record/dist/rrweb-record.cjs 238 kB
packages/rrweb/record/dist/rrweb-record.js 237 kB
packages/rrweb/record/dist/rrweb-record.umd.cjs 242 kB
packages/rrweb/record/dist/rrweb-record.umd.min.cjs 118 kB
packages/rrweb/replay/dist/rrweb-replay.cjs 437 kB
packages/rrweb/replay/dist/rrweb-replay.js 437 kB
packages/rrweb/replay/dist/rrweb-replay.umd.cjs 458 kB
packages/rrweb/replay/dist/rrweb-replay.umd.min.cjs 228 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.cjs 142 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.js 141 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.cjs 155 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.min.cjs 76.4 kB
packages/rrweb/rrdom/dist/rrdom.cjs 168 kB
packages/rrweb/rrdom/dist/rrdom.js 167 kB
packages/rrweb/rrdom/dist/rrdom.umd.cjs 179 kB
packages/rrweb/rrdom/dist/rrdom.umd.min.cjs 86.9 kB
packages/rrweb/rrweb-snapshot/dist/rebuild-********.cjs 133 kB
packages/rrweb/rrweb-snapshot/dist/rebuild-********.js 132 kB
packages/rrweb/rrweb-snapshot/dist/record.cjs 4.48 kB
packages/rrweb/rrweb-snapshot/dist/record.js 3.14 kB
packages/rrweb/rrweb-snapshot/dist/record.umd.cjs 97.3 kB
packages/rrweb/rrweb-snapshot/dist/record.umd.min.cjs 45.6 kB
packages/rrweb/rrweb-snapshot/dist/replay.cjs 1.96 kB
packages/rrweb/rrweb-snapshot/dist/replay.js 1.31 kB
packages/rrweb/rrweb-snapshot/dist/replay.umd.cjs 206 kB
packages/rrweb/rrweb-snapshot/dist/replay.umd.min.cjs 90.9 kB
packages/rrweb/rrweb-snapshot/dist/rrweb-snapshot.cjs 4.76 kB
packages/rrweb/rrweb-snapshot/dist/rrweb-snapshot.js 3.32 kB
packages/rrweb/rrweb-snapshot/dist/rrweb-snapshot.umd.cjs 252 kB
packages/rrweb/rrweb-snapshot/dist/rrweb-snapshot.umd.min.cjs 113 kB
packages/rrweb/rrweb-snapshot/dist/snapshot-********.cjs 37.7 kB
packages/rrweb/rrweb-snapshot/dist/snapshot-CtRtJ-aJ.js 35.6 kB
packages/rrweb/rrweb-snapshot/dist/types-********.cjs 49.9 kB
packages/rrweb/rrweb-snapshot/dist/types-********.js 44.6 kB
packages/rrweb/rrweb/dist/rrweb.cjs 655 kB
packages/rrweb/rrweb/dist/rrweb.js 654 kB
packages/rrweb/rrweb/dist/rrweb.umd.cjs 681 kB
packages/rrweb/rrweb/dist/rrweb.umd.min.cjs 335 kB
packages/rrweb/types/dist/rrweb-types.cjs 5.8 kB
packages/rrweb/types/dist/rrweb-types.js 5.5 kB
packages/rrweb/types/dist/rrweb-types.umd.cjs 6.06 kB
packages/rrweb/types/dist/rrweb-types.umd.min.cjs 2.95 kB
packages/rrweb/utils/dist/rrweb-utils.cjs 10.1 kB
packages/rrweb/utils/dist/rrweb-utils.js 9.5 kB
packages/rrweb/utils/dist/rrweb-utils.umd.cjs 10.2 kB
packages/rrweb/utils/dist/rrweb-utils.umd.min.cjs 5.07 kB
packages/types/dist/capture-log.js 585 B
packages/types/dist/capture-log.mjs 12 B
packages/types/dist/capture-metric.js 1.47 kB
packages/types/dist/capture-metric.mjs 93 B
packages/types/dist/capture.js 585 B
packages/types/dist/capture.mjs 12 B
packages/types/dist/common.js 585 B
packages/types/dist/common.mjs 12 B
packages/types/dist/feature-flags.js 585 B
packages/types/dist/feature-flags.mjs 12 B
packages/types/dist/index.js 1.83 kB
packages/types/dist/index.mjs 137 B
packages/types/dist/posthog-config.js 1.53 kB
packages/types/dist/posthog-config.mjs 209 B
packages/types/dist/posthog.js 585 B
packages/types/dist/posthog.mjs 12 B
packages/types/dist/request.js 585 B
packages/types/dist/request.mjs 12 B
packages/types/dist/segment.js 585 B
packages/types/dist/segment.mjs 12 B
packages/types/dist/session-recording.js 585 B
packages/types/dist/session-recording.mjs 12 B
packages/types/dist/survey.js 585 B
packages/types/dist/survey.mjs 12 B
packages/types/dist/toolbar.js 585 B
packages/types/dist/toolbar.mjs 12 B
packages/types/dist/traces.js 585 B
packages/types/dist/traces.mjs 12 B
packages/types/dist/tree-shakeable.js 585 B
packages/types/dist/tree-shakeable.mjs 12 B
packages/web/dist/index.cjs 9.09 kB
packages/web/dist/index.mjs 8.93 kB
packages/webpack-plugin/dist/config.js 3.55 kB
packages/webpack-plugin/dist/config.mjs 2.48 kB
packages/webpack-plugin/dist/index.js 20.2 kB
packages/webpack-plugin/dist/index.mjs 15.6 kB
tooling/changelog/dist/index.js 399 B
tooling/rollup-utils/dist/index.js 1.17 kB
tooling/sdk-mock-server/dist/decode.js 2.03 kB
tooling/sdk-mock-server/dist/index.js 16 kB
tooling/sdk-mock-server/dist/state.js 3.79 kB

compressed-size-action

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

posthog-js Compliance Report

Date: 2026-11-09 08:42:27 UTC
Duration: 88662ms

✅ 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 ✅ 96ms
Format Validation.Event Has Uuid ✅ 15ms
Format Validation.Event Has Lib Properties ✅ 12ms
Format Validation.Distinct Id Is String Client ✅ 12ms
Format Validation.Token Is Present Client ✅ 13ms
Format Validation.Custom Properties Preserved ✅ 13ms
Format Validation.Event Has Timestamp ✅ 11ms
Retry Behavior.Retries On 503 ✅ 5018ms
Retry Behavior.Does Not Retry On 400 ✅ 2016ms
Retry Behavior.Does Not Retry On 401 ✅ 2030ms
Retry Behavior.Respects Retry After Header ✅ 5015ms
Retry Behavior.Implements Backoff ✅ 15023ms
Retry Behavior.Retries On 500 ✅ 5015ms
Retry Behavior.Retries On 502 ✅ 5015ms
Retry Behavior.Retries On 504 ✅ 5011ms
Retry Behavior.Max Retries Respected ✅ 15025ms
Deduplication.Generates Unique Uuids ✅ 18ms
Deduplication.Preserves Uuid On Retry ✅ 5012ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10020ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5020ms
Deduplication.No Duplicate Events In Batch ✅ 37ms
Deduplication.Different Events Have Different Uuids ✅ 9ms
Batch Format.Flush With No Events Sends Nothing ✅ 5ms
Error Handling.Does Not Retry On 403 ✅ 2011ms
Error Handling.Does Not Retry On 413 ✅ 2013ms
Error Handling.Retries On 408 ✅ 5016ms

@ioannisj
ioannisj marked this pull request as ready for review October 26, 2026 13:04
@ioannisj
ioannisj requested a review from a team as a code owner October 26, 2026 13:04

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Automated advisory code review. Three reproduced regressions from the reviewed patch; the pre-write deletion issue is already described in an existing review thread, so it is not duplicated here.

}

const channel = this._facebookClickIdChannel
this.persistence.refreshMetaIdentifiers()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

blocking: Refresh cookie identifiers before constructing debounced captures — With persistence_save_debounce_ms enabled, removing this refresh leaves a sibling subdomain's cookie identifier unseen while the conversion event is constructed; refreshing on a later flush cannot amend that event. This affects pure-cookie persistence when a new pending $fbc replaces an already-delivered value, and default localStorage+cookie when the cookie fills a missing identifier. Neither receives cross-subdomain storage events to compensate. Reproduction: reproduced — the two cookie-mode cases in review-meta-regressions.test.ts emit no expected $set.$fbc on reviewed head, while the identical tests pass on the merge base.

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

Fixed in ddae297. capture() now calls refreshMetaIdentifiersBeforeCapture() once before the Meta block, so $set.$fbc is built after the cookie is read, whatever the debounce. Pure cookie (and sessionStorage) go through the snapshot-gated refresh, localStorage+cookie goes through the cookie compare, and both only parse when the raw text changed, so it's one document.cookie read per capture and still no persistence parse.

Added both of your cases, pure cookie with a delivered $fbc replaced by a new pending one, and localStorage+cookie filling a missing one, with persistence_save_debounce_ms on.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Reconcile an already-cached identifier before constructing deferred captures

Location: packages/browser/src/posthog-persistence.ts:1384–1392; anchor line 1391, RIGHT. Related fill-only condition: :519.

Change relationship: introduced by the full PR; incompletely repaired by the follow-up.
Severity/disposition: IMPORTANT / REQUIRED.

A tab holding automatically discovered click A can construct a conversion with A after a sibling has durably persisted click B. The merge base constructs that same conversion with B.

This remains reproducible with supported configuration:

{
    persistence: 'localStorage+cookie',
    defaults: '2026-05-30',
    person_profiles: 'always'
}

Those dated defaults select 250 ms persistence debounce and disable cookie-wins precedence (posthog-core.ts:301–305).

Trigger and source explanation

  1. P discovers A from fbclid, captures, and flushes; its identifier is no longer a pending local persistence mutation.
  2. Q discovers B and flushes. Shared localStorage contains B.
  3. P captures a conversion on a clean URL before notification or its next deferred write.
  4. The new pre-capture hybrid branch checks only the shared cookie.
  5. _adoptMetaIdentifiersFromCookie() refuses to replace a key already present in props, leaving cached A.
  6. The conversion is constructed before later write/event reconciliation can adopt B.

“localStorage wins” should select current durable localStorage B here, not stale in-memory A. This is not a conflicting subdomain-cookie case.

The governing contract is established merge-base browser behavior and compatibility-preserving capture semantics. No sdk-spec requirement for synchronous cross-tab freshness is asserted.

Executed public-entry regression

The following is the retained failing case, using real SDK caches, public capture(), automatic URL discovery, and actual jsdom storage:

import { uuidv7 } from '@posthog/browser-common/utils/uuidv7'
import { defaultPostHog } from './helpers/posthog-instance'
import { PERSISTENCE_FACEBOOK_CLICK_ID as FBC } from '../constants'
import type { PostHogConfig } from '../types'

const route = (click?: string) =>
    window.history.replaceState({}, '', click ? `/?fbclid=${click}` : '/')

const init = (token: string, config: Partial<PostHogConfig>) =>
    defaultPostHog().init(token, {
        person_profiles: 'always',
        capture_pageview: false,
        request_batching: false,
        ...config,
    }, uuidv7())!

beforeEach(() => {
    vi.useFakeTimers()
    vi.setSystemTime(new Date('2026-10-26T12:00:00Z'))
    route()
})

afterEach(() => {
    route()
    vi.clearAllTimers()
    vi.useRealTimers()
    vi.restoreAllMocks()
    localStorage.clear()
    sessionStorage.clear()
})

it('uses an automatically discovered sibling click for a later conversion', () => {
    const config = {
        persistence: 'localStorage+cookie',
        defaults: '2026-05-30',
    } as const
    const token = uuidv7()
    const key = `ph_${token}_posthog`
    const p = init(token, config)

    route('first-click')
    expect(p.capture('first automatic click')?.$set?.$fbc)
        .toBe(`fb.1.${Date.now()}.first-click`)
    p.persistence!.flush()
    route()

    const q = init(token, config)
    vi.setSystemTime(Date.now() + 1000)
    route('second-click')
    const expected = `fb.1.${Date.now()}.second-click`
    expect(q.capture('second automatic click')?.$set?.$fbc).toBe(expected)
    q.persistence!.flush()
    expect(JSON.parse(localStorage.getItem(key)!)[FBC].value).toBe(expected)

    route()
    expect(p.capture('conversion on clean URL')?.$set?.$fbc).toBe(expected)
})

Tested with Node 24.13.0, Vitest 1.6.1, and jsdom under equivalent conditions on each pinned revision. Put the regression alongside the existing browser source tests and run from packages/browser:

pnpm exec vitest run src/__tests__/automatic-meta-review.test.ts --maxWorkers=1 --minWorkers=1
Revision Result
Merge base All four automatic cases pass
Previous head All four fail
Current head This case fails; other three pass

Current expected: fb.1.1793016001000.second-click
Current received: fb.1.1793016000000.first-click

The three additional controls—notification first, zero debounce, and cookie-wins mode—pass on both base and head.

Impact, limits, and recommendation

This can send the previous click as a person-property update instead of the newer durable click. Later reconciliation can correct subsequent captures; permanent loss of B, consent bypass, and live Meta misattribution were not demonstrated.

The test models separate SDK caches in one document; no current real multi-document execution is claimed. The queued browser storage-notification contract supports the ordering.

Consider reconciling current durable Meta state before building deferred captures when a sibling change is detected, preserving pending-local priority and configured cookie/localStorage precedence. The solution need not restore unconditional full-entry parsing on unchanged captures.

Retain the automatic cached-A→B test and its three controls alongside the new missing-key and cookie-only cases.

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

Fixed in 10cb54d. refreshMetaIdentifiersBeforeCapture() now also compares the stored text against the snapshot on localStorage and localStorage+cookie, and re-reads the Meta keys when it changed, so a capture can't be built from cached A once B is readable. A pending local change still wins.

An unchanged capture adds raw text reads but no parse. A sibling write costs one parse on localStorage and two on localStorage+cookie, because that store's _parse writes the merged entry back.

I forced this ordering in real tabs too (Chromium 136, Firefox 137, WebKit 18.4, capture before the storage event) and all 24 runs match the merge base. That also narrowed the impact: the previous head only sent stale A while A's request was in flight, otherwise it sent no $fbc and B went out on the next capture.

There's one difference I haven't explained. In a free-running tab loop the merge base stops re-sending an in-flight A and this branch keeps sending it. It's the same value so I think it's harmless, but I haven't traced why.

Added cached A to B, sibling reset and pending-local cases to packages/browser/src/__tests__/capture-hot-path.test.ts for both stores, plus your three controls.

if (!this.persistence) {
return
}
this.persistence.refreshMetaIdentifiers()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

blocking: Reconcile before confirming an old request's identifier — Removing the callback refresh lets an older successful request overwrite a newer sibling identifier before its storage event arrives. The callback sees the stale in-memory identifier, registers it as delivered and marks it locally pending; pre-write reconciliation then skips the newer stored value. This loses the new click and its pending-delivery state rather than merely delaying propagation. Reproduction: reproduced — the delayed-response case in review-meta-regressions.test.ts replaces the newer sibling identifier with the old delivered identifier on reviewed head, while the identical test passes on the merge base.

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

Fixed in ddae297. _markMetaIdentifierDelivered refreshes the Meta identifiers from storage before the compare again, so a newer sibling value fails the stored.value === value check and keeps its pending state instead of being overwritten by the old delivered one.

On localStorage stores that refresh now always parses rather than trusting the snapshot, since the snapshot can't see the cookie half of localStorage+cookie or an A→B→A change. It runs once per confirming response, not per capture. Test covers localStorage and cookie.

// event, the pre-write reconciliation and the cookie compare below. Only the
// cookie store, capped at 4 KB, still re-reads here; sessionStorage and memory
// have no siblings.
if (this._usesCookieMetaIdentifierRefresh()) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

blocking: Preserve sessionStorage synchronization between same-origin frames — Same-origin iframes within one tab share sessionStorage, so this store does have sibling writers. After a frame writes a pending identifier, this instance ignores its storage event because it is not split-storage eligible; with the capture refresh removed and this write refresh now restricted to cookies, the parent's next conversion omits the identifier and can overwrite it with stale state. Keep a reconciliation path for shared sessionStorage. Reproduction: reproduced — the actual-iframe case in review-meta-regressions.test.ts confirms that the parent sees the frame's stored value but omits $set.$fbc on reviewed head, while the identical test passes on the merge base.

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

I had the premise wrong here, same-origin frames share sessionStorage and our listener drops their storage events. Fixed in ddae297: sessionStorage now gets the same snapshot-gated refresh as the cookie store, before capture and before writes, and the snapshot is remembered after our own writes so it doesn't parse on every capture. I fixed the code comment too, and the PR description is next.

Test runs two instances over the shared sessionStorage and checks the second one's next capture sends the first one's $fbc.

@marandaneto
marandaneto requested a review from a team October 27, 2026 13:59

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I independently reproduced the older-response overwrite and deferred-capture freshness issues through automatic fbclid discovery, so I have not duplicated those inline findings. The pre-write deletion/reset gap also still reproduces on this head; details are inline.

All four focused automatic-discovery cases pass on merge base 64f8a4325bde1b2c00338a1c13ba6c9bbbfa9a4f and fail on reviewed head 4e2cc29b40dc74b02883ec5445be3baf6db891df (the acknowledgement case covers both localStorage and cookie). Validation used real SDK instances in jsdom; no real multi-tab browser or live ingestion result is claimed.

AI-assisted review.

// event, the pre-write reconciliation and the cookie compare below. Only the
// cookie store, capped at 4 KB, still re-reads here; sessionStorage and memory
// have no siblings.
if (this._usesCookieMetaIdentifierRefresh()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Reconcile an externally removed entry before rewriting localStorage

A sibling reset() can remove the main localStorage entry while its replacement save is deferred. If this instance captures before that replacement or the storage notification, this new cookie-only refresh gate lets it write its cached Meta identifier back. On the merge base the identifier stays removed; on this head it is restored.

The replacement _reconcileCrossTabFeatureFlagPropertiesBeforeWrite() merges Meta state only in the non-null branch (posthog-persistence.ts:567–568). Its null branch (:562–565) sets mainState.storageValue = null without reconciling Meta keys. The new storage-event null handling (:373–383) therefore fixes only the ordering where notification arrives before the write. It rereads current storage, so notification after resurrection can observe the restored value rather than the earlier deletion.

This is the remaining pre-write part of the earlier removal finding. Reproduced through automatic URL fbclid discovery followed by public SDK reset()/capture() calls:

import { uuidv7 } from '@posthog/browser-common/utils/uuidv7'
import { defaultPostHog } from './helpers/posthog-instance'
import { PERSISTENCE_FACEBOOK_CLICK_ID as FBC } from '../constants'
import type { PostHogConfig } from '../types'

const route = (click?: string) =>
    window.history.replaceState({}, '', click ? `/?fbclid=${click}` : '/')
const init = (token: string, config: Partial<PostHogConfig> = {}) =>
    defaultPostHog().init(token, {
        persistence: 'localStorage',
        person_profiles: 'always',
        capture_pageview: false,
        request_batching: false,
        ...config,
    }, uuidv7())!

beforeEach(() => {
    vi.useFakeTimers()
    vi.setSystemTime(new Date('2026-10-26T12:00:00Z'))
    route()
})
afterEach(() => {
    route()
    vi.clearAllTimers()
    vi.useRealTimers()
    vi.restoreAllMocks()
    localStorage.clear()
    sessionStorage.clear()
})

it('does not resurrect an automatically discovered identifier during sibling reset', () => {
    const token = uuidv7()
    const p = init(token)
    route('first-click')
    expect(p.capture('first automatic click')?.$set?.$fbc)
        .toBe(`fb.1.${Date.now()}.first-click`)
    p.persistence!.flush()
    route()

    const q = init(token, { persistence_save_debounce_ms: 250 })
    q.persistence!.flush()
    q.reset()
    const key = `ph_${token}_posthog`
    expect(localStorage.getItem(key)).toBeNull()

    vi.setSystemTime(Date.now() + 1000)
    const conversion = p.capture('conversion after reset on clean URL')
    expect(JSON.parse(localStorage.getItem(key)!)).not.toHaveProperty(FBC)
    expect(conversion?.$set?.$fbc).toBeUndefined()
})

Executed with Node 24.13.0, Vitest 1.6.1 and jsdom using equivalent dependencies/configuration on merge base 64f8a4325bde1b2c00338a1c13ba6c9bbbfa9a4f and head 4e2cc29b40dc74b02883ec5445be3baf6db891df:

# Place alongside the existing browser source tests, then run from packages/browser:
pnpm exec vitest run src/__tests__/automatic-meta-review.test.ts --maxWorkers=1 --minWorkers=1

Base: passes. Head: fails because the rewritten entry contains { value: 'fb.1.1793016000000.first-click', delivered: false }. A separate removal-before-notification test shows the same differential failure; delivering the keyed removal notification first passes on both revisions. The two named instances model independent caches; these exact orderings were not run in real multi-document browsers. The browser storage broadcast algorithm queues notification after mutation, so another SDK operation can run in this interval.

The observed impact is deleted attribution becoming durable again and potentially being reused; later sibling writes may correct it. This does not establish a consent bypass or a new identity-synchronization defect, and it does not generalize the absent-entry interval to cookie-wins reset configurations that synchronously publish a replacement.

Consider reconciling externally observed absence for Meta keys before writing, preserving pending-local priority and intentional local removal/migration behavior. Keep unrelated feature-flag retention semantics unchanged. Retain the public-reset, removal-before-notification and delivered-notification control cases as regression coverage.

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

Fixed in ddae297. The pre-write null branch now clears non-pending Meta keys when this tab had previously seen an entry (storageValue is a string), so a sibling reset() sticks even if our write lands before the storage event. Feature-flag handling in that branch is unchanged.

A first write can't take that path, since load seeds storageValue with null, so a cookie-only $fbc on first write is kept. Added your reset scenario plus that first-write case as a guard.

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

The rewrite you reported was fixed in ddae297, but the event itself could still carry the cleared $fbc when this tab captured with a debounce on and the storage event hadn't arrived. Same cause as the cached A to B thread, fixed in 10cb54d, the capture now sees the removal before it's built.

Added a sibling reset() case for localStorage and localStorage+cookie.

@dustinbyrne
dustinbyrne requested a review from a team October 27, 2026 14:17
…over sessionStorage frames and sibling reset
@ioannisj ioannisj changed the title fix(browser): adopt sibling Meta identifiers from storage events instead of reading storage on every capture() fix(browser): cut per-capture storage reads for Meta identifiers Oct 29, 2026

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PostHog Review · Standard · reviewed ddae297: 1 Should fix.

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The delayed-acknowledgement and sibling-reset reproductions now pass. The deferred hybrid capture case with an already-cached identifier still fails against the merge base; details are in the existing freshness thread. I also reproduced the batch-confirmation work concern already reported here, but treat that as optional because no latency regression was measured.

AI-assisted review.

@dustinbyrne
dustinbyrne requested a review from a team October 29, 2026 21:04

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The latest callback optimization addresses repeated confirmation work, but the cached-A→B deferred-capture freshness issue still applies on this head. The hybrid pre-capture path fills missing identifiers but does not reconcile an already-cached identifier before constructing the conversion.

Consider addressing that path and adding the cached-state regression before approval.

AI-assisted review.

@dustinbyrne
dustinbyrne requested a review from a team November 3, 2026 20:32
@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

SDK performance: posthog-node

1 change worth reviewing: 1 observed improvement.

Flags require at least a 5% change in the median and all six pairs agreeing on direction. This is a noise filter, not proof of a performance change or a CI gate.

Test Measurement Before PR With PR Change
Queue an event (4,096-byte payload) Allocated memory per operation (estimated) 8.99 KiB/op 8.22 KiB/op 8.6% less memory
View all results
Test Measurement Before PR With PR Change Assessment
Capture and deliver events (32-byte payload, burst)
Shard: capture
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Capture and deliver events (4,096-byte payload, burst)
Shard: capture
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Capture and deliver events (32-byte payload, steady)
Shard: capture
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Capture and deliver events (4,096-byte payload, steady)
Shard: capture
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Queue an event (32-byte payload)
Shard: capture
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Queue an event (4,096-byte payload)
Shard: capture
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate all 10 flags
Shard: flags-scaling
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate all 100 flags
Shard: flags-scaling
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate all 1,000 flags
Shard: flags-scaling
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate one boolean flag
Shard: flags-single
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate a cohort-filtered flag
Shard: flags-single
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate a flag (early match)
Shard: flags-single
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate a flag (late match)
Shard: flags-single
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate a flag (no match)
Shard: flags-single
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate a property-filtered flag
Shard: flags-single
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate a regex-filtered flag
Shard: flags-single
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate a rollout flag
Shard: flags-single
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Evaluate a multivariate flag
Shard: flags-single
Allocations per operation — — — unavailable; base:​ unsupported; head:​ unsupported; base:​ V8 samples do not expose total allocation count; sample count is not object count.​; head:​ V8 samples do not expose total allocation count; sample count is not object count.​
Capture and deliver events (32-byte payload, burst)
Shard: capture
Allocated memory per operation (estimated) 10.19 KiB/op 10.32 KiB/op 1.3% more memory Not flagged
Capture and deliver events (32-byte payload, burst)
Shard: capture
Time per operation 16.41 µs/op 16.24 µs/op 1% less time Not flagged
Capture and deliver events (32-byte payload, burst)
Shard: capture
Idle process memory (RSS) 102.65 MiB 102.74 MiB <0.1% more memory Not flagged
Capture and deliver events (32-byte payload, burst)
Shard: capture
Observed peak process memory (RSS) 106.2 MiB 106.11 MiB <0.1% less memory Not flagged
Capture and deliver events (32-byte payload, burst)
Shard: capture
Managed heap after settling 9.96 MiB 9.96 MiB <0.1% less memory Not flagged
Capture and deliver events (32-byte payload, burst)
Shard: capture
Process memory after settling (RSS) 105.88 MiB 105.79 MiB <0.1% less memory Not flagged
Capture and deliver events (32-byte payload, burst)
Shard: capture
Process CPU time per operation 28.5 µs/op 27.84 µs/op 2.3% less time Not flagged
Capture and deliver events (32-byte payload, burst)
Shard: capture
Lifetime peak process memory (RSS) 106.47 MiB 106.36 MiB 0.1% less memory Not flagged
Capture and deliver events (4,096-byte payload, burst)
Shard: capture
Allocated memory per operation (estimated) 17.33 KiB/op 17.82 KiB/op 2.8% more memory Not flagged
Capture and deliver events (4,096-byte payload, burst)
Shard: capture
Time per operation 29.72 µs/op 29.63 µs/op 0.3% less time Not flagged
Capture and deliver events (4,096-byte payload, burst)
Shard: capture
Idle process memory (RSS) 103.27 MiB 103.25 MiB <0.1% less memory Not flagged
Capture and deliver events (4,096-byte payload, burst)
Shard: capture
Observed peak process memory (RSS) 113.75 MiB 113.51 MiB 0.2% less memory Not flagged
Capture and deliver events (4,096-byte payload, burst)
Shard: capture
Managed heap after settling 9.97 MiB 9.96 MiB <0.1% less memory Not flagged
Capture and deliver events (4,096-byte payload, burst)
Shard: capture
Process memory after settling (RSS) 109.62 MiB 109.45 MiB 0.2% less memory Not flagged
Capture and deliver events (4,096-byte payload, burst)
Shard: capture
Process CPU time per operation 43.23 µs/op 42.36 µs/op 2% less time Not flagged
Capture and deliver events (4,096-byte payload, burst)
Shard: capture
Lifetime peak process memory (RSS) 116.54 MiB 116.29 MiB 0.2% less memory Not flagged
Capture and deliver events (32-byte payload, steady)
Shard: capture
Allocated memory per operation (estimated) 10.3 KiB/op 10.58 KiB/op 2.7% more memory Not flagged
Capture and deliver events (32-byte payload, steady)
Shard: capture
Time per operation 17.45 µs/op 17.41 µs/op 0.2% less time Not flagged
Capture and deliver events (32-byte payload, steady)
Shard: capture
Idle process memory (RSS) 102.46 MiB 102.49 MiB <0.1% more memory Not flagged
Capture and deliver events (32-byte payload, steady)
Shard: capture
Observed peak process memory (RSS) 106.8 MiB 106.36 MiB 0.4% less memory Not flagged
Capture and deliver events (32-byte payload, steady)
Shard: capture
Managed heap after settling 10.04 MiB 10.03 MiB <0.1% less memory Not flagged
Capture and deliver events (32-byte payload, steady)
Shard: capture
Process memory after settling (RSS) 106.86 MiB 106.43 MiB 0.4% less memory Not flagged
Capture and deliver events (32-byte payload, steady)
Shard: capture
Process CPU time per operation 30.37 µs/op 30.24 µs/op 0.4% less time Not flagged
Capture and deliver events (32-byte payload, steady)
Shard: capture
Lifetime peak process memory (RSS) 106.87 MiB 106.75 MiB 0.1% less memory Not flagged
Capture and deliver events (4,096-byte payload, steady)
Shard: capture
Allocated memory per operation (estimated) 17.82 KiB/op 17.81 KiB/op <0.1% less memory Not flagged
Capture and deliver events (4,096-byte payload, steady)
Shard: capture
Time per operation 25.43 µs/op 25.95 µs/op 2.1% more time Not flagged
Capture and deliver events (4,096-byte payload, steady)
Shard: capture
Idle process memory (RSS) 102.85 MiB 102.76 MiB <0.1% less memory Not flagged
Capture and deliver events (4,096-byte payload, steady)
Shard: capture
Observed peak process memory (RSS) 109.38 MiB 109.12 MiB 0.2% less memory Not flagged
Capture and deliver events (4,096-byte payload, steady)
Shard: capture
Managed heap after settling 10.04 MiB 10.04 MiB <0.1% less memory Not flagged
Capture and deliver events (4,096-byte payload, steady)
Shard: capture
Process memory after settling (RSS) 108.21 MiB 107.92 MiB 0.3% less memory Not flagged
Capture and deliver events (4,096-byte payload, steady)
Shard: capture
Process CPU time per operation 38.66 µs/op 39.17 µs/op 1.3% more time Not flagged
Capture and deliver events (4,096-byte payload, steady)
Shard: capture
Lifetime peak process memory (RSS) 109.41 MiB 109.16 MiB 0.2% less memory Not flagged
Queue an event (32-byte payload)
Shard: capture
Allocated memory per operation (estimated) 9.2 KiB/op 9.26 KiB/op 0.6% more memory Not flagged
Queue an event (32-byte payload)
Shard: capture
Time per operation 12.38 µs/op 12.45 µs/op 0.5% more time Not flagged
Queue an event (32-byte payload)
Shard: capture
Process CPU time per operation 24.38 µs/op 24.52 µs/op 0.6% more time Not flagged
Queue an event (4,096-byte payload)
Shard: capture
Allocated memory per operation (estimated) 8.99 KiB/op 8.22 KiB/op 8.6% less memory Worth reviewing: observed improvement
Queue an event (4,096-byte payload)
Shard: capture
Time per operation 11.53 µs/op 11.8 µs/op 2.4% more time Not flagged
Queue an event (4,096-byte payload)
Shard: capture
Process CPU time per operation 21.25 µs/op 23.32 µs/op 9.7% more time Not flagged
Evaluate all 10 flags
Shard: flags-scaling
Allocated memory per operation (estimated) 133.43 KiB/op 132.96 KiB/op 0.4% less memory Not flagged
Evaluate all 10 flags
Shard: flags-scaling
Time per operation 141.09 µs/op 138.06 µs/op 2.2% less time Not flagged
Evaluate all 10 flags
Shard: flags-scaling
Process CPU time per operation 247.02 µs/op 244.12 µs/op 1.2% less time Not flagged
Evaluate all 100 flags
Shard: flags-scaling
Allocated memory per operation (estimated) 1.23 MiB/op 1.23 MiB/op 0.5% more memory Not flagged
Evaluate all 100 flags
Shard: flags-scaling
Time per operation 1.22 ms/op 1.26 ms/op 3.3% more time Not flagged
Evaluate all 100 flags
Shard: flags-scaling
Process CPU time per operation 2.11 ms/op 2.15 ms/op 2% more time Not flagged
Evaluate all 1,000 flags
Shard: flags-scaling
Allocated memory per operation (estimated) 12.13 MiB/op 12.1 MiB/op 0.2% less memory Not flagged
Evaluate all 1,000 flags
Shard: flags-scaling
Time per operation 13.65 ms/op 13.93 ms/op 2.1% more time Not flagged
Evaluate all 1,000 flags
Shard: flags-scaling
Process CPU time per operation 21.86 ms/op 22.31 ms/op 2% more time Not flagged
Evaluate 1,000 flags under concurrent load
Shard: flags-memory
Idle process memory (RSS) 273.09 MiB 272.95 MiB <0.1% less memory Not flagged
Evaluate 1,000 flags under concurrent load
Shard: flags-memory
Observed peak process memory (RSS) 273.18 MiB 272.95 MiB <0.1% less memory Not flagged
Evaluate 1,000 flags under concurrent load
Shard: flags-memory
Managed heap after settling 9.61 MiB 9.61 MiB <0.1% less memory Not flagged
Evaluate 1,000 flags under concurrent load
Shard: flags-memory
Process memory after settling (RSS) 272.66 MiB 272.33 MiB 0.1% less memory Not flagged
Evaluate 1,000 flags under concurrent load
Shard: flags-memory
Lifetime peak process memory (RSS) 274.31 MiB 274.17 MiB <0.1% less memory Not flagged
Refresh 1,000 flag definitions
Shard: flags-memory
Idle process memory (RSS) 227.55 MiB 227.28 MiB 0.1% less memory Not flagged
Refresh 1,000 flag definitions
Shard: flags-memory
Observed peak process memory (RSS) 239.74 MiB 239.57 MiB <0.1% less memory Not flagged
Refresh 1,000 flag definitions
Shard: flags-memory
Managed heap after settling 11.62 MiB 11.62 MiB <0.1% less memory Not flagged
Refresh 1,000 flag definitions
Shard: flags-memory
Process memory after settling (RSS) 235.18 MiB 234.62 MiB 0.2% less memory Not flagged
Refresh 1,000 flag definitions
Shard: flags-memory
Lifetime peak process memory (RSS) 241.89 MiB 241.27 MiB 0.3% less memory Not flagged
Evaluate one boolean flag
Shard: flags-single
Allocated memory per operation (estimated) 17.22 KiB/op 17.16 KiB/op 0.3% less memory Not flagged
Evaluate one boolean flag
Shard: flags-single
Time per operation 91.36 µs/op 91.21 µs/op 0.2% less time Not flagged
Evaluate one boolean flag
Shard: flags-single
Process CPU time per operation 99.21 µs/op 98.88 µs/op 0.3% less time Not flagged
Evaluate a cohort-filtered flag
Shard: flags-single
Allocated memory per operation (estimated) 14.22 KiB/op 14.05 KiB/op 1.2% less memory Not flagged
Evaluate a cohort-filtered flag
Shard: flags-single
Time per operation 49.17 µs/op 49.24 µs/op 0.1% more time Not flagged
Evaluate a cohort-filtered flag
Shard: flags-single
Process CPU time per operation 57.11 µs/op 57.33 µs/op 0.4% more time Not flagged
Evaluate a flag (early match)
Shard: flags-single
Allocated memory per operation (estimated) 17.7 KiB/op 17.76 KiB/op 0.4% more memory Not flagged
Evaluate a flag (early match)
Shard: flags-single
Time per operation 50.83 µs/op 50.16 µs/op 1.3% less time Not flagged
Evaluate a flag (early match)
Shard: flags-single
Process CPU time per operation 58.37 µs/op 57.57 µs/op 1.4% less time Not flagged
Evaluate a flag (late match)
Shard: flags-single
Allocated memory per operation (estimated) 22.28 KiB/op 22.45 KiB/op 0.8% more memory Not flagged
Evaluate a flag (late match)
Shard: flags-single
Time per operation 52.19 µs/op 50.81 µs/op 2.6% less time Not flagged
Evaluate a flag (late match)
Shard: flags-single
Process CPU time per operation 60.13 µs/op 58.25 µs/op 3.1% less time Not flagged
Evaluate a flag (no match)
Shard: flags-single
Allocated memory per operation (estimated) 16.91 KiB/op 17 KiB/op 0.5% more memory Not flagged
Evaluate a flag (no match)
Shard: flags-single
Time per operation 5.68 µs/op 5.73 µs/op 1% more time Not flagged
Evaluate a flag (no match)
Shard: flags-single
Process CPU time per operation 10.31 µs/op 10.28 µs/op 0.4% less time Not flagged
Evaluate a property-filtered flag
Shard: flags-single
Allocated memory per operation (estimated) 12.68 KiB/op 12.71 KiB/op 0.3% more memory Not flagged
Evaluate a property-filtered flag
Shard: flags-single
Time per operation 49.87 µs/op 49.75 µs/op 0.2% less time Not flagged
Evaluate a property-filtered flag
Shard: flags-single
Process CPU time per operation 57.27 µs/op 57.01 µs/op 0.5% less time Not flagged
Evaluate a regex-filtered flag
Shard: flags-single
Allocated memory per operation (estimated) 18.28 KiB/op 18.25 KiB/op 0.2% less memory Not flagged
Evaluate a regex-filtered flag
Shard: flags-single
Time per operation 97.07 µs/op 98.02 µs/op 1% more time Not flagged
Evaluate a regex-filtered flag
Shard: flags-single
Process CPU time per operation 106.73 µs/op 107.54 µs/op 0.8% more time Not flagged
Evaluate a rollout flag
Shard: flags-single
Allocated memory per operation (estimated) 14.3 KiB/op 14.31 KiB/op <0.1% more memory Not flagged
Evaluate a rollout flag
Shard: flags-single
Time per operation 70.15 µs/op 69.91 µs/op 0.3% less time Not flagged
Evaluate a rollout flag
Shard: flags-single
Process CPU time per operation 77.37 µs/op 76.85 µs/op 0.7% less time Not flagged
Evaluate a multivariate flag
Shard: flags-single
Allocated memory per operation (estimated) 17.54 KiB/op 17.4 KiB/op 0.8% less memory Not flagged
Evaluate a multivariate flag
Shard: flags-single
Time per operation 92.42 µs/op 92.86 µs/op 0.5% more time Not flagged
Evaluate a multivariate flag
Shard: flags-single
Process CPU time per operation 100.53 µs/op 101.52 µs/op 1% more time Not flagged

Values are medians of paired measurements. Not flagged does not mean unchanged. Unavailable means a measurement could not be provided, not zero. Estimated allocation measurements retain their instrumentation uncertainty. RSS measures the whole process, not just SDK allocations; observed peaks are sampled checkpoints. Paired ranges in the diagnostics describe variability, not confidence intervals.

Each shard uses its own runner; compare Before PR against With PR within a row, not across shards.

Compared 6428f1664a82657b290647f661a2f39c44ff8d1f → 62c156d07fc777f8673e6018c6dbfbc0a6fae738.

Full report and diagnostics

102 metric rows; 102 rows shown in all results. Omitted or shortened data remain in comparison.json, including per-runner environments, resource limits, measurement methods, samples and checkpoints.

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The cached-identifier localStorage/hybrid freshness issue is addressed, including capture before the storage event and sibling reset. I have one non-blocking compatibility note about same-namespace memory clients.

AI-assisted review.


// The cookie store and sessionStorage (shared by same-origin frames) get no storage event.
private _usesMetaIdentifierSnapshotRefresh(): boolean {
return this._storage === cookieStore || this._storage === sessionStore

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

M1. [P2] Include shared memory clients in the Meta refresh path

  • Location: packages/browser/src/posthog-persistence.ts:1402, RIGHT; related gates at lines 1395–1407 and 1473.
  • Severity / disposition: MINOR / OPTIONAL.
  • Change relationship: Introduced by the full PR, already present at the previous reviewed head; newly identified in this follow-up, not introduced by the latest main merge.
  • Evidence: Source-supported differential behavior; the regression sketch below was not executed.

Memory persistence can have another writer in the same JavaScript module: memoryStore uses a module-level map keyed by persistence name (storage.ts:582–611). Named init() is supported (posthog-core.ts:800–830), and the persistence name depends on the token or persistence_name, not the instance name (posthog-persistence.ts:99–110).

For two named clients using the same token and persistence: 'memory':

  1. Initialize both clients.
  2. P discovers click A, captures, and flushes persistence.
  3. Q discovers click B, captures, and flushes persistence.
  4. P captures a conversion on a clean URL before either request is confirmed.

The merge base refreshes P’s Meta state from the shared memory entry and constructs the conversion with B. On this head, memory is excluded from both the pre-capture classifier and the pre-write refresh gate (posthog-persistence.ts:1388–1407, :1473), so P retains and emits A.

The same exclusion can leave P repeating A after Q has confirmed the identical value and flushed its delivered state.

On base, identifier calculation calls refreshMetaIdentifiers() before reading cached state (posthog-core.ts:1673,1722). Memory’s object-valued _get() produces no string snapshot, so _refreshKeys() reads the current shared entry (posthog-persistence.ts:1269–1293). On head, those calculation-time calls are removed and memory does not qualify for their replacements. Loading copies the top-level props dictionary, and channel registration replaces the Meta object (posthog-persistence.ts:1162; posthog-core.ts:1607–1628), so Q’s update does not simply mutate P’s cache. P’s successful flush also clears its pending-local guard; an unconfirmed network request does not keep that guard set.

This is a narrow same-module/same-namespace configuration—not memory shared across tabs, and not a failure of ordinary single-instance memory persistence. The compatibility evidence is merge-base behavior; neither the public docs nor the inspected sdk-specs promise general cross-instance memory synchronization. The source-inferred impact is stale or redundant Meta person-property enrichment, not a dropped event, consent bypass, permanent attribution loss, or observed live Meta misattribution.

Consider retaining the existing memory refresh path and adding the regression controls below. Including the resolved memoryStore in the current classifier would preserve the pending-local guard and perform an object lookup, without JSON parsing or browser-storage I/O.

Test sketch (not executed): the test below predicts base success and head failure for memory A→B and sibling-confirmation cases. SessionStorage and pending-local controls should pass on both. Execution could not be completed: Docker is unavailable and the available sandbox mechanism aborts before establishing an execution environment.

Exact regression sketch — not executed

Place at packages/browser/src/__tests__/memory-meta-review.test.ts in isolated validation copies. Both clients initialize before attribution is discovered; capture assertions distinguish a missing identifier from a dropped event.

import { uuidv7 } from '@posthog/browser-common/utils/uuidv7'
import { defaultPostHog } from './helpers/posthog-instance'
import type { PostHog } from '../posthog-core'
import type { PostHogConfig } from '../types'

type Persistence = 'memory' | 'sessionStorage'

const originalUrl = window.location.href

const route = (click?: string) =>
    window.history.replaceState(null, '', click ? `/?fbclid=${click}` : '/')

const captureFbc = (posthog: PostHog, event: string) => {
    const result = posthog.capture(event)
    expect(result?.event).toBe(event)
    return result?.$set?.$fbc
}

const init = (token: string, persistence: Persistence) => {
    const config: Partial<PostHogConfig> = {
        persistence,
        persistence_save_debounce_ms: 250,
        person_profiles: 'always',
        bootstrap: { distinctID: 'shared-review-visitor' },
        capture_pageview: false,
        autocapture: false,
        disable_session_recording: true,
        disable_surveys: true,
        disable_conversations: true,
        advanced_disable_flags: true,
        request_batching: false,
        rate_limiting: {
            events_per_second: 1000,
            events_burst_limit: 1000,
        },
    }

    const posthog = defaultPostHog().init(token, config, uuidv7())
    const responses: (() => void)[] = []

    vi.spyOn(posthog, '_send_retriable_request').mockImplementation((options) => {
        responses.push(() => options.callback?.({ statusCode: 200 }))
    })

    posthog.persistence!.flush()
    return { posthog, responses }
}

const pair = (persistence: Persistence) => {
    const token = uuidv7()
    const p = init(token, persistence)
    const q = init(token, persistence)
    return { p, q }
}

beforeEach(() => {
    vi.useFakeTimers()
    vi.setSystemTime(new Date('2026-10-26T12:00:00Z'))
    route()
    document.cookie = '_fbc=; Max-Age=0; path=/'
    document.cookie = '_fbp=; Max-Age=0; path=/'
})

afterEach(() => {
    window.history.replaceState(null, '', originalUrl)
    vi.clearAllTimers()
    vi.useRealTimers()
    vi.restoreAllMocks()
    localStorage.clear()
    sessionStorage.clear()
})

describe.each(['memory', 'sessionStorage'] as const)(
    'shared named-instance Meta state: %s',
    (persistence) => {
        it('uses a sibling’s newer automatically discovered click', () => {
            const { p, q } = pair(persistence)

            route('click-a')
            const a = captureFbc(p.posthog, 'landing A')
            expect(a).toMatch(/\.click-a$/)
            p.posthog.persistence!.flush()

            vi.setSystemTime(Date.now() + 1000)
            route('click-b')
            const b = captureFbc(q.posthog, 'landing B')
            expect(b).toMatch(/\.click-b$/)
            q.posthog.persistence!.flush()

            route()
            expect(captureFbc(p.posthog, 'conversion')).toBe(b)
        })

        it('observes a sibling’s confirmation of the identical value', () => {
            const { p, q } = pair(persistence)

            route('click-a')
            const a = captureFbc(p.posthog, 'landing A')
            expect(a).toMatch(/\.click-a$/)
            p.posthog.persistence!.flush()

            // Keep the same URL and fixed clock. Q must actually send A.
            expect(captureFbc(q.posthog, 'sibling delivery')).toBe(a)
            expect(q.responses.length).toBeGreaterThan(0)
            q.responses.forEach((respond) => respond())
            q.posthog.persistence!.flush()

            // P's own response remains withheld.
            route()
            expect(captureFbc(p.posthog, 'after confirmation')).toBeUndefined()
        })

        it('preserves a newer local change awaiting its write', () => {
            const { p, q } = pair(persistence)

            route('click-a')
            expect(captureFbc(p.posthog, 'landing A')).toMatch(/\.click-a$/)
            p.posthog.persistence!.flush()

            vi.setSystemTime(Date.now() + 1000)
            route('click-b')
            expect(captureFbc(q.posthog, 'landing B')).toMatch(/\.click-b$/)
            q.posthog.persistence!.flush()

            vi.setSystemTime(Date.now() + 1000)
            route('local-click')
            const local = captureFbc(p.posthog, 'local landing')
            expect(local).toMatch(/\.local-click$/)

            // No flush of P's newer local change.
            route()
            expect(captureFbc(p.posthog, 'local conversion')).toBe(local)
        })
    }
)

it('stops enrichment after ordinary single-instance memory delivery', () => {
    const p = init(uuidv7(), 'memory')

    route('click-a')
    expect(captureFbc(p.posthog, 'landing')).toMatch(/\.click-a$/)
    expect(p.responses.length).toBeGreaterThan(0)
    p.responses.forEach((respond) => respond())
    p.posthog.persistence!.flush()

    route()
    expect(captureFbc(p.posthog, 'after delivery')).toBeUndefined()
})

In equivalent disposable copies of base 6428f1664a82657b290647f661a2f39c44ff8d1f and head bc83272120b0eeb7f06553e67b54bd098e52f802, with matching audited dependencies and Node 24:

# Bootstrap workspace prerequisites at each repository root:
pnpm turbo run build --filter=posthog-js

# From packages/browser:
pnpm exec vitest run src/__tests__/memory-meta-review.test.ts \
  --maxWorkers=1 --minWorkers=1
Case Base — source-inferred Head — source-inferred
Memory A→B Conversion carries B Conversion carries A
Memory sibling confirms A Omits $fbc Repeats A
Memory pending-local priority Keeps local value Keeps local value
SessionStorage controls Pass Pass
Ordinary single memory client Pass Pass

Executed results / exit codes: none. This sketch and the suggested correction were not executed. Docker is unavailable and sandbox-exec aborts with exit 134 even for /usr/bin/true, so no credential-isolated execution environment was established.

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

Fixed in 62c156d. Memory now goes through the same refresh as cookie and sessionStorage before capture and before writes, so a sibling's $fbc (or its confirmation) is picked up. It's an object lookup on memoryStore, no parse, so the hot path matrix still shows 0 parses for memory.

With memory in, _tracksMetaIdentifierStorageSnapshot was true for every store, so I dropped it. Added your three cases (newer sibling click, sibling confirmation, pending local change) to capture-hot-path.test.ts.

@veria-ai

veria-ai Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Reviews

@ioannisj
ioannisj added this pull request to the merge queue Nov 9, 2026
Merged via the queue into main with commit 7ceaa14 Nov 9, 2026
73 checks passed
@ioannisj
ioannisj deleted the fix/meta-identifier-storage-event branch November 9, 2026 09:40
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.

3 participants