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

medusa-analytics

v0.0.53

Published

A starter for Medusa plugins.

Downloads

4,303

Readme

medusa-analytics

Medusa v2 admin analytics extension that adds orders and customers dashboards with custom admin APIs.

Plugin Overview

medusa-analytics adds an Analytics extension page to the Medusa Admin with:

  • Orders KPIs (total orders, revenue, AOV, pending/cancelled/delivered, returns, exchanges, fulfillment time)
  • Orders time-series charts (7 days, 30 days, 12 months)
  • Customer KPIs (guest, registered, total, deleted accounts)
  • Customer time-series charts (registered vs guest over time)
  • POS / Stores KPIs (net/gross sales, AOV, velocity, payment mix, staff, inventory performance, LTV, CSV export)

Aggregation uses paginated date-filtered Query API calls (no silent 50k cap). Day buckets respect plugin timezone (default Asia/Kolkata). Revenue prefers metadata.pos_charged_total for POS sales.

Medusa Compatibility

  • Built for Medusa v2
  • Package versions indicate Medusa 2.12.4 compatibility (@medusajs/framework, @medusajs/medusa)

Installation & Setup

1) Install

npm install medusa-analytics
yarn add medusa-analytics

2) Register plugin in medusa-config.ts / medusa-config.js

import { defineConfig } from "@medusajs/framework"

export default defineConfig({
  plugins: [
    {
      resolve: "medusa-analytics",
      options: {},
    },
  ],
})

3) Build and run

npx medusa plugin:build
npx medusa develop

4) Migrations

This plugin does not define custom models or migrations. No plugin-specific migration step is required.

Configuration (config.ts / plugin options)

| Option | Type | Required | Default | Description | |---|---|---|---|---| | timezone | string | No | Asia/Kolkata | IANA timezone for day/hour buckets | | guestEmail | string | No | [email protected] | Excluded from LTV / repeat metrics |

Example registration:

{
  resolve: "medusa-analytics",
  options: {
    timezone: "Asia/Kolkata",
    guestEmail: "[email protected]",
  }
}

Environment Variables

No runtime environment variables are consumed by the implemented analytics code.

| Variable | Required | Purpose | Example | |---|---|---|---| | None in implementation | - | - | - |

⚠️ Note: src/modules/README.md contains generic starter examples using process.env, but those are documentation snippets, not active plugin logic.

REST APIs / Routes

All implemented custom APIs are admin routes under /admin/analytics/*.

1) GET /admin/analytics/orders-summary

Returns orders KPI cards data and status counts (pending, cancelled, delivered) for a selected day range.

Auth requirement: Admin authenticated request (admin route context)

Query Params

| Name | Type | Required | Description | |---|---|---|---| | days | string \| number | No | Supports all (default), 0 (today), or integer day ranges (clamped between 1 and 365). |

Response Schema

| Field | Type | Description | |---|---|---| | totalOrders | number | Total orders in range. | | totalRevenue | number | Revenue sum excluding cancelled orders. | | aov | number | Average order value excluding cancelled orders. | | ordersToday | number | Orders created today. | | pendingOrders | number | Pending orders count. | | cancelledOrders | number | Cancelled orders count. | | deliveredOrders | number | Delivered orders count (based on fulfillments.delivered_at). | | exchangeOrders | number | Exchange order changes in range. | | returnOrders | number | Returns in range. | | avgFulfillmentTimeHours | number \| null | Average created_at -> first shipped_at duration. | | statusCounts | { pending?: number; cancelled?: number; delivered?: number } | Status breakdown used by charts/cards. |

Example

curl -X GET "http://localhost:9000/admin/analytics/orders-summary?days=30" \
  -H "Authorization: Bearer <ADMIN_TOKEN>"

2) GET /admin/analytics/orders-over-time

Returns orders time-series for charting.

Auth requirement: Admin authenticated request (admin route context)

Query Params

| Name | Type | Required | Description | |---|---|---|---| | period | string | No | one_week (default), one_month, 12_months, or one_year. |

Response Schema

| Field | Type | Description | |---|---|---| | dailyOrders | Array<{ date: string; orders_count: number; label?: string }> | Time-series points; monthly modes include optional month label. |

Example

curl -X GET "http://localhost:9000/admin/analytics/orders-over-time?period=one_year" \
  -H "Authorization: Bearer <ADMIN_TOKEN>"

3) GET /admin/analytics/customers-summary

Returns customer summary cards (guest, registered, total, deleted).

Auth requirement: Admin authenticated request (admin route context)

Query Params

| Name | Type | Required | Description | |---|---|---|---| | days | string \| number | No | Supports all (default), 0, or integer day ranges (clamped between 1 and 365). |

Response Schema

| Field | Type | Description | |---|---|---| | guestCount | number | Customers without account in range. | | registeredCount | number | Customers with account in range. | | totalCount | number | Total customers in range. | | deletedAccountsCount | number | Count of soft-deleted customer accounts (withDeleted: true). |

Example

curl -X GET "http://localhost:9000/admin/analytics/customers-summary?days=90" \
  -H "Authorization: Bearer <ADMIN_TOKEN>"

4) GET /admin/analytics/customers-over-time

Returns customer time-series split by registered vs guest.

Auth requirement: Admin authenticated request (admin route context)

Query Params

| Name | Type | Required | Description | |---|---|---|---| | period | string | No | one_week (default), one_month, 12_months, or one_year. |

Response Schema

| Field | Type | Description | |---|---|---| | series | Array<{ date: string; label?: string; registered_count: number; guest_count: number }> | Time-series rows for dual-line chart rendering. |

Example

curl -X GET "http://localhost:9000/admin/analytics/customers-over-time?period=one_month" \
  -H "Authorization: Bearer <ADMIN_TOKEN>"

5) POS analytics (/admin/analytics/pos/*)

Shared query params: from, to (ISO), location_id, sales_channel_id, source=pos|all|web.

| Endpoint | Purpose | |---|---| | GET /admin/analytics/pos/sales-summary | Gross/net/tax/AOV/tickets/returns/margin | | GET /admin/analytics/pos/sales-over-time | Velocity series (granularity=hour\|day\|week), including gross_margin per bucket | | GET /admin/analytics/pos/sales-by-category | Revenue and margin by one product category per line | | GET /admin/analytics/pos/sales-by-channel | Revenue by sales channel. Ignores sales_channel_id so every channel in range is included | | GET /admin/analytics/pos/promotion-performance | Line revenue and discount grouped by adjustment code | | GET /admin/analytics/pos/stored-value | Gift card and wallet totals. { available: false } when wallet tables are absent | | GET /admin/analytics/pos/payment-mix | Tender breakdown | | GET /admin/analytics/pos/product-sales | Top SKUs + ABC bucket | | GET /admin/analytics/pos/inventory-performance | Sell-through approx + on-hand | | GET /admin/analytics/pos/customers-summary | New/repeat/LTV (excludes guest email) | | GET /admin/analytics/pos/basket-pairs | Market-basket pairs | | GET /admin/analytics/pos/staff-summary | Sales / items-per-min / discounts / returns by cashier | | GET /admin/analytics/pos/export?format=csv | CSV export of POS orders |

Services

No custom service classes are implemented in this plugin.

The routes query Medusa data via Query graph pagination helpers in src/utils/analytics-helpers.ts and core modules (Modules.ORDER, Modules.CUSTOMER, Modules.USER).

Workflows & Steps (Medusa v2)

No custom workflows or steps are implemented in source code.

Subscribers / Event Hooks

No event subscribers are implemented in source code.

Admin UI / Widgets

This plugin ships a custom Admin route extension (not widget-zone injection).

Route: Analytics page

  • Location: Extensions sidebar as Analytics (ChartBar icon)
  • File: src/admin/routes/analytics/page.tsx
  • What it renders: Module switcher with three dashboards: Orders, Customers, and POS / Stores
  • Interactions: Tab/button switch between modules
  • Data consumed: Ecommerce analytics APIs + /admin/analytics/pos/*

Orders dashboard

  • File: src/admin/routes/analytics/components/OrdersDashboard.tsx
  • Renders:
    • KPI cards (orders, revenue, AOV, orders today, pending, cancelled, delivered, exchange, return)
    • Pie chart for order status
    • Pie chart for returns vs exchanges
    • Line chart for orders over time
  • Interactions:
    • Summary period selector (all, 0, 7, 30, 90)
    • Over-time period selector (one_week, one_month, one_year)
    • Clear filter action
  • Data consumed:
    • /admin/analytics/orders-summary
    • /admin/analytics/orders-over-time

Customers dashboard

  • File: src/admin/routes/analytics/components/CustomersDashboard.tsx
  • Renders:
    • KPI cards (guest, registered, overall, deleted accounts)
    • Dual-line chart (registered vs guest over time)
  • Interactions:
    • Count period selector (all, 0, 7, 30, 90)
    • Graph period selector (one_week, one_month, one_year)
    • Clear filter action
  • Data consumed:
    • /admin/analytics/customers-summary
    • /admin/analytics/customers-over-time

Models & Entities

No custom entities/models are defined by this plugin.

It reads existing Medusa entities through query/module APIs:

  • order
  • fulfillment (via order fulfillments fields)
  • return
  • order_change
  • customer

Use Cases & Examples

  1. Track order health in admin

    • Use /admin/analytics/orders-summary?days=30 to monitor pending, delivered, and cancelled distribution.
  2. Visualize order demand trends

    • Use /admin/analytics/orders-over-time?period=one_year for monthly trendline analysis.
  3. Monitor customer acquisition mix

    • Use /admin/analytics/customers-over-time?period=one_month to compare guest vs registered growth.
  4. Operational return/exchange visibility

    • Use exchangeOrders and returnOrders from /admin/analytics/orders-summary to track post-purchase operations.
  5. Review account lifecycle signals

    • Use /admin/analytics/customers-summary to compare total/registered/guest counts and deleted accounts.

Troubleshooting

Analytics page does not appear in Admin

  • Ensure plugin is registered in medusa-config.ts.
  • Rebuild plugin: npx medusa plugin:build.
  • Restart backend and hard refresh admin.

401/403 on analytics APIs

  • These are /admin/* routes; call with valid admin auth token/session.

Empty charts or zero counts

  • Confirm store has orders/customers in selected range.
  • Try broader ranges (days=all, period=one_year).

Returns count stuck at 0 / isInitialized in logs

Medusa 2.21 OrderModule.listAndCountReturns can throw when a return references a missing shipping_method (Cannot read properties of undefined (reading 'isInitialized')). Analytics loads returns via Query Graph instead (loadReturnsForOrderIds) so the KPI still works.

Slow response with large datasets

  • Aggregation is paginated (500 rows per page) with created_at filters — there is no silent 50k cap.
  • Prefer narrower date ranges for POS inventory / basket endpoints on very large catalogs.

"Failed to fetch ..." API errors

  • Check backend logs for the route-specific error messages.
  • Verify module availability and that core services (ORDER, CUSTOMER) resolve correctly.