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

@insightdive/sdk

v0.9.0

Published

JavaScript/TypeScript SDK for Insightdive in-app surveys. Embeds a survey as a modal bottom sheet or inline widget, streams lifecycle events.

Readme

@insightdive/sdk

JavaScript / TypeScript SDK for Insightdive — the in-app feedback platform.

Embeds a survey as a modal bottom sheet or inline widget, streams lifecycle events back to your app. Anonymous by default — no user identifiers are ever collected or passed to the server.

Install

npm install @insightdive/sdk
# or
yarn add @insightdive/sdk
# or
pnpm add @insightdive/sdk

3-line integration

import { Insightdive } from '@insightdive/sdk';

Insightdive.configure({
  tenant: 'acme',             // your workspace slug
  survey: 'onboarding',       // the project slug
  apiKey: 'ik_abc123...',  // copy from Admin → Settings → API
});

// anywhere later:
const result = await Insightdive.show();
if (result.status === 'completed') {
  console.log('Submitted! submissionId:', result.submissionId);
}

Configuration

| Field | Type | Description | |---------------------|--------------------------------------------------|-------------| | tenant | string | Workspace slug — the subdomain on insightdive.com (e.g. 'acme'). | | survey | string | Project slug from the admin (e.g. 'onboarding'). Always serves the currently active deployment. | | apiKey | string | Tenant API key found in Admin → Settings → API. Required. | | baseUrl | string? | Full URL override for staging or self-hosted instances (e.g. 'http://acme.localhost:3000'). | | productVersion | string? | Free-form version stamped on every submission (e.g. '1.2.3'). | | productIdentifier | string? | Surface slug — useful when one app embeds the SDK in several places. | | locale | string? | Locale to render the survey in. Falls back to the survey's default. | | theme | string? | 'light' or 'dark'. Falls back to the survey's authored theme. | | scale | number? | Content zoom factor (CSS zoom), clamped to [0.5, 2]. Default 1. Shrinks/enlarges the survey content to fit the modal/iframe instead of being clipped. | | context | Record<string, string \| number \| boolean>? | Operator-defined key/value metadata stamped on every submission. See Operator context. | | respondentToken | string? | Opaque hash for operator-side cross-referencing without storing a user identity. See Respondent token. |

Check availability first

const available = await Insightdive.isAvailable();
if (available) {
  await Insightdive.show();
}

isAvailable() hits /api/v1/surveys/{survey}/status with a 5-second timeout and returns false on any error, so it's safe to call on every page load.

Modal sheet

const result = await Insightdive.show();
// Resolves when the sheet closes (completed or dismissed)
console.log(result.status);    // 'completed' | 'dismissed'
console.log(result.sessionId);
console.log(result.submissionId); // only present when status === 'completed'
console.log(result.duration);  // milliseconds

Dismiss the sheet programmatically:

Insightdive.hide();

Inline widget

Render the survey directly inside any container element — useful for dedicated feedback pages or embedded panels:

const container = document.getElementById('survey-slot');
// container needs an explicit height in CSS
Insightdive.embed(container);
<div id="survey-slot" style="height: 600px; width: 100%;"></div>

Lifecycle events

Insightdive.on('ready', () => {
  console.log('Bridge alive');
});

Insightdive.on('viewed', (e) => {
  console.log('Session registered', e.sessionId);
});

Insightdive.on('started', () => {
  console.log('User clicked start');
});

Insightdive.on('completed', (e) => {
  analytics.track('feedback_completed', { id: e.submissionId });
});

Insightdive.on('dismissed', () => {
  analytics.track('feedback_dismissed');
});

// Catch-all
Insightdive.on('*', (e) => {
  console.log(e.type, e);
});

Unsubscribe:

const handler = (e) => console.log(e);
Insightdive.on('completed', handler);
Insightdive.off('completed', handler);

Event-based triggering

trigger() calls the status endpoint with ?event=<name> before opening the modal. The survey only opens when the insight's trigger-event list (configured in the admin) includes the event name. When the list is empty every event matches.

// Fires the survey only when 'app_launched' is in the insight's trigger list.
await Insightdive.trigger('app_launched');

On network error the SDK falls through and opens the survey anyway (fail-open).

Frequency capping (cooldown)

isAvailable(), checkAvailability(), and trigger() all respect the cooldown configured on the insight (Admin → Insight → General → Cooldown). The last shown timestamp is stored in localStorage per tenant+survey pair. If the cooldown period hasn't elapsed the call resolves without showing the modal.

Operator context fields

Stamp arbitrary application context on every submission — plan tier, feature flags, active surface, A/B cohort — without collecting any user identity. The admin can filter, segment, and run AI analysis per context dimension.

Insightdive.configure({
  tenant: 'acme',
  survey: 'onboarding',
  apiKey: 'ik_abc123...',
  context: {
    plan: 'enterprise',
    trialDaysRemaining: 12,
    featureExportV2: true,
    surface: 'settings',
  } satisfies Record<string, string | number | boolean>,
});

Constraints (enforced server-side; invalid entries are silently dropped):

  • Max 20 keys per object
  • Key format: [a-z0-9_], max 64 characters
  • Values: string, number, or boolean — no nested objects
  • String values: max 255 characters
  • Total JSON payload: max 4 KB

Context values are visible in Admin → Responses (detail view) and included in CSV exports as context.<key> columns.


Respondent token

Let the operator correlate responses with their own user records — without ever exposing a user identity to Insightdive. Compute an opaque hash client-side and pass it as respondentToken:

async function computeToken(userId: string, workspaceSalt: string): Promise<string> {
  const data = new TextEncoder().encode(userId + workspaceSalt);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  return Array.from(new Uint8Array(hashBuffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

Insightdive.configure({
  tenant: 'acme',
  survey: 'onboarding',
  apiKey: 'ik_abc123...',
  respondentToken: await computeToken(currentUser.id, 'my-secret-salt'),
});

What Insightdive stores: the hash only — no ability to reverse it to a user.
What the operator can do: compute the same hash from their own database and look up all responses for that hash in Admin → Responses.
GDPR note: Insightdive is a processor with no identification capability. The operator (controller) owns the correlation.

Tip: rotate workspaceSalt if you want to "forget" historical correlations without deleting data.

Constraints: max 128 characters, characters [a-zA-Z0-9-_] only.


Screenshot capture

When an insight has screenshot collection enabled (Admin → Insight → Settings → Delivery), the SDK captures the current page with html2canvas right before the modal opens and attaches it to the response. The screenshot is of the page UI — never the user.

  • No setup required: html2canvas is loaded lazily (dynamic import()), so it only enters the bundle graph when a screenshot is actually captured.
  • The flag is read from the status endpoint, so call isAvailable() / checkAvailability() / trigger() before show() for the SDK to know capture is on.
  • Capture is best-effort: any failure is swallowed and the survey still opens.
  • The image is downscaled to ≤1280px wide and encoded as JPEG to keep the payload small.
// Capture happens automatically inside show() when the insight opted in.
if (await Insightdive.isAvailable()) {
  await Insightdive.show();
}

Advanced availability check

checkAvailability() returns the full status payload for diagnostics:

const { available, reason, error } = await Insightdive.checkAvailability();
// reason: 'disabled' | 'not_published' | 'not_found' | 'cooldown'
// error: set on network failure
if (!available) console.warn('Survey unavailable:', reason ?? error);

TypeScript

All types are exported:

import type {
  InsightdiveOptions,
  FeedbackResult,
  FeedbackEvent,
  FeedbackCompletedEvent,
} from '@insightdive/sdk';

Platform support

Works in all modern browsers (Chrome, Firefox, Safari, Edge). Requires a DOM environment — not suitable for Node.js server-side rendering without conditional guards.

Privacy

The SDK does not collect or transmit any user-identifying data by default. Only deploymentId, optional productVersion, optional productIdentifier, locale, and theme are forwarded to the server. Submissions are linked to a SurveySession via an opaque id that never leaves the device tied to anything personal. Insightdive cannot identify any respondent — anonymous to us by architecture.

The optional context map contains only operator-stamped metadata — no PII. The optional respondentToken is an opaque hash the operator computes themselves; Insightdive never decodes it.

License

MIT. See LICENSE.