Skip to content

Conversation

lucasheriques
Copy link
Contributor

Problem

Closes #1898

Changes

Surveys used to rely on localStorage directly to manage some properties we use for our functionality (surveySeen, lastSeenSurvey, and inProgressSurvey).

Now, instead, we use posthog.persistence, but maintain backwards compatibility by using localStorage if persistence is disabled. This is necessary as we can have customers that are using surveys, but might not be using persistence. Unlikely, but can happen

Release info Sub-libraries affected

Libraries affected

  • posthog-js (web)

Checklist

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

If releasing new changes

  • Ran pnpm changeset to generate a changeset file
  • Added the "release" label to the PR to indicate we're publishing new versions for the affected packages

Copy link

vercel bot commented Sep 23, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
posthog-js Ready Ready Preview Sep 25, 2025 7:59pm

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

9 files reviewed, 2 comments

Edit Code Review Bot Settings | Greptile

Copy link

github-actions bot commented Sep 23, 2025

Copy link

github-actions bot commented Sep 23, 2025

Size Change: +14.2 kB (+0.28%)

Total Size: 5.11 MB

Filename Size Change
packages/browser/dist/all-external-dependencies.js 224 kB +796 B (+0.36%)
packages/browser/dist/array.full.es5.js 323 kB +1.2 kB (+0.37%)
packages/browser/dist/array.full.js 385 kB +1.17 kB (+0.3%)
packages/browser/dist/array.full.no-external.js 402 kB +1.17 kB (+0.29%)
packages/browser/dist/array.js 184 kB +1.19 kB (+0.65%)
packages/browser/dist/array.no-external.js 200 kB +1.19 kB (+0.6%)
packages/browser/dist/main.js 185 kB +1.19 kB (+0.65%)
packages/browser/dist/module.full.js 385 kB +1.17 kB (+0.3%)
packages/browser/dist/module.full.no-external.js 402 kB +1.17 kB (+0.29%)
packages/browser/dist/module.js 185 kB +1.19 kB (+0.65%)
packages/browser/dist/module.no-external.js 201 kB +1.19 kB (+0.6%)
packages/browser/dist/surveys-preview.js 71.8 kB +740 B (+1.04%)
packages/browser/dist/surveys.js 80.7 kB +796 B (+1%)
ℹ️ View Unchanged
Filename Size Change
packages/ai/dist/anthropic/index.cjs 16.7 kB 0 B
packages/ai/dist/anthropic/index.mjs 16.5 kB 0 B
packages/ai/dist/gemini/index.cjs 17.6 kB 0 B
packages/ai/dist/gemini/index.mjs 17.5 kB 0 B
packages/ai/dist/index.cjs 120 kB 0 B
packages/ai/dist/index.mjs 119 kB 0 B
packages/ai/dist/langchain/index.cjs 39.6 kB 0 B
packages/ai/dist/langchain/index.mjs 39 kB 0 B
packages/ai/dist/openai/index.cjs 29.8 kB 0 B
packages/ai/dist/openai/index.mjs 29.5 kB 0 B
packages/ai/dist/vercel/index.cjs 21.9 kB 0 B
packages/ai/dist/vercel/index.mjs 21.9 kB 0 B
packages/browser/dist/crisp-chat-integration.js 1.97 kB 0 B
packages/browser/dist/customizations.full.js 19.3 kB 0 B
packages/browser/dist/dead-clicks-autocapture.js 12.6 kB 0 B
packages/browser/dist/exception-autocapture.js 11.6 kB 0 B
packages/browser/dist/external-scripts-loader.js 2.81 kB 0 B
packages/browser/dist/intercom-integration.js 2.02 kB 0 B
packages/browser/dist/lazy-recorder.js 146 kB 0 B
packages/browser/dist/posthog-recorder.js 240 kB 0 B
packages/browser/dist/recorder-v2.js 113 kB 0 B
packages/browser/dist/recorder.js 113 kB 0 B
packages/browser/dist/tracing-headers.js 1.84 kB 0 B
packages/browser/dist/web-vitals.js 10.4 kB 0 B
packages/browser/react/dist/esm/index.js 15.1 kB 0 B
packages/browser/react/dist/umd/index.js 17.8 kB 0 B
packages/core/dist/error-tracking/chunk-ids.js 2.54 kB 0 B
packages/core/dist/error-tracking/chunk-ids.mjs 1.31 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.js 2.3 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.mjs 993 B 0 B
packages/core/dist/error-tracking/coercers/error-coercer.js 2.02 kB 0 B
packages/core/dist/error-tracking/coercers/error-coercer.mjs 794 B 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.js 1.76 kB 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.mjs 513 B 0 B
packages/core/dist/error-tracking/coercers/event-coercer.js 1.82 kB 0 B
packages/core/dist/error-tracking/coercers/event-coercer.mjs 548 B 0 B
packages/core/dist/error-tracking/coercers/index.js 6.79 kB 0 B
packages/core/dist/error-tracking/coercers/index.mjs 326 B 0 B
packages/core/dist/error-tracking/coercers/object-coercer.js 3.46 kB 0 B
packages/core/dist/error-tracking/coercers/object-coercer.mjs 2.07 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.js 1.67 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.mjs 419 B 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.js 2.25 kB 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.mjs 904 B 0 B
packages/core/dist/error-tracking/coercers/string-coercer.js 2.01 kB 0 B
packages/core/dist/error-tracking/coercers/string-coercer.mjs 820 B 0 B
packages/core/dist/error-tracking/coercers/utils.js 2.06 kB 0 B
packages/core/dist/error-tracking/coercers/utils.mjs 716 B 0 B
packages/core/dist/error-tracking/error-properties-builder.js 5.64 kB 0 B
packages/core/dist/error-tracking/error-properties-builder.mjs 4.24 kB 0 B
packages/core/dist/error-tracking/index.js 4.11 kB 0 B
packages/core/dist/error-tracking/index.mjs 152 B 0 B
packages/core/dist/error-tracking/parsers/base.js 2.62 kB 0 B
packages/core/dist/error-tracking/parsers/base.mjs 697 B 0 B
packages/core/dist/error-tracking/parsers/chrome.js 2.7 kB 0 B
packages/core/dist/error-tracking/parsers/chrome.mjs 1.29 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.js 2.45 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.mjs 1.11 kB 0 B
packages/core/dist/error-tracking/parsers/index.js 4.36 kB 0 B
packages/core/dist/error-tracking/parsers/index.mjs 1.92 kB 0 B
packages/core/dist/error-tracking/parsers/node.js 3.95 kB 0 B
packages/core/dist/error-tracking/parsers/node.mjs 2.68 kB 0 B
packages/core/dist/error-tracking/parsers/opera.js 2.22 kB 0 B
packages/core/dist/error-tracking/parsers/opera.mjs 706 B 0 B
packages/core/dist/error-tracking/parsers/react-native.js 203 B 0 B
packages/core/dist/error-tracking/parsers/react-native.mjs 0 B 0 B 🆕
packages/core/dist/error-tracking/parsers/safari.js 1.88 kB 0 B
packages/core/dist/error-tracking/parsers/safari.mjs 574 B 0 B
packages/core/dist/error-tracking/parsers/winjs.js 1.7 kB 0 B
packages/core/dist/error-tracking/parsers/winjs.mjs 406 B 0 B
packages/core/dist/error-tracking/types.js 1.33 kB 0 B
packages/core/dist/error-tracking/types.mjs 131 B 0 B
packages/core/dist/error-tracking/utils.js 1.8 kB 0 B
packages/core/dist/error-tracking/utils.mjs 604 B 0 B
packages/core/dist/eventemitter.js 1.78 kB 0 B
packages/core/dist/eventemitter.mjs 571 B 0 B
packages/core/dist/featureFlagUtils.js 6.5 kB 0 B
packages/core/dist/featureFlagUtils.mjs 4.28 kB 0 B
packages/core/dist/gzip.js 1.88 kB 0 B
packages/core/dist/gzip.mjs 577 B 0 B
packages/core/dist/index.js 6.07 kB 0 B
packages/core/dist/index.mjs 649 B 0 B
packages/core/dist/posthog-core-stateless.js 29.5 kB 0 B
packages/core/dist/posthog-core-stateless.mjs 27 kB 0 B
packages/core/dist/posthog-core.js 28.4 kB 0 B
packages/core/dist/posthog-core.mjs 24.3 kB 0 B
packages/core/dist/testing/index.js 2.93 kB 0 B
packages/core/dist/testing/index.mjs 79 B 0 B
packages/core/dist/testing/PostHogCoreTestClient.js 3.15 kB 0 B
packages/core/dist/testing/PostHogCoreTestClient.mjs 1.74 kB 0 B
packages/core/dist/testing/test-utils.js 2.71 kB 0 B
packages/core/dist/testing/test-utils.mjs 1.03 kB 0 B
packages/core/dist/types.js 8.2 kB 0 B
packages/core/dist/types.mjs 5.93 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.js 3.14 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.mjs 1.76 kB 0 B
packages/core/dist/utils/index.js 9.26 kB 0 B
packages/core/dist/utils/index.mjs 1.88 kB 0 B
packages/core/dist/utils/number-utils.js 2 kB 0 B
packages/core/dist/utils/number-utils.mjs 735 B 0 B
packages/core/dist/utils/promise-queue.js 2 kB 0 B
packages/core/dist/utils/promise-queue.mjs 768 B 0 B
packages/core/dist/utils/string-utils.js 1.91 kB 0 B
packages/core/dist/utils/string-utils.mjs 414 B 0 B
packages/core/dist/utils/type-utils.js 6.93 kB 0 B
packages/core/dist/utils/type-utils.mjs 3.03 kB 0 B
packages/core/dist/vendor/uuidv7.js 8.29 kB 0 B
packages/core/dist/vendor/uuidv7.mjs 6.72 kB 0 B
packages/nextjs-config/dist/config.js 5.51 kB 0 B
packages/nextjs-config/dist/config.mjs 4.03 kB 0 B
packages/nextjs-config/dist/index.js 2.24 kB 0 B
packages/nextjs-config/dist/index.mjs 30 B 0 B
packages/nextjs-config/dist/utils.js 6.06 kB 0 B
packages/nextjs-config/dist/utils.mjs 3.54 kB 0 B
packages/nextjs-config/dist/utils.spec.js 723 B 0 B
packages/nextjs-config/dist/utils.spec.mjs 455 B 0 B
packages/nextjs-config/dist/webpack-plugin.js 3.69 kB 0 B
packages/nextjs-config/dist/webpack-plugin.mjs 1.98 kB 0 B
packages/node/dist/client.js 22.6 kB 0 B
packages/node/dist/client.mjs 20.7 kB 0 B
packages/node/dist/entrypoints/index.edge.js 4.14 kB 0 B
packages/node/dist/entrypoints/index.edge.mjs 652 B 0 B
packages/node/dist/entrypoints/index.node.js 5.08 kB 0 B
packages/node/dist/entrypoints/index.node.mjs 901 B 0 B
packages/node/dist/exports.js 3.6 kB 0 B
packages/node/dist/exports.mjs 124 B 0 B
packages/node/dist/extensions/error-tracking/autocapture.js 2.65 kB 0 B
packages/node/dist/extensions/error-tracking/autocapture.mjs 1.23 kB 0 B
packages/node/dist/extensions/error-tracking/index.js 3.88 kB 0 B
packages/node/dist/extensions/error-tracking/index.mjs 2.61 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.js 8.81 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs 7.15 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.js 2.78 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.mjs 1.45 kB 0 B
packages/node/dist/extensions/express.js 2.17 kB 0 B
packages/node/dist/extensions/express.mjs 548 B 0 B
packages/node/dist/extensions/feature-flags/crypto-helpers.js 2.72 kB 0 B
packages/node/dist/extensions/feature-flags/crypto-helpers.mjs 624 B 0 B
packages/node/dist/extensions/feature-flags/crypto.js 1.96 kB 0 B
packages/node/dist/extensions/feature-flags/crypto.mjs 673 B 0 B
packages/node/dist/extensions/feature-flags/feature-flags.js 26.8 kB 0 B
packages/node/dist/extensions/feature-flags/feature-flags.mjs 25 kB 0 B
packages/node/dist/extensions/feature-flags/lazy.js 1.89 kB 0 B
packages/node/dist/extensions/feature-flags/lazy.mjs 739 B 0 B
packages/node/dist/extensions/sentry-integration.js 4.7 kB 0 B
packages/node/dist/extensions/sentry-integration.mjs 3.21 kB 0 B
packages/node/dist/storage-memory.js 1.52 kB 0 B
packages/node/dist/storage-memory.mjs 297 B 0 B
packages/node/dist/types.js 603 B 0 B
packages/node/dist/types.mjs 0 B 0 B 🆕
packages/node/dist/utils/logger.js 2.16 kB 0 B
packages/node/dist/utils/logger.mjs 971 B 0 B
packages/node/dist/version.js 1.21 kB 0 B
packages/node/dist/version.mjs 45 B 0 B
packages/react-native/dist/autocapture.js 4.68 kB 0 B
packages/react-native/dist/frameworks/wix-navigation.js 1.3 kB 0 B
packages/react-native/dist/hooks/useFeatureFlag.js 1.49 kB 0 B
packages/react-native/dist/hooks/useFeatureFlags.js 821 B 0 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.46 kB 0 B
packages/react-native/dist/hooks/usePostHog.js 467 B 0 B
packages/react-native/dist/index.js 3.12 kB 0 B
packages/react-native/dist/native-deps.js 13.9 kB 0 B
packages/react-native/dist/optional/OptionalAsyncStorage.js 299 B 0 B
packages/react-native/dist/optional/OptionalExpoApplication.js 377 B 0 B
packages/react-native/dist/optional/OptionalExpoDevice.js 347 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 386 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystemLegacy.js 423 B 0 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 383 B 0 B
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 303 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 443 B 0 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 644 B 0 B
packages/react-native/dist/optional/OptionalSessionReplay.js 455 B 0 B
packages/react-native/dist/posthog-rn.js 31.4 kB 0 B
packages/react-native/dist/PostHogContext.js 329 B 0 B
packages/react-native/dist/PostHogProvider.js 4.77 kB 0 B
packages/react-native/dist/storage.js 3.39 kB 0 B
packages/react-native/dist/surveys/components/BottomSection.js 1.34 kB 0 B
packages/react-native/dist/surveys/components/Cancel.js 909 B 0 B
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.58 kB 0 B
packages/react-native/dist/surveys/components/QuestionHeader.js 1.11 kB 0 B
packages/react-native/dist/surveys/components/QuestionTypes.js 10.1 kB 0 B
packages/react-native/dist/surveys/components/SurveyModal.js 3.86 kB 0 B
packages/react-native/dist/surveys/components/Surveys.js 7.18 kB 0 B
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 3.48 kB 0 B
packages/react-native/dist/surveys/icons.js 7.76 kB 0 B
packages/react-native/dist/surveys/index.js 600 B 0 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 5.61 kB 0 B
packages/react-native/dist/surveys/surveys-utils.js 9.31 kB 0 B
packages/react-native/dist/surveys/useActivatedSurveys.js 3.38 kB 0 B
packages/react-native/dist/surveys/useSurveyStorage.js 2.16 kB 0 B
packages/react-native/dist/types.js 70 B 0 B
packages/react-native/dist/version.js 129 B 0 B
packages/react/dist/esm/index.js 15.1 kB 0 B
packages/react/dist/umd/index.js 17.8 kB 0 B
packages/web/dist/index.cjs 13.8 kB 0 B
packages/web/dist/index.mjs 13.7 kB 0 B
tooling/rollup-utils/dist/index.js 1.17 kB 0 B

compressed-size-action

@lucasheriques
Copy link
Contributor Author

@pauldambra requested a review from you as well since we were doing some discussions in the issue

we don't have a lot of data stored. 2 are simple values like boolean/strings, other one is only for surveys in progress, so it only stored until the survey is sent or dismissed

so even if the persistence is set to cookie only it would work well

*/
export const getFromPersistenceWithLocalStorageFallback = (key: string, posthog?: PostHog) => {
try {
if (posthog?.persistence && !posthog.persistence.isDisabled()) {
Copy link
Member

Choose a reason for hiding this comment

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

this check is duplicate across the 3 methods, i'd extract and reuse it

localStorage.setItem(key, value)
}
} catch (e) {
SURVEY_LOGGER.error('Error setting survey seen on persistence', e)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
SURVEY_LOGGER.error('Error setting survey seen on persistence', e)
SURVEY_LOGGER.error('Error setting survey seen on persistence or localStorage', e)

}
return localStorage.getItem(key)
} catch (e) {
SURVEY_LOGGER.error('Error getting property from persistence or localStorage', e)
Copy link
Member

Choose a reason for hiding this comment

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

those logs would be better if it was logged when an error happened within the persistence or localStorage happened so it'd be easier to debug issues.
right now we'd not know whats throwing, the persistence or localStorage

Copy link
Contributor Author

Choose a reason for hiding this comment

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

separate try/catch blocks for all of them now

@marandaneto
Copy link
Member

@lucasheriques we have discussed about this if the localStorage wasnt added intentionally, have you checked the commit history, PRs and comments if there was any reason to use the localStorage directly instead of the persistence? since the API already existed back then, i wonder if doing this would break things for some reason that we are not aware of

@lucasheriques
Copy link
Contributor Author

lucasheriques commented Sep 24, 2025

@marandaneto I went back in the history, and found the first PR that added local storage functionality to surveys

looks like using persistence didn't come up back then

it might have been because surveys used to live on another package here. and that package just used localStorage directly

i found other prs after that (#933 #964 #1200) but all of them just used localStorage directly

in that case, I do think we should go ahead with this, as it should work for most implementations. I also tested with a posthog instance set to memory only, and it worked as expected

@lucasheriques lucasheriques force-pushed the fix/use-persistence-instead-of-localStorage-directly-on-surveys branch from dde549b to 50e8d67 Compare September 25, 2025 19:44
@lucasheriques
Copy link
Contributor Author

@marandaneto i actually tested more throughly, and posthog does not work on incognito well without localStorage access. as it causes the survey to show up consistently without it

so instead I made this commit to warn about it, but still fall back to localStorage. but it's behind a try/catch, so it should also avoid the exceptions users are seeing

but it's a logic change regardless. any thoughts on it before i merge?

}
if (isPersistenceEnabledWithLocalStorage(this._instance)) {
logger.warn(
'Persistence does not include localStorage, but surveys it to work properly. Please set persistence to include localStorage to avoid this warning, or set disable_surveys to true. Falling back to localStorage usage directly to maintain backwards compatibility.'
Copy link
Member

Choose a reason for hiding this comment

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

but surveys it to work properl

this sentence is confusing

Comment on lines +2 to +5
'posthog-js': patch
---

fix: use persistence instead of localStorage on surveys
Copy link
Member

Choose a reason for hiding this comment

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

i think the reason should be slightly better now with the possible odd behaviour after this change (also the PR description)
maybe it should not be a patch anymore?

Comment on lines +56 to +58
* We used to retrieve from localStorage directly. Now, we instead rely on the persistence API, since this is the preferred way to store data.
* But, since we might have customers that might be using surveys with persistence disabled, we need to fallback to localStorage
* to maintain backwards compatibility.
Copy link
Member

Choose a reason for hiding this comment

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

i think the persistence config should mention that surveys will fallback to localStorage if needed

@marandaneto
Copy link
Member

@marandaneto i actually tested more throughly, and posthog does not work on incognito well without localStorage access. as it causes the survey to show up consistently without it

so instead I made this commit to warn about it, but still fall back to localStorage. but it's behind a try/catch, so it should also avoid the exceptions users are seeing

but it's a logic change regardless. any thoughts on it before i merge?

a good moment to review/engage with https://github.com/PostHog/product-internal/pull/854 and talk to the customer support team on how to handle (and communicate) this change that might break customers
do we need this somewhere in https://posthog.com/docs/surveys/troubleshooting ?
do we need to let customers know about this change?
do we have numbers on how many customers dont init posthog with persistence? etc
i dont know the impact so i cant really tell if its ok or not
as a 1st step, i'd just try-catch the local storage usages to avoid the errors on customers as a separate PR and dont get blocked by this until you figure this out

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

Successfully merging this pull request may close these issues.

ReferenceError: localStorage is not defined with posthog.reset() and memory persistence
2 participants