Skip to content

fix(sdk): catch storage errors in getAnonymousId and getSessionId - #641

Open
r69shabh wants to merge 3 commits into
databuddy-analytics:stagingfrom
r69shabh:fix/sdk-tracking-id-storage-throws
Open

fix(sdk): catch storage errors in getAnonymousId and getSessionId#641
r69shabh wants to merge 3 commits into
databuddy-analytics:stagingfrom
r69shabh:fix/sdk-tracking-id-storage-throws

Conversation

@r69shabh

@r69shabh r69shabh commented Aug 20, 2026

Copy link
Copy Markdown

Fixes #638

What

getAnonymousId() and getSessionId() both access localStorage and
sessionStorage with no error handling. Web Storage can throw a
DOMException (usually SecurityError) when storage is blocked by
browser privacy settings, sandboxed iframes, or Safari ITP — and when
that happens the exception propagates up through getTrackingIds() and
getTrackingParams() to every caller.

Reproduced it with the snippet from the issue — overriding
Storage.prototype.getItem to throw and calling getAnonymousId()
confirms it throws instead of returning null.

Why it matters

Two real callsites get hurt by this. The contact form calls
getTrackingIds() before entering its try/catch, so a storage error
prevents the form from submitting entirely — not just drops the tracking
IDs. The Stripe metadata helper has no error handling at all.

How

While reading through the codebase I noticed getProfileId() already
handles this — it wraps localStorage.getItem() in a try/catch and
returns null on failure. The fix for getAnonymousId and getSessionId
is the exact same pattern, just wasn't applied consistently.

Also made the URL-param short-circuit an explicit if guard so when a
param is present, storage is never touched at all (not just skipped via
JS truthiness). Matches what the issue asked for.

getTrackingIds and getTrackingParams are unchanged — they just
delegate and get the fix for free.

Added 8 Playwright tests covering: each helper returning null when its
storage throws, partial results when only one storage fails, empty string
from getTrackingParams, and URL param bypassing storage entirely.

Tests

40 passed (sdk-functions.spec.ts, chromium)
5 passed (storage-edge-cases.spec.ts, chromium)
tsc --noEmit: 0 errors

AI disclosure: I used Claude to help with research and writing. I
reproduced the issue myself, traced the callsites, and spotted the
getProfileId pattern in the codebase as the solution. I sketched the
plan and rough pseudocode for the fix and tests — Claude helped complete
the implementation and fill in the test cases from that. I reviewed all
the generated code, ran type-check and the full E2E suite locally before
opening this PR.


Summary by cubic

Prevents Web Storage errors from breaking tracking ID lookups in @databuddy/sdk. Previously, getAnonymousId/getSessionId threw when storage was blocked; now they return null, and URL params short-circuit without accessing storage so flows like form submissions keep working.

  • Mirrors the getProfileId try/catch pattern; getTrackingIds/getTrackingParams are unchanged and inherit the safer behavior.
  • Adds Playwright tests for storage-throw cases, partial results, empty params, and URL param short-circuit.
  • Migration: If any caller relied on these helpers throwing, update it to handle null results instead.

Written for commit a713e06. Summary will update on new commits.

Review in cubic

@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

@r69shabh is attempting to deploy a commit to the Databuddy OSS Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4f48de91-2434-4038-8e36-2eda11392d4d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@r69shabh
r69shabh marked this pull request as ready for review August 20, 2026 20:42
@r69shabh
r69shabh requested a review from izadoesdev as a code owner August 20, 2026 20:42
@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR makes tracking-ID helpers return null when browser storage access throws while preserving URL-parameter precedence.

  • Wraps anonymous and session storage reads in error handling.
  • Adds browser tests for blocked storage, partial results, and URL-parameter short-circuiting.
  • Adds a patch changeset for @databuddy/sdk.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/sdk/src/core/tracker.ts Adds guarded storage reads to the anonymous and session ID helpers while retaining existing precedence and return contracts.
packages/sdk/tests/sdk-functions.spec.ts Adds coverage for storage exceptions, partial tracking data, and avoiding storage access when a URL ID exists.
.changeset/sdk-storage-error-fix.md Documents the storage-error handling change as an SDK patch release.

Reviews (2): Last reviewed commit: "chore: add changeset for sdk storage err..." | Re-trigger Greptile

Comment on lines +293 to +298
Storage.prototype.getItem = function (key: string) {
if (this === localStorage) {
throw new DOMException("Access denied", "SecurityError");
}
return original.call(this, key);
};

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.

P2 Function expressions violate lint rules

The new storage mocks use traditional function expressions here and at the other Storage.prototype.getItem assignments, violating the repository's arrow-function requirement and potentially failing the corresponding lint check.

Context Used: Ultracite Rules - AI-Ready Formatter and Linter (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@izadoesdev
izadoesdev deleted the branch databuddy-analytics:staging August 21, 2026 09:05
@izadoesdev izadoesdev closed this Aug 21, 2026
@izadoesdev izadoesdev reopened this Aug 21, 2026
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.

2 participants