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

@vibesignals/observe

v1.0.5

Published

The simplest observability integration ever - Dual-mode support (Custom Events + OpenTelemetry OTLP), zero-config, framework agnostic

Downloads

602

Readme

Vibesignals SDK

The Simplest Observability Integration Ever

Zero-config observability for modern applications with dual-mode support: use custom events for business analytics OR OpenTelemetry OTLP for standards-compliant observability. Just 2 lines of code to get started.

npm version License: MIT TypeScript OpenTelemetry

✨ Features

  • 🚀 Zero Configuration - Works out of the box with sensible defaults
  • 📦 Flexible Bundle - 58KB for custom events, 176KB with full OpenTelemetry support
  • 🎯 Dual Mode Support - Choose custom events OR OpenTelemetry OTLP (or both!)
  • 🔧 Three Operating Modes:
    • Custom Events: Flexible business analytics (default)
    • OpenTelemetry OTLP: Standards-compliant observability
    • Hybrid: Best of both worlds
  • 🌐 Framework Agnostic - Works with Express, Next.js, React, Vue, Angular, and vanilla JavaScript
  • 💪 TypeScript First - Full type safety and IntelliSense support
  • 🛡️ Privacy Focused - Built-in data sanitization and masking
  • ⚡ High Performance - Minimal overhead (<50ms)
  • 📊 Rich Insights - Errors, performance, traces, metrics, and more

🎯 Quick Start

Installation

npm install @vibesignals/observe

Mode 1: Custom Events (Default - Simplest)

Perfect for business analytics, custom metrics, and flexible event tracking.

import { observe } from '@vibesignals/observe';

observe.init('YOUR_API_KEY');
// Done! Everything is now being tracked automatically ✨

// Track custom events
observe.event('user.signup', { plan: 'premium' });
observe.metric('checkout.duration', 1234);

You now have:

  • ✅ Error tracking
  • ✅ Performance monitoring (Web Vitals)
  • ✅ HTTP request tracing
  • ✅ Console log capture
  • ✅ Custom events and metrics

API Endpoint: POST /api/v1/events/batch


Mode 2: OpenTelemetry OTLP (Standards-Compliant)

Perfect for distributed tracing, microservices, and vendor-neutral observability.

import { otlp } from '@vibesignals/observe';

// Configure OpenTelemetry OTLP exporters
const { tracer, meter } = await otlp.configureOTLP({
  apiKey: 'YOUR_API_KEY',
  serviceName: 'my-service',
  serviceVersion: '1.0.0',
  // endpoint: 'https://custom-backend.com', // Optional: only for dev/testing/self-hosted
});

// Use OpenTelemetry Tracer API
const span = tracer.startSpan('process-order');
span.setAttribute('order.id', '12345');
span.end();

// Use OpenTelemetry Metrics API
const counter = meter.createCounter('orders.total');
counter.add(1, { status: 'completed' });

You now have:

  • ✅ OTLP/HTTP traces (Protobuf or JSON)
  • ✅ OTLP/HTTP metrics (counters, histograms, gauges)
  • ✅ Distributed tracing with W3C Trace Context
  • ✅ OpenTelemetry Semantic Conventions
  • ✅ Vendor-neutral telemetry

API Endpoints:

  • POST /v1/traces (OTLP)
  • POST /v1/metrics (OTLP)
  • POST /v1/logs (OTLP)

Mode 3: Hybrid (Best of Both Worlds)

Perfect for comprehensive monitoring - business events + technical observability.

import { observe, otlp } from '@vibesignals/observe';

// Initialize both systems
observe.init('YOUR_API_KEY', {
  mode: 'hybrid',
});

const { tracer } = await otlp.configureOTLP({
  apiKey: 'YOUR_API_KEY',
  serviceName: 'ecommerce-api',
});

// Use both together
async function processOrder(orderId) {
  // Start OTLP trace
  const span = tracer.startSpan('process-order');
  const spanContext = span.spanContext();

  try {
    // ... your business logic ...

    // Send custom business event linked to trace
    observe.event('order.completed', {
      order_id: orderId,
      // Link to distributed trace
      trace_id: spanContext.traceId,
      span_id: spanContext.spanId,
    });

    span.setStatus({ code: SpanStatusCode.OK });
  } catch (error) {
    span.recordException(error);
    observe.event('order.failed', {
      order_id: orderId,
      error: error.message,
      trace_id: spanContext.traceId,
    });
    throw error;
  } finally {
    span.end();
  }
}

You now have:

  • ✅ Custom business events
  • ✅ OpenTelemetry distributed traces
  • ✅ Events linked to traces (query together in ClickHouse!)
  • ✅ Comprehensive monitoring

Both API endpoints used!


📊 Mode Comparison

| Feature | Custom Events | OpenTelemetry OTLP | Hybrid | |---------|--------------|-------------------|---------| | Setup | 2 lines | ~10 lines | Both | | Bundle Size | ~58KB | ~176KB | ~176KB | | Use Case | Business analytics | Technical observability | Both | | Standards | Proprietary | CNCF OpenTelemetry | Both | | Learning Curve | Low | Medium | Medium | | Best For | Simple apps, custom metrics | Microservices, distributed systems | Comprehensive monitoring |


📚 Documentation

Core Documentation

Integration Guides

Advanced


🔧 Configuration

Custom Events Mode Configuration

observe.init('YOUR_API_KEY', {
  // Mode selection
  mode: 'custom-events', // 'custom-events' | 'otlp' | 'hybrid'

  // Connection (endpoint is optional - only for dev/testing/self-hosted)
  // endpoint: 'http://localhost:8080', // Optional: defaults to https://api.vibesignals.ai
  environment: 'production',
  release: 'v1.2.3',

  // Batching
  batchSize: 1000,
  maxBatchSize: 10000,
  flushInterval: 5000,

  // Auto-instrumentation
  autoInstrument: true,
  captureConsole: true,
  captureErrors: true,
  capturePerformance: true,
  captureHttp: true,

  // Sampling
  sampleRate: 1.0, // 100% of events

  // Filter/modify events
  beforeSend: (event) => {
    delete event.context.user?.email;
    return event;
  },

  // Privacy controls
  privacy: {
    maskEmails: true,
    maskIPs: true,
    sensitiveKeys: ['password', 'token', 'apiKey'],
  },

  // Retry strategy
  retry: {
    maxRetries: 3,
    initialDelay: 1000,
    maxDelay: 60000,
    backoffMultiplier: 2,
    jitter: true,
  },
});

OpenTelemetry OTLP Configuration

const { tracer, meter, shutdown } = await otlp.configureOTLP({
  // Required
  apiKey: 'YOUR_API_KEY',
  serviceName: 'my-service',

  // Optional
  endpoint: 'http://localhost:8080', // Base URL
  serviceVersion: '1.0.0',
  useTLS: false, // Auto-detected for localhost

  // Resource attributes (added to all telemetry)
  resourceAttributes: {
    'deployment.environment': 'production',
    'service.namespace': 'backend',
    'host.name': 'server-1',
  },
});

// Remember to shutdown on process exit
process.on('SIGTERM', async () => {
  await shutdown();
  process.exit(0);
});

Development Mode

Enable dev mode to see what's being tracked in your console:

observe.init('YOUR_API_KEY', {
  dev: true, // Pretty prints to console instead of sending
});

// Output:
// 🔍 [Vibesignals] HTTP
//    Data: { method: 'GET', url: '/api/users', duration: 145 }
// ⚠️  [Vibesignals] ERROR
//    Data: { message: 'Database connection failed' }

🎨 Framework Integrations

Express.js (Custom Events)

import express from 'express';
import { observe, integrations } from '@vibesignals/observe';

observe.init('YOUR_API_KEY');

const app = express();

// Add Vibesignals middleware
const expressIntegration = integrations.Express();
app.use(expressIntegration.middleware());

// Error handler
app.use(expressIntegration.errorHandler());

app.listen(3000);

Express.js (OpenTelemetry)

import express from 'express';
import { otlp } from '@vibesignals/observe';

const { tracer } = await otlp.configureOTLP({
  apiKey: 'YOUR_API_KEY',
  serviceName: 'express-api',
});

const app = express();

app.get('/api/users', async (req, res) => {
  const span = tracer.startSpan('GET /api/users');
  try {
    const users = await fetchUsers();
    span.setStatus({ code: SpanStatusCode.OK });
    res.json(users);
  } finally {
    span.end();
  }
});

app.listen(3000);

Next.js

// pages/_app.tsx
import { observe, integrations } from '@vibesignals/observe';

observe.init('YOUR_API_KEY');

const nextIntegration = integrations.NextJS();

export default nextIntegration.wrapApp(MyApp);

React

import { observe, integrations } from '@vibesignals/observe';

observe.init('YOUR_API_KEY');

const reactIntegration = integrations.React();
const ErrorBoundary = reactIntegration.createErrorBoundary();

function App() {
  return (
    <ErrorBoundary>
      <YourApp />
    </ErrorBoundary>
  );
}

Vue.js

import { createApp } from 'vue';
import { observe, integrations } from '@vibesignals/observe';

observe.init('YOUR_API_KEY');

const app = createApp(App);
const vueIntegration = integrations.Vue();
vueIntegration.install(app);

Angular

// app.module.ts
import { ErrorHandler } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { observe, integrations } from '@vibesignals/observe';

observe.init('YOUR_API_KEY');

const angularIntegration = integrations.Angular();
const providers = angularIntegration.createAngularProviders(angularIntegration);

@NgModule({
  providers: [
    { provide: ErrorHandler, useClass: providers.ErrorHandler },
    { provide: HTTP_INTERCEPTORS, useClass: providers.HttpInterceptor, multi: true },
  ]
})
export class AppModule {}

🎯 Manual Instrumentation

Custom Events & Metrics

import { observe } from '@vibesignals/observe';

// Track custom events
observe.event('button_clicked', {
  button_id: 'signup-cta',
  page: '/pricing',
});

// Track metrics
observe.metric('cart.value', 149.99, {
  currency: 'USD',
  items: 3,
});

// Trace function execution
await observe.trace('process-payment', async () => {
  return await processPayment();
}, {
  payment_method: 'stripe',
});

// Manual span creation
const span = observe.startSpan('database-query');
span.setTag('query_type', 'select');
await executeQuery();
span.finish();

OpenTelemetry Tracing

import { otlp, SpanStatusCode } from '@vibesignals/observe';

const { tracer } = await otlp.configureOTLP({...});

// Manual span
const span = tracer.startSpan('operation-name');
span.setAttribute('user.id', userId);
span.addEvent('processing started');
span.setStatus({ code: SpanStatusCode.OK });
span.end();

// Nested spans
const parentSpan = tracer.startSpan('parent-operation');
const childSpan = tracer.startSpan('child-operation', {
  parent: parentSpan.spanContext(),
});
childSpan.end();
parentSpan.end();

OpenTelemetry Metrics

const { meter } = await otlp.configureOTLP({...});

// Counter (monotonically increasing)
const requestCounter = meter.createCounter('http.requests', {
  description: 'Total HTTP requests',
});
requestCounter.add(1, { method: 'GET', status: 200 });

// Histogram (distribution)
const latencyHistogram = meter.createHistogram('http.latency', {
  description: 'HTTP request latency',
  unit: 'ms',
});
latencyHistogram.record(123.45, { route: '/api/users' });

// UpDownCounter (can increase/decrease)
const activeConnections = meter.createUpDownCounter('connections.active');
activeConnections.add(1); // New connection
activeConnections.add(-1); // Connection closed

User Context

import { observe } from '@vibesignals/observe';

// Set user context
observe.setUser({
  id: 'user_123',
  email: '[email protected]',
  username: 'johndoe',
  subscription: 'premium',
});

// Set custom context
observe.setContext('cart', {
  items: 3,
  total: 149.99,
});

// Clear context
observe.clearContext();

🚀 Advanced Features

Error Tracking

// Automatically tracked
throw new Error('Something went wrong');

// Manually track
try {
  riskyOperation();
} catch (error) {
  observe.event('operation.failed', {
    error: error.message,
    stack: error.stack,
  });
}

Performance Monitoring

Automatically tracks:

  • ✅ Page Load Time
  • ✅ Web Vitals (LCP, FID, CLS)
  • ✅ HTTP Request Duration
  • ✅ Custom Performance Marks
// Custom performance tracking
await observe.trace('heavy-operation', async () => {
  return await heavyComputation();
});

HTTP Request Tracking

Automatically captures:

  • ✅ Method, URL, Status Code
  • ✅ Request/Response Duration
  • ✅ Headers (sanitized)
  • ✅ Errors and Timeouts

Privacy & Security

observe.init('YOUR_API_KEY', {
  privacy: {
    maskEmails: true,      // [email protected] → u***@example.com
    maskIPs: true,         // 192.168.1.1 → 192.168.*.*
    sensitiveKeys: [       // Remove these keys from all data
      'password',
      'creditCard',
      'ssn',
      'apiKey',
    ],
  },

  beforeSend: (event) => {
    // Custom filtering
    if (event.data.sensitive) {
      return null; // Drop the event
    }
    return event;
  },
});

📦 Bundle Size

| Mode | Bundle Size | Notes | |------|-------------|-------| | Custom Events | ~58KB | Lightweight, zero dependencies | | OpenTelemetry OTLP | ~176KB | Includes OpenTelemetry SDKs | | Hybrid | ~176KB | Both modes available |

Optimization tip: Use dynamic imports to lazy-load OTLP:

// Only load when needed
if (shouldEnableOTLP) {
  const { otlp } = await import('@vibesignals/observe');
  await otlp.configureOTLP({...});
}

🗄️ Data Storage (ClickHouse)

Tables

| Table | API | Purpose | |-------|-----|---------| | events | Custom Events | Business events, flexible JSON schema | | otlp_traces | OTLP | Distributed tracing spans | | otlp_metrics | OTLP | Metrics (counters, histograms, gauges) | | otlp_logs | OTLP | Application logs |

Cross-Table Queries

Link custom events to OTLP traces:

-- Find all data for a trace
SELECT 'trace' AS type, name, start_time
FROM otlp_traces
WHERE trace_id = '0af7651916cd43dd8448eb211c80319c'

UNION ALL

SELECT 'event' AS type, event_type, timestamp
FROM events
WHERE JSONExtractString(data, 'trace_id') = '0af7651916cd43dd8448eb211c80319c'

ORDER BY timestamp;

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.


📄 License

MIT © Vibesignals


🔗 Links


💡 Need Help?


Built with ❤️ by the Vibesignals team

🚀 Start monitoring your application in 2 minutes!