@mosovn/echo
v0.4.0
Published
Echo SDK — event tracking for moso products. Works in browser and React Native (auto-picked by bundler).
Maintainers
Readme
@mosovn/echo
SDK for the Echo event-tracking system. Works in both browser and React Native — bundler auto-picks the right implementation via conditional exports.
# Web (Next.js / Vite / Webpack / etc.)
npm install @mosovn/echo
# React Native — also install the platform polyfills
npm install @mosovn/echo \
@react-native-async-storage/async-storage \
react-native-get-random-values
# iOS only
cd ios && pod install && cd ..Web usage
import { createEcho } from '@mosovn/echo';
const echo = createEcho({
writeKey: 'pk_xxxxxxxxxxxx',
});
echo.track('Sign Up', { plan: 'pro' });
echo.identify('user_123', { email: '[email protected]' });Web autocapture (default ON)
$pageview— page load + SPA navigation (pushState/popstate/hashchange)$click— every click; usedata-no-trackto exclude$form_submit— form submit (never captures field values)$scroll— throttled to 250 ms + ≥10% delta$visibility— tab focus/blur$hover— mouseenter on a/button/[id]/[role=button], 500 ms throttle$error—window.onerror+unhandledrejection, 5 s dedup$web_vital— LCP, FID, CLS$session_start/$session_end— 30 min inactivity timeout
Configure or disable:
createEcho({
writeKey: 'pk_xxx',
autoCapture: {
clicks: 'instrumented', // only a/button/[id]/[role=button]
scroll: false,
},
maskTextSelectors: ['input', '[data-private]'],
blockSelectors: ['[data-no-track]'],
});React Native usage
In your app entry (index.js or App.tsx), import the polyfill FIRST:
// index.js — TOP OF FILE
import 'react-native-get-random-values';Then anywhere:
import { createEcho } from '@mosovn/echo';
const echo = createEcho({
writeKey: 'pk_xxxxxxxxxxxx',
app: {
name: 'MOSO Mobile',
version: '2.4.1',
build: '124',
},
});
echo.track('Sign Up', { plan: 'pro' });
echo.identify('user_123', { email: '[email protected]' });RN autocapture
Limited (no DOM in RN):
$session_start/$session_end—AppStateforeground/background + 30 min inactivity$error—ErrorUtils.setGlobalHandler+unhandledrejection
You must call manually:
- Screen views — hook into React Navigation:
<NavigationContainer ref={navRef} onStateChange={() => { const r = navRef.getCurrentRoute(); if (r) echo.screen?.(r.name); }} > - Button taps, form submits, network errors — call
echo.track()in your handlers
API
| Method | Web | RN | Notes |
|---|---|---|---|
| createEcho(config) | ✅ | ✅ | Returns EchoClient |
| echo.track(name, props?) | ✅ | ✅ | Custom event |
| echo.identify(userId, traits?) | ✅ | ✅ | Set user identity |
| echo.setUserProperties(traits) | ✅ | ✅ | Update traits |
| echo.page(props?) | ✅ | n/a | Web only — URL-based |
| echo.screen(name, props?) | n/a | ✅ | RN only — call from navigation |
| echo.reset() | sync | async | Logout; rotates anonymousId |
| echo.flush() | ✅ | ✅ | Force send queued events |
| echo.getAnonymousId() | ✅ | ✅ | |
| echo.getUserId() | ✅ | ✅ | |
| echo.getSessionId() | ✅ | ✅ | |
How bundler picks the right entry
@mosovn/echo ships two builds in dist/:
dist/web.js— useslocalStorage,document,window,MutationObserver,PerformanceObserverdist/native.js— usesAsyncStorage,AppState,ErrorUtils,react-native-get-random-values
package.json exports field routes:
{
"exports": {
".": {
"react-native": "./dist/native.js", // ← Metro picks this
"browser": "./dist/web.js", // ← Webpack/Vite picks this
"import": "./dist/web.js", // ← ESM default
"require": "./dist/web.cjs" // ← CJS default
}
},
"react-native": "./dist/native.js" // ← older Metro fallback
}Same import { createEcho } from '@mosovn/echo' in your code works in both environments.
PII
Form field values are NEVER captured. Text inside <input>, <textarea>, <select>, and [data-private] is masked from autocaptured events by default.
data-no-track attribute on any element excludes it (and its descendants) from all autocapture.
Identity
- anonymous_id — UUIDv7, persistent across sessions. Web: localStorage + cookie on apex domain. RN: AsyncStorage.
- user_id — set by
identify(), cleared byreset(). - session_id — rotates after 30 min inactivity. Web: per-tab. RN: per-app.
License
MIT
