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

@micrologs/node

v1.1.0

Published

Node.js SDK for Micrologs - self-hosted analytics and error tracking

Downloads

16

Readme

@micrologs/node

npm

Node.js SDK for Micrologs - self-hosted analytics and error tracking.

Requires Node.js 18+


How it works

Micrologs is an engine you install on your own server. You own the database, you own the data. This SDK is a thin wrapper around its REST API - it makes HTTP calls to your server, not to any third-party service.

Your Node app  →  SDK  →  your Micrologs server  →  your database

Nothing goes anywhere you don't control.


Install

npm install @micrologs/node

Initialize

// CommonJS
const Micrologs = require("@micrologs/node")

// ESM
import Micrologs from "@micrologs/node"

const client = new Micrologs({
    host: "https://analytics.yourdomain.com", // your server - where Micrologs is installed
    key:  "your_secret_key"                   // your project secret key
})

Both host and key are required. The constructor will throw immediately if either is missing.

host is the URL of the server where you installed Micrologs. key is the secret key for your project - find it in your env.php. Never use the public key here - that's for the JS snippet only.


Tracking

Track an error

Use this to send errors from your Node backend to Micrologs. Works alongside the JS snippet - the snippet catches frontend errors, this catches backend errors.

try {
    await processPayment(order)
} catch (err) {
    await client.error(err.message, {
        type:        "CheckoutError",      // groups errors of the same type together
        severity:    "critical",           // info | warning | error | critical
        file:        "checkout.js",
        line:        42,
        stack:       err.stack,
        url:         "/api/checkout",
        environment: "production",         // default: "production"
        context:     { order_id: 123, amount: 2999 } // any extra data, capped at 8KB
    })
}

All fields except message are optional.

How grouping works: Micrologs hashes error_type + message + file + line into a fingerprint. The same error firing 1000 times creates 1 group with 1000 occurrences - not 1000 separate records. If you mark a group as resolved and it fires again, it automatically reopens.

Response:

{
    "success": true,
    "message": "OK",
    "data": {
        "group_id": 12
    }
}

group_id is the error group this occurrence was added to. Useful for logging on your side.


Track an audit event

Use this to record any action that matters in your application - logins, payments, config changes, anything you want a trail for.

// action (required), actor (optional), context (optional)
await client.audit("user.login",        "[email protected]", { ip: "1.2.3.4", role: "admin" })
await client.audit("order.placed",      "[email protected]", { order_id: 123, amount: 2999 })
await client.audit("settings.updated",  "[email protected]")
await client.audit("api_key.rotated",   "[email protected]")

action is a free-form string - use dot notation by convention (resource.action) for easy filtering. actor is whoever triggered the action. context is any extra data you want attached.


Link management

Create a tracked short link

const link = await client.createLink(
    "https://yourdomain.com/pricing", // destination URL
    "Pricing CTA"                     // optional label
)

console.log(link.data)
// {
//     code:            "aB3xYz12",
//     short_url:       "https://analytics.yourdomain.com/api/redirect.php?c=aB3xYz12",
//     destination_url: "https://yourdomain.com/pricing",
//     label:           "Pricing CTA"
// }

Every click on the short link is tracked with timestamp, referrer, and location. Query click analytics via client.analytics.linkDetail({ code: "aB3xYz12" }).

Delete a link

await client.deleteLink("aB3xYz12")

Get a single link

const link = await client.getLink("aB3xYz12")
// Returns link details including total_clicks

Edit a link

// Any combination of fields - all optional except code
await client.editLink("aB3xYz12", {
    destinationUrl: "https://yourdomain.com/new-page",
    label:          "Updated CTA",
    isActive:       false
})

Analytics

All analytics methods return data from your Micrologs server as plain JSON. Every response follows this shape:

{
    "success": true,
    "message": "...",
    "data": { ... }
}

Access your data via result.data.

Common params

All analytics methods accept an optional params object:

| Param | Type | Default | Description | |---|---|---|---| | range | string | "30d" | "7d" / "30d" / "90d" / "custom" | | from | string | - | "YYYY-MM-DD" - required when range="custom" | | to | string | - | "YYYY-MM-DD" - required when range="custom" |

Custom ranges are capped at 365 days and from must be before to.


Visitors

const result = await client.analytics.visitors({ range: "30d" })

console.log(result.data)
// {
//     range:           { from: "2026-01-31", to: "2026-03-01" },
//     unique_visitors: 1842,
//     total_pageviews: 5631,
//     total_sessions:  2109,
//     bounce_rate:     43.2,
//     over_time: [
//         { date: "2026-01-31", pageviews: 178, unique_visitors: 91 },
//         { date: "2026-02-01", pageviews: 204, unique_visitors: 113 },
//         ...
//     ]
// }

New vs returning visitors

const result = await client.analytics.returning({ range: "30d" })

console.log(result.data)
// {
//     total_visitors:     500,
//     new_visitors:       340,
//     returning_visitors: 160,
//     new_pct:            68.0,
//     returning_pct:      32.0,
//     over_time: [
//         { date: "2026-02-01", new_visitors: 12, returning_visitors: 5 },
//         ...
//     ]
// }

New = first visit falls within the selected range. Returning = visited before the range and came back within it.


Sessions

const result = await client.analytics.sessions({ range: "7d" })

console.log(result.data)
// {
//     total_sessions:        2109,
//     bounce_rate:           43.2,
//     avg_duration_seconds:  91,   // all sessions including bounces
//     avg_duration_engaged:  180,  // bounced sessions excluded - more honest number
//     avg_pages_per_session: 2.67,
//     over_time: [
//         { date: "2026-02-01", sessions: 45, avg_duration_seconds: 120 },
//         ...
//     ]
// }

avg_duration_engaged excludes bounced sessions (visitors who left immediately). It's a more accurate measure of how long engaged users actually stay.


Pages

const result = await client.analytics.pages({ range: "30d", limit: 10 })

console.log(result.data)
// [
//     { url: "/", page_title: "Home", pageviews: 1200, unique_visitors: 800 },
//     { url: "/pricing", page_title: "Pricing", pageviews: 430, unique_visitors: 310 },
//     ...
// ]

Locations

const result = await client.analytics.locations({ range: "30d" })
// Breakdown by country, region, and city

Devices

const result = await client.analytics.devices({ range: "30d" })
// Breakdown by device type (desktop/mobile/tablet), OS, browser

Referrers

const result = await client.analytics.referrers({ range: "30d" })
// Traffic sources categorized: organic, social, email, referral, direct

UTM campaigns

const result = await client.analytics.utm({ range: "30d" })
// Breakdown by utm_source, utm_medium, utm_campaign

Errors

// All error groups
const result = await client.analytics.errors({ range: "30d" })

// Daily error trend across all groups
const trend = await client.analytics.errorsTrend({ range: "30d" })

// Daily trend for one specific error group
const groupTrend = await client.analytics.errorsTrend({ range: "30d", group_id: 12 })

// Full detail for one error group - all occurrences, stack traces, context
const detail = await client.analytics.errorDetail({ id: 12 })

Update error status

Mark error groups as investigating, resolved, ignored, or reopen as open. Accepts a single ID or an array of up to 100.

// Start investigating
await client.updateErrorStatus(42, "investigating")

// Resolve a single group
await client.updateErrorStatus(42, "resolved")

// Bulk ignore
await client.updateErrorStatus([12, 15, 22], "ignored")

Audit log

const result = await client.analytics.audits({ range: "7d" })

Tracked links

// All links with click counts
const result = await client.analytics.links({ range: "30d" })

// Detail for one link - clicks over time
const detail = await client.analytics.linkDetail({ code: "aB3xYz12", range: "30d" })

Custom date range

const result = await client.analytics.visitors({
    range: "custom",
    from:  "2026-01-01",
    to:    "2026-01-31"
})

Verify a key

const result = await client.verify("some_key")
// Returns whether the key is valid and which project it belongs to

Error handling

The SDK never throws or crashes your application. If a network error occurs, the server is unreachable, or the server returns an error - the method returns null and logs a warning via console.warn. This is intentional.

const result = await client.error("Payment failed")

if (result === null) {
    // SDK call failed - your server may be unreachable
    // Your application continues normally regardless
}

Analytics failures should never affect your application's users.


Full method reference

| Method | Description | |---|---| | client.error(message, options?) | Track a backend error | | client.audit(action, actor?, context?) | Track an audit event | | client.createLink(destinationUrl, label?) | Create a tracked short link | | client.getLink(code) | Fetch a single tracked link by code | | client.editLink(code, options?) | Edit a link's destination, label, or active state | | client.deleteLink(code) | Delete a tracked link by code | | client.updateErrorStatus(ids, status) | Update error group status - single ID or array | | client.verify(key) | Verify a public or secret key | | client.analytics.visitors(params?) | Unique visitors, pageviews, sessions, bounce rate | | client.analytics.returning(params?) | New vs returning visitors | | client.analytics.sessions(params?) | Session duration, pages per session | | client.analytics.pages(params?) | Top pages by pageviews | | client.analytics.devices(params?) | Device, OS, browser breakdown | | client.analytics.locations(params?) | Country, region, city breakdown | | client.analytics.referrers(params?) | Traffic sources | | client.analytics.utm(params?) | UTM campaign data | | client.analytics.errors(params?) | Error groups with occurrence counts | | client.analytics.errorsTrend(params?) | Daily error trend, top groups | | client.analytics.errorDetail(params?) | Single error group - all occurrences and detail | | client.analytics.audits(params?) | Audit log events | | client.analytics.links(params?) | Tracked links with click counts | | client.analytics.linkDetail(params?) | Single link - clicks over time |


Requirements

  • Node.js 18+ - uses native fetch and private class fields (#field). No polyfills, no build step.
  • A running Micrologs server (v1.3.0+)

License

MIT - Om Dongaonkar