@nexly/web
v0.17.0
Published
Nexly browser ingest SDK: sendBeacon transport, DOM metadata, engagement listeners on top of @nexly/core
Downloads
174
Maintainers
Readme
@nexly/web
Browser ingest SDK for Nexly: sendBeacon transport, DOM metadata, engagement listeners. Implements the abstract NexlyBase from @nexly/core for the browser runtime.
Install
npm install @nexly/webUsage
import { Nexly } from '@nexly/web'
const client = Nexly.init({
appId: 'your-app-id',
key: 'your-ingest-key',
})
client.pageview()
client.customEvent('cta_clicked', { placement: 'hero' })
const stopEngagement = client.startEngagement()
// stopEngagement() on SPA unmount / route change if neededstartEngagement() is idempotent — calling it again stops the previous subscription first, so HMR or double-mounts can't produce duplicate listeners.
Opting elements out of auto-capture
Auto-click and auto-focus listeners skip any element (or descendant of an element) marked with data-nexly-ignore. Use it on elements where you already emit your own event(...) to avoid semantic duplicates:
<button data-nexly-ignore onClick={() => client.customEvent('signup_clicked')}>
Sign up
</button>What you get
Nexly— browser client (auto session + visitor IDs vialocalStorage/sessionStorage).collectSessionMeta(),collectEventMeta(),collectBrowserMeta()— reusable metadata collectors.startEngagementTracking(creds)— standalone engagement attach (scroll / click / focus / visibility / keepalive).sendBeaconCollect(input)— rawsendBeaconhelper.
For React bindings use @nexly/react-web; for Next.js App Router use @nexly/next; for React Native use @nexly/react-native; for Node.js servers use @nexly/node.
Custom analytics events
For application-specific events use the ergonomic customEvent API. It takes three arguments and always emits an event_type: 'custom' event:
client.customEvent('checkout_completed', {
plan_id: 'pro',
amount_cents: 4200,
items: 3,
})name— registered as a custom analytics event in the dashboard. Unapproved names show up under Discovered for later approval and do not enter analytics until you accept them.cdata— user-defined custom properties. Values must bestring,number, orboolean; numbers and booleans are normalised to strings server-side. Nested objects, arrays, andnullare silently dropped.context(optional) — per-event attribution override for the standard marketing parameters (utm_source,utm_medium,utm_campaign,utm_content,utm_term,gclid,gad_source,gad_campaignid,fbclid,msclkid,ttclid,li_fat_id,yclid,mc_cid,ref). Useful when the landing URL no longer carries them at click time (single-page navigation, deep-links, post-redirect flows). Only standard attribution keys are accepted in this slot.
client.customEvent(
'signup_clicked',
{ source_section: 'pricing' },
{ utm_source: 'newsletter', utm_campaign: 'q2-launch' },
)The generic client.event({ name, type, cdata, context }) remains available when you need to set Nexly-known context fields like visitor_id alongside custom properties.
Linking backend events to this visitor
If you also emit server-side events with @nexly/node and want them to show up on the same user timeline as browser activity, forward the browser's Nexly visitor id to your backend once (on sign-up / login), persist it next to your own user record, and pass it through in context when emitting backend events.
import { getVisitorId, getSessionId } from '@nexly/web'
// once per signed-in user — send to your own backend
await fetch('/api/link-visitor', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
visitorId: getVisitorId(),
sessionId: getSessionId(), // optional
}),
})getVisitorId() reads the persistent anonymous id Nexly stores in localStorage; getSessionId() reads the 30-minute tab session id from sessionStorage. Both are plain strings, safe to call from anywhere.
See the full recipe (backend storage + emitting linked events) in the @nexly/node README.
Bot detection
Bots and AI crawlers are classified server-side from the HTTP User-Agent header at ingest — do not try to compute or send an is_bot flag from your page code. Every event is stored (bots are not filtered out); the dashboard surfaces them in the dedicated "AI & Crawler activity" section and excludes them from standard visitor metrics.
