Skip to main content
The vij-sdk provides two main APIs for capturing errors and messages: captureException() for error objects and captureMessage() for custom log messages.

captureException()

Capture and send error objects to your VIJ Admin dashboard.

Basic Usage

import { captureException } from "vij-sdk";

try {
  // Code that might throw an error
  const result = riskyOperation();
} catch (error) {
  captureException(error);
}

Signature

captureException(
  error: Error,
  metadata?: Record<string, any>,
  severity?: "error" | "warning" | "info"
): void

Parameters

error
Error
required
The error object to capture. Can be any JavaScript Error instance or object with name, message, and stack properties.Supported Types:
  • Native JavaScript errors (Error, TypeError, ReferenceError, etc.)
  • Custom error classes extending Error
  • Objects with error-like structure
// Native error
captureException(new Error("Something went wrong"));

// Custom error class
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}
captureException(new ValidationError("Invalid email format"));

// Error from catch block
try {
  await fetchData();
} catch (error) {
  captureException(error);
}
metadata
object
default:"{}"
Additional contextual information to attach to this specific error.Use Cases:
  • User information (ID, email, role)
  • Request details (URL, method, headers)
  • Application state at time of error
  • Feature or component context
captureException(error, {
  userId: "user-123",
  userEmail: "user@example.com",
  feature: "checkout",
  cartTotal: 99.99,
  requestUrl: "/api/payment",
  requestMethod: "POST"
});
Metadata is merged with global metadata from init(). Per-error metadata takes precedence.
severity
string
default:"error"
The severity level of this error.Options:
  • "error" - Critical errors requiring immediate attention
  • "warning" - Non-critical issues that should be investigated
  • "info" - Informational logs for tracking behavior
// Critical error
captureException(error, { feature: "payment" }, "error");

// Non-critical warning
captureException(deprecationError, { api: "legacy" }, "warning");

// Informational
captureException(new Error("Rate limit approaching"), {}, "info");
Severity levels help you filter and prioritize errors in the dashboard.

Automatic Error Capture

The SDK automatically captures uncaught errors and unhandled promise rejections without any additional code:
  • Browser
  • Node.js
// Automatically captured - no try/catch needed
window.addEventListener("click", () => {
  throw new Error("Button click error"); // Captured automatically
});

// Unhandled promise rejection - automatically captured
fetch("/api/data").then(response => {
  throw new Error("Processing failed"); // Captured automatically
});
Browser Events Captured:
  • window.onerror - Uncaught exceptions
  • window.onunhandledrejection - Unhandled promise rejections
While automatic capture is convenient, it’s better to explicitly catch and handle errors in production code. Use captureException() in catch blocks for better control.

Advanced Examples

Capturing with Rich Metadata

import { captureException } from "vij-sdk";

async function processPayment(userId, amount) {
  try {
    const payment = await stripeAPI.charge({ userId, amount });
    return payment;
  } catch (error) {
    captureException(error, {
      // User context
      userId: userId,
      userPlan: "premium",

      // Transaction context
      paymentAmount: amount,
      currency: "USD",

      // Application state
      cartItems: 5,
      discountApplied: true,

      // Technical details
      stripeApiVersion: "2023-10-16",
      timestamp: new Date().toISOString()
    });

    throw error; // Re-throw after capturing
  }
}

Capturing Errors in React Components

import { captureException } from "vij-sdk";
import { Component } from "react";

class ErrorBoundary extends Component {
  componentDidCatch(error, errorInfo) {
    captureException(error, {
      componentStack: errorInfo.componentStack,
      route: window.location.pathname,
      userAgent: navigator.userAgent
    });
  }

  render() {
    return this.props.children;
  }
}

Capturing Errors in Express Middleware

import { captureException } from "vij-sdk";

app.use((err, req, res, next) => {
  captureException(err, {
    requestUrl: req.originalUrl,
    requestMethod: req.method,
    requestHeaders: req.headers,
    requestBody: req.body,
    userId: req.user?.id,
    ipAddress: req.ip
  });

  res.status(500).json({ error: "Internal server error" });
});

captureMessage()

Capture custom log messages without an error object.

Basic Usage

import { captureMessage } from "vij-sdk";

captureMessage("User logged in successfully");

Signature

captureMessage(
  message: string,
  metadata?: Record<string, any>,
  severity?: "error" | "warning" | "info"
): void

Parameters

message
string
required
The log message to capture.Best Practices:
  • Use clear, descriptive messages
  • Include relevant details in the message or metadata
  • Keep messages concise but informative
// Good
captureMessage("Payment processed successfully for order #12345");

// Better - use metadata
captureMessage("Payment processed successfully", { orderId: 12345 });
metadata
object
default:"{}"
Additional contextual information to attach to this message.
captureMessage("User action", {
  action: "button_click",
  buttonId: "checkout",
  userId: "user-123",
  timestamp: Date.now()
});
severity
string
default:"info"
The severity level of this message.Options:
  • "info" - Informational messages (default for captureMessage)
  • "warning" - Warning messages
  • "error" - Error messages
// Info level (default)
captureMessage("User logged in", { userId: "123" }, "info");

// Warning level
captureMessage("Rate limit approaching", { requestCount: 950 }, "warning");

// Error level
captureMessage("Configuration missing", { key: "API_KEY" }, "error");

Use Cases

  • User Actions
  • System Events
  • Performance Monitoring
  • Business Logic
import { captureMessage } from "vij-sdk";

function trackUserAction(action, details) {
  captureMessage(`User action: ${action}`, {
    userId: details.userId,
    actionType: action,
    timestamp: new Date().toISOString(),
    ...details
  }, "info");
}

// Track button clicks
trackUserAction("checkout_clicked", {
  userId: "user-123",
  cartValue: 99.99
});

// Track form submissions
trackUserAction("form_submitted", {
  formId: "contact-form",
  fields: 5
});

Contextual Information

Both captureException() and captureMessage() automatically collect rich contextual information:

Browser Context

{
  "viewport": {
    "width": 1920,
    "height": 1080
  },
  "screen": {
    "width": 1920,
    "height": 1080,
    "colorDepth": 24
  },
  "browser": {
    "userAgent": "Mozilla/5.0...",
    "language": "en-US",
    "platform": "MacIntel",
    "cookieEnabled": true,
    "doNotTrack": "1"
  },
  "network": {
    "effectiveType": "4g",
    "downlink": 10,
    "rtt": 50
  }
}

Node.js Context

{
  "process": {
    "pid": 12345,
    "platform": "linux",
    "arch": "x64",
    "nodeVersion": "v20.0.0",
    "uptime": 3600,
    "memory": {
      "rss": 50000000,
      "heapTotal": 30000000,
      "heapUsed": 20000000,
      "external": 1000000
    }
  }
}
This context is collected automatically. You don’t need to add it manually.

Best Practices

Add contextual information that will help debug the issue:
// Good
captureException(error, {
  userId: user.id,
  feature: "checkout",
  step: "payment",
  paymentMethod: "stripe"
});

// Bad
captureException(error); // Missing context
Error: Critical issues requiring immediate attention
captureException(paymentError, { orderId: 123 }, "error");
Warning: Issues that should be investigated but aren’t critical
captureException(deprecatedApiWarning, {}, "warning");
Info: Tracking and informational purposes
captureMessage("Feature flag enabled", { flag: "new-ui" }, "info");
Never log passwords, tokens, or PII without sanitization:
// Bad
captureException(error, {
  password: user.password, // Never log passwords!
  creditCard: user.card // Never log card numbers!
});

// Good
captureException(error, {
  userId: user.id, // Use IDs instead
  hasPaymentMethod: !!user.card // Use boolean flags
});
Avoid overwhelming your VIJ instance with duplicate errors:
// Bad
for (let i = 0; i < 10000; i++) {
  try {
    processItem(i);
  } catch (error) {
    captureException(error); // Will create 10000 errors!
  }
}

// Good - batch errors or add deduplication
const errors = [];
for (let i = 0; i < 10000; i++) {
  try {
    processItem(i);
  } catch (error) {
    errors.push({ index: i, error });
  }
}
if (errors.length > 0) {
  captureException(new Error(`Batch processing failed`), {
    failedCount: errors.length,
    totalItems: 10000
  });
}
Capture the error but don’t swallow it:
// Good
try {
  await criticalOperation();
} catch (error) {
  captureException(error, { operation: "critical" });
  throw error; // Re-throw for upstream handling
}

// Bad
try {
  await criticalOperation();
} catch (error) {
  captureException(error);
  // Swallowed! Upstream code won't know about the error
}

Integration Patterns

React Error Boundary

import { Component } from "react";
import { captureException } from "vij-sdk";

class ErrorBoundary extends Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    captureException(error, {
      componentStack: errorInfo.componentStack,
      route: window.location.pathname
    });
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

Vue Error Handler

import { createApp } from "vue";
import { captureException } from "vij-sdk";

const app = createApp(App);

app.config.errorHandler = (err, instance, info) => {
  captureException(err, {
    componentName: instance?.$options?.name,
    errorInfo: info,
    route: window.location.pathname
  });
};

app.mount("#app");

Express Error Middleware

import express from "express";
import { captureException } from "vij-sdk";

const app = express();

// Routes...

// Error handling middleware (must be last)
app.use((err, req, res, next) => {
  captureException(err, {
    url: req.originalUrl,
    method: req.method,
    headers: req.headers,
    body: req.body,
    params: req.params,
    query: req.query,
    userId: req.user?.id
  });

  res.status(500).json({ error: "Internal server error" });
});

Async/Await Error Handling

import { captureException } from "vij-sdk";

async function fetchUserData(userId) {
  try {
    const response = await fetch(`/api/users/${userId}`);

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    return await response.json();
  } catch (error) {
    captureException(error, {
      operation: "fetchUserData",
      userId,
      timestamp: new Date().toISOString()
    });

    throw error;
  }
}

Troubleshooting

Check the following:
  1. Verify init() was called before captureException()
  2. Check browser console/server logs for network errors
  3. Ensure VIJ Admin endpoint is accessible
  4. Verify batching settings aren’t delaying delivery too long
  5. Check that error object has name, message, and stack properties
Debug: Disable batching for immediate delivery
init({ batch: false, /* ... */ });
Cause: Same error being captured multiple timesSolutions:
  • Check if error is being captured in both automatic handlers and manual try/catch
  • Implement deduplication logic for recurring errors
  • Use error grouping features in VIJ Admin dashboard
Learn more about error grouping →
Issue: Custom metadata not showing in dashboardSolution: Ensure metadata is JSON-serializable
// Bad - circular reference
const obj = { name: "test" };
obj.self = obj;
captureException(error, { obj }); // Will fail

// Good
captureException(error, { name: "test", id: 123 });

Next Steps