Skip to content

feat: identify() + cross-subdomain anonymous ID cookie (v0.3.0)#3

Merged
DuncanAForbes merged 4 commits into
mainfrom
develop
Apr 20, 2026
Merged

feat: identify() + cross-subdomain anonymous ID cookie (v0.3.0)#3
DuncanAForbes merged 4 commits into
mainfrom
develop

Conversation

@DuncanAForbes
Copy link
Copy Markdown
Contributor

@DuncanAForbes DuncanAForbes commented Apr 20, 2026

Summary

  • identify(params) — stitch the current anonymous ID to a known contact by POSTing to the Bagdock identify relay (/api/identify). Upserts contact_anonymous_ids on the operator database and optionally backfills contact traits + first-touch UTM attribution.
  • Cross-subdomain anonymous ID — generate a stable bagdock_anon_id on first visit, persisted in both localStorage and a .bagdock.com cookie (400-day TTL, SameSite=lax). The same ID follows visitors across marketing site, checkout, and customer app so pre-identify events are attributed correctly.
  • anonymous_id in every event payload — all track() calls now include the anonymous ID, enabling server-side correlation of events to contacts even before identify() is called.
  • anonymousId getter — read the current anonymous ID from the SDK instance.
  • README — new "How to identify visitors" section, updated Methods/Types/Exports tables, updated Data privacy section describing the cookie.
  • Version bump0.2.00.3.0.

Test plan

  • new BagdockAnalytics({ apiKey, debug: true }) logs anonymous ID on init
  • analytics.anonymousId returns a UUID string
  • analytics.identify({ contactId: 'ct_x' }) POSTs to /api/identify with anonymous_id, contact_id, UTM, landing_page
  • Cookie bagdock_anon_id set on .bagdock.com with ~400-day max-age
  • Opening a new tab on the same domain reuses the same anonymous ID from the cookie
  • track() payloads include anonymous_id field
  • npm run build produces clean dist with new exports

Summary by CodeRabbit

  • New Features

    • Added visitor identification capability to link anonymous browsing history to known contacts.
    • Introduced automatic anonymous ID generation and cross-domain persistence.
    • New identify() method for stitching user sessions.
  • Documentation

    • Updated guides explaining identification workflow and data privacy considerations.
  • Chores

    • Released version 0.3.0.
    • Enhanced release workflow for improved tag detection and release targeting.

release.yml:
- Use git ls-remote instead of git rev-parse for tag check so
  remote tags are detected reliably (not just local refs)
- Pin release target to merge_commit_sha instead of moving main
  branch ref to avoid race conditions

src/index.ts:
- parseUTM: use URL base parameter so relative URLs and query-only
  inputs ('?utm_source=google', '/page?utm_medium=cpc') resolve
  correctly instead of throwing
- persistUTM/getPersistedUTM: validate JSON.parse output is a plain
  object before spreading, preventing corrupt sessionStorage from
  injecting unexpected metadata fields
- Constructor: always read back from getPersistedUTM() after persist
  so in-memory UTM state includes previously persisted keys merged
  with fresh ones, not just the fresh subset
The pull_request.closed event checks out the PR merge ref by default,
which can yield an empty version read. Explicitly checkout main with
fetch-depth: 0 so package.json and git tags are both available.
- Add identify() to stitch anonymous_id to a known contact via the
  identify relay API on the loyalty/operator backend
- Generate and persist anonymous_id in localStorage + cross-subdomain
  cookie (.bagdock.com, 400-day TTL, SameSite=lax)
- Include anonymous_id in every tracked event payload
- Export IdentifyParams type and anonymousId getter
- Cookie priority: cookie > localStorage > generate fresh
- Bump version 0.2.0 → 0.3.0
- Add "How to identify visitors" section with code examples
- Document IdentifyParams type and anonymousId getter
- Add identify() and anonymousId to Methods table
- Update Data privacy section to describe the anonymous ID cookie
@DuncanAForbes DuncanAForbes merged commit 9876ee7 into main Apr 20, 2026
3 of 4 checks passed
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 55445289-5ab3-4f4a-8749-8af78f426d6f

📥 Commits

Reviewing files that changed from the base of the PR and between c9c6c2a and 1f3b00b.

📒 Files selected for processing (4)
  • .github/workflows/release.yml
  • README.md
  • package.json
  • src/index.ts

Walkthrough

The pull request implements visitor identification functionality for the Bagdock Analytics SDK. It introduces an identify() method to stitch anonymous browsing history to known contacts, adds anonymous ID management with cross-domain cookie support, updates event payloads to include anonymous IDs, bumps the package version to 0.3.0, enhances the release workflow for improved tag and commit handling, and updates documentation accordingly.

Changes

Cohort / File(s) Summary
Release Workflow & Versioning
.github/workflows/release.yml, package.json
Enhanced release workflow with explicit main ref checkout (fetch-depth: 0), remote tag existence checking via git ls-remote, and targeting merge commit SHA for GitHub release creation. Version bumped from 0.2.0 to 0.3.0.
Documentation
README.md
Added documentation for new identify() method, anonymousId getter, and IdentifyParams interface. Updated sequence diagram to reflect anonymous ID metadata. Documented anonymous ID persistence via localStorage and cross-subdomain .bagdock.com cookie, plus expanded data privacy section.
Core SDK Implementation
src/index.ts
Implemented anonymous ID management with generation and cross-domain cookie helpers. Added public identify(params: IdentifyParams): Promise<void> method to POST identify payloads to /api/identify. Added anonymousId getter. Updated parseUTM for improved URL handling and hardened UTM storage validation. Modified event payloads to include anonymous_id field. Exported new IdentifyParams interface.

Sequence Diagram

sequenceDiagram
    actor App as App
    participant SDK as Bagdock Analytics SDK
    participant Storage as Browser Storage
    participant API as Bagdock API

    rect rgba(100, 150, 200, 0.5)
    Note over App,API: Anonymous ID Generation & Persistence
    SDK->>Storage: Check localStorage/cookie for anonymousId
    alt ID exists
        Storage-->>SDK: Return existing anonymousId
    else ID not found
        SDK->>SDK: Generate new anonymousId
        SDK->>Storage: Save to localStorage + .bagdock.com cookie
    end
    SDK->>App: anonymousId ready (via getter)
    end

    rect rgba(150, 100, 200, 0.5)
    Note over App,API: Visitor Identification
    App->>SDK: identify({ contactId, operatorId?, traits? })
    SDK->>SDK: Build identify payload with anonymous_id, utm, landing_page, referrer
    SDK->>API: POST /api/identify (with Authorization header)
    API-->>SDK: { stitched } response
    SDK->>App: Promise resolves (silently catches errors)
    end

    rect rgba(100, 200, 150, 0.5)
    Note over App,API: Event Tracking with Anonymous ID
    App->>SDK: track(event)
    SDK->>SDK: Build event payload with anonymous_id
    SDK->>API: POST event with anonymous_id included
    API-->>SDK: Acknowledgement
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 A visitor arrives, anonymous and free,
We generate an ID, store it in localStorage!
When contactId is known, we stitch the history,
Events now carry their anonymous ID seal,
The SDK remembers, across all time—
identifies what was once only a rhyme! 🌐

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

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 and usage tips.

Comment thread src/index.ts
function setCrossDomainCookie(name: string, value: string): void {
if (typeof document === 'undefined') return
const hostname = typeof window !== 'undefined' ? window.location.hostname : ''
const domain = hostname.endsWith('bagdock.com') ? '.bagdock.com' : undefined
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