Skip to content

feat(analytics): generate random IDs in the SDK and drop react-native-get-random-values - #472

Merged
ketanmixpanel merged 3 commits into
feat/spm-rn-0.88from
feat/remove-get-random-values
Oct 30, 2026
Merged

ketanmixpanel merged 3 commits into
feat/spm-rn-0.88from
feat/remove-get-random-values

Conversation

@ketanmixpanel

Copy link
Copy Markdown
Contributor

Summary

Removes react-native-get-random-values and uuid. The SDK now generates random IDs itself in javascript/mixpanel-random.js, using the same order of sources the library used, with a new randomUUID method on our native module as the secure source for device IDs when JavaScript has none.

Linear: SDK-456 (December CocoaPods removal / next major)

Why

  • Expo + SPM builds fail on our dependency. Expo autolinks transitive dependencies, so apps with "experiments": { "swiftPackageManager": true } link react-native-get-random-values 1.11.0, which has no Package.swift:
    error: Package.swift is missing for library "react-native-get-random-values"
  • The upstream fix doesn't fit us. 2.1.0 adds a Package.swift, but it builds on 2.0.0, which is New-Architecture-only and needs React Native ≥ 0.81. On React Native 0.79, npm silently installs a second React Native 0.88 under our package instead of failing.
  • Plain React Native apps never had the native part. The React Native CLI only autolinks an app's direct dependencies, so the polyfill's native module wasn't linked unless the app added the library itself. JavaScript mode in those apps has been falling back to Math.random for device IDs.

Changes

  • javascript/mixpanel-random.js (new):
    • randomUUID() (async) tries, in order:
      1. Web Crypto (globalThis.crypto.getRandomValues);
      2. Expo's crypto module (global.expo.modules.ExpoCrypto);
      3. MixpanelReactNative.randomUUID();
      4. Math.random, with a one-time console.warn.
    • randomHex(n) (sync) is a best-effort source for trace IDs. It uses the same JavaScript sources, then Math.random.
  • Native: randomUUID on iOS (UUID(), in MixpanelReactNative.swift and .m) and on Android (UUID.randomUUID()), both backed by the system's secure random generator.
  • mixpanel-persistent.js: the device ID uses randomUUID(). Existing stored device IDs are loaded unchanged.
  • mixpanel-flags-js.js: traceparent uses randomHex, so the header is now always sent. Previously it was skipped when uuid had no crypto source.
  • package.json: removes react-native-get-random-values and uuid, and drops them from Jest's transformIgnorePatterns.
  • Tests:
    • New __tests__/random.test.js covers each source and the one-time warning.
    • The device-ID tests are rewritten.
    • The uuid and polyfill mocks are removed.
  • .github/copilot-instructions.md: dependency list updated.
  • package-lock.json: besides removing the packages, npm 11 added "dev": true markers and corrected the stale root version (3.8.1 → 4.0.0).

Breaking change

Importing the SDK no longer sets global.crypto.getRandomValues for the whole app. Apps that use uuid or other crypto libraries and relied on our import must add the polyfill themselves:

npm install react-native-get-random-values
// first line of the app's entry file
import 'react-native-get-random-values';

Test setups that call jest.mock('react-native-get-random-values') without the package installed will also fail with "Cannot find module".

Unchanged:

  • Native mode (the default) never used the library.
  • JavaScript mode keeps existing device IDs, and new IDs have the same UUID v4 format.
  • An over-the-air JavaScript update running on an older binary without randomUUID falls back without crashing.

Testing

  • npm test: 526 passed, 4 skipped (skipped before this change).
  • Expo SDK 58 (React Native 0.88), Release builds, with a JavaScript-mode instance next to the native one:
    • iOS, CocoaPods: native mode OK, Session Replay isRecording=true. JavaScript mode got its device ID from the native randomUUID, since Hermes has no Web Crypto. Podfile.lock no longer contains react-native-get-random-values.
    • Android: same results.
    • These ran before the warning was switched to console.warn. The ID logic is unchanged.

Not yet tested:

  • Expo + SPM.
  • The Expo crypto path on a device (Expo Go, or an app with expo-crypto).
  • React Native Web.
  • JavaScript mode in a plain React Native CLI app.

@ketanmixpanel
ketanmixpanel requested review from a team and rahul-mixpanel October 29, 2026 16:05
@greptile-apps

greptile-apps Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; the remaining sample setup documentation issue is non-blocking.

Findings

  1. P2 Fresh-clone setup misses dependencies ▶

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[New device ID] --> B{JavaScript crypto works?}
  B -->|Yes| C[Format UUID v4]
  B -->|No| D{Native randomUUID works?}
  D -->|Yes| E[Return lowercase UUID]
  D -->|No| F[Warn once and use Math.random]
Loading

Reviews (4) · Last reviewed commit: "updated sample apps" · Reviewed by Greptile

## Run

```sh
npm install

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Fresh-clone setup misses dependencies

These instructions install only the sample's dependencies. mixpanel-react-native links to the repository root, whose dependencies are not installed by this command. On a fresh clone, Metro therefore cannot resolve imports such as react-native-get-random-values. Add a root npm install step before the sample install, as CI already does.

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.

removed the react-native-get-random-values library and implemented the feature in the SDK.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You're right—the react-native-get-random-values reference in my comment is outdated. The sample's npm install also installs the local SDK's declared runtime dependencies, so a separate root install isn't needed for those imports. Please disregard my comment.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@ketanmixpanel
ketanmixpanel changed the base branch from master to feat/spm-rn-0.88 October 29, 2026 16:13
Comment thread javascript/mixpanel-random.js Resolved
A crypto polyfill without its native module, such as
react-native-get-random-values imported by another dependency, throws
from getRandomValues. randomUUID then rejected instead of trying the
SDK's native module, so JavaScript-mode init failed for a new device ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@rahul-mixpanel rahul-mixpanel 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.

Nice cleanup. The source order in mixpanel-random.js makes sense, existing device IDs load unchanged, and e5b258a handles a polyfill that throws. Plain React Native CLI apps in JavaScript mode also get secure device IDs now instead of Math.random.

The main test workflow doesn't run on this PR because it only triggers for PRs into master, so I ran Jest locally on e5b258a: 528 passed, 4 skipped.

A few things before merge:

  1. Release notes reminder: when the CHANGELOG for this release is generated, please add the breaking change by hand. Importing the SDK no longer installs crypto.getRandomValues for the whole app, so apps that relied on that need react-native-get-random-values and an import at the top of their entry file. The migration steps in this PR's description could go in as they are.
  2. Expo + SwiftPM: this PR exists to fix that build, but it's listed as not yet tested. Could you run one Expo + SwiftPM build (e.g. Samples/MixpanelExpo with "experiments": { "swiftPackageManager": true }) before merging, to confirm the Package.swift is missing error is gone?

Nits (optional):

  • Samples/MixpanelExpo/ios/Podfile.lock still lists react-native-get-random-values from mixpanel-react-native/node_modules. Running pod install would refresh it.
  • Samples/MixpanelStarter still installs react-native-get-random-values and has a Metro alias for it. That's harmless, but it means the sample never exercises the new fallback path.

@ketanmixpanel

Copy link
Copy Markdown
Contributor Author

Testing

Setup: Expo SDK 58 (expo 58.0.17) with React Native 0.88.0, using mixpanel-react-native from this branch (e5b258a) and @mixpanel/react-native-session-replay from feat/spm-rn-0.88. iOS uses Swift Package Manager (experiments.swiftPackageManager: true); Android uses Gradle.

Platform Native linking Mixpanel mode Result
iOS Swift Package Manager Native (default) ✅ Builds and runs; events tracked, Session Replay recording
iOS Swift Package Manager JavaScript (useNative: false) ✅ Builds and runs; device ID generated, events tracked
Android Gradle Native (default) ✅ Builds and runs; events tracked, Session Replay recording
Android Gradle JavaScript (useNative: false) ✅ Builds and runs; device ID generated, events tracked
Web None (no native module) JavaScript (automatic) ✅ Runs; device ID generated with the browser's crypto, events tracked. Session Replay was left out of the web build because it only supports iOS and Android.

The Nits are addressed in the c6e2e8b commit

@rahul-mixpanel rahul-mixpanel 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.

Thanks for the thorough testing, Ketan. Expo + SwiftPM on iOS, Android, and web in both modes covers it, and the sample cleanup (including the Starter metro.config.js fix) looks good. LGTM.

Reminder for the release: please add the breaking change to the generated CHANGELOG by hand. Importing the SDK no longer installs crypto.getRandomValues for the whole app, so apps that relied on it need react-native-get-random-values and an import at the top of their entry file.

@ketanmixpanel
ketanmixpanel merged commit be728f5 into feat/spm-rn-0.88 Oct 30, 2026
2 checks passed
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