npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

landom-sdk

v0.2.0

Published

Lightweight SDK that auto-captures landing page user behavior (clicks, scrolls, inputs, exits, rrweb session replay) and ships it to your analytics backend.

Readme

LandOm SDK

A lightweight SDK that automatically captures landing page user behavior — clicks, scrolls, inputs, exits, and full session replay — and ships it to your analytics backend.

Installation

npm / yarn / pnpm

npm install landom-sdk
# or
yarn add landom-sdk
# or
pnpm add landom-sdk

CDN (<script> tag)

<script src="https://unpkg.com/landom-sdk/dist/landom-sdk.umd.js"></script>

Quick Start

With a bundler (Vite, Webpack, Next.js, etc.)

import { init } from 'landom-sdk';

init({
  apiKey: 'your-project-key',
  endpoint: 'https://your-server.com/api/v1/events',
});

Or import everything under a namespace:

import * as LandOm from 'landom-sdk';

LandOm.init({ apiKey: '...', endpoint: '...' });

With a <script> tag (UMD)

The UMD build attaches the SDK to window.LandOm:

<script src="https://unpkg.com/landom-sdk/dist/landom-sdk.umd.js"></script>
<script>
  LandOm.init({
    apiKey: 'your-project-key',
    endpoint: 'https://your-server.com/api/v1/events',
  });
</script>

A single init() call enables automatic capture of user events and rrweb-based session replay.

API

import { init, capture, destroy } from 'landom-sdk';

| Function | Description | |----------|-------------| | init(options) | Initialize the SDK and start auto-capture | | capture(type, payload?) | Manually record a custom event | | destroy() | Stop capture and flush any pending events |

Configuration

init({
  apiKey: 'your-project-key',
  endpoint: '/api/v1/events',          // event ingest endpoint
  flushInterval: 3000,                 // auto-flush interval (ms)
  flushQueueSize: 20,                  // flush immediately when queue hits this size
  maxQueueSize: 100,                   // max queued events; oldest are dropped beyond this
  maxRetries: 3,                       // fetch retry count on failure

  enableReplay: true,                  // enable rrweb session replay
  replayMaskAllInputs: true,           // mask all input values in replay
  replayBlockClass: 'rr-block',        // class to fully exclude an element from replay
  replayBlockSelector: '.no-record',   // selector to fully exclude elements from replay
  replayMaskTextClass: 'rr-mask',      // class to mask text content in replay
  replayInlineStylesheet: true,        // inline external stylesheets (replay fidelity ↔ payload size)
  replayCheckoutEveryNms: 600000,      // rrweb full-snapshot interval (default: 10 min)
  replayMousemoveSampling: false,      // record mousemove events (off by default)
  replayMousemoveCallbackSampling: 500,// mousemove emit interval (ms) when enabled
  replayScrollSampling: 200,           // scroll sampling interval (ms)
  replayInputSampling: 'last',         // input recording strategy (change-based)

  debug: false,                        // verbose console logging
  beforeSend: (event) => event,        // hook to transform or filter events before send
});

Auto-Captured Events

After init(), the SDK automatically collects the following events. Each event includes a common cssSelector: string | null field (null when no element is associated).

| Event | Description | Payload | cssSelector | |-------|-------------|---------|-------------| | start | Page load | — | null | | visibility | Tab visibility change | isVisible | null | | scroll | Page scroll (500 ms throttle) | yOffset, percentage | null | | click | Element click | targetId | clicked element | | input | Input field focus (value is not captured) | fieldId | focused field | | replay | rrweb session replay chunk | compressed, compression, encoding, data, version | null | | ping | Currently visible section (5 s interval) | sectionId | current section | | exit | Page exit | lastElementId, maxDepth | last element or null |

Session Replay

Session replay is powered by rrweb and is enabled by default. Disable it with enableReplay: false.

Replay chunks are emitted as type: "replay" events; the rrweb payload is gzipped via the browser-native CompressionStream API and base64-encoded:

{
  "type": "replay",
  "timestamp": 1711612803000,
  "cssSelector": null,
  "payload": {
    "compressed": true,
    "compression": "gzip",
    "encoding": "base64",
    "data": "...",
    "version": "rrweb"
  }
}

The server is expected to decompress the payload before persisting the original rrweb JSON.

Replay Footprint Optimizations

The SDK applies the following rrweb settings by default to keep payloads small:

| Setting | Value | Purpose | |---------|-------|---------| | slimDOMOptions | "all" | Strip scripts, comments, head metadata, etc. | | sampling.mousemove | false | Disable mousemove recording | | sampling.scroll | 200 | Reduce scroll recording frequency (rrweb default is 100 ms) | | sampling.input | "last" | Record only the last value on change | | checkoutEveryNms | 600000 | Take a full snapshot every 10 minutes | | blockSelector | .no-record | Exclude marked elements entirely |

Excluding & Masking Sensitive Content

Add rr-block or no-record to fully exclude an element from replay, or rr-mask to mask its text content:

<section class="no-record">
  This section is never recorded.
</section>

<p class="rr-mask">
  This text is masked in the replay.
</p>

Server Contract

Events are batched and sent via POST <endpoint>:

Header: X-Project-Key: <apiKey>
{
  "sessionId": "UUIDv7",
  "userAgent": "Mozilla/5.0 ...",
  "url": "https://example.com",
  "events": [
    {
      "type": "click",
      "timestamp": 1711612800000,
      "cssSelector": "section[id=\"hero\"] > button:nth-of-type(1)",
      "payload": { "targetId": "#signup-btn" }
    },
    {
      "type": "scroll",
      "timestamp": 1711612802000,
      "cssSelector": null,
      "payload": { "yOffset": 500, "percentage": 25 }
    }
  ]
}

On page exit the SDK falls back to navigator.sendBeacon. Since custom headers cannot be set on beacons, the apiKey is included in the body instead.

Build Outputs

npm install ships these prebuilt artifacts (resolved automatically via package.json exports):

| File | Format | Use | |------|--------|-----| | dist/landom-sdk.esm.js | ESM | Bundlers (Vite, Webpack, Rollup) | | dist/landom-sdk.cjs.js | CommonJS | Node / require() | | dist/landom-sdk.umd.js | UMD | Direct <script> tag | | dist/types/index.d.ts | TypeScript declarations | Type-checked consumers |

Development

git clone https://github.com/DontYouKnowFunnel/LandOm-SDK.git
cd LandOm-SDK
npm install
npm run build   # one-off build
npm run dev     # watch mode

License

MIT © Kim Seongmin