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

@luluhoc/medusa-plugin-abandoned-cart

v0.2.2

Published

Abandoned cart detection, multi-stage recovery notifications, and recovery analytics for Medusa v2.

Readme

@luluhoc/medusa-plugin-abandoned-cart

Abandoned cart detection, multi-stage recovery emails, and recovery analytics for Medusa v2.

The plugin watches for carts that go quiet, tracks each one in its own table, sends a configurable sequence of reminders through Medusa's Notification Module, and attributes the resulting orders back to the cart so you can see what the sequence actually earned.

  • Detection — a scheduled sweep finds open carts that have been inactive longer than your first stage's delay, filtered by item count, subtotal, sales channel and customer type.
  • Sequences — any number of stages (1h, 24h, 3d, …), each with its own provider template and channel.
  • Localization — resolve each cart's locale from its metadata, country, region or your own rule, then send the matching template with a localized recovery link.
  • Recovery links — every tracked cart gets an opaque token; the storefront exchanges it for the cart id and the click is recorded.
  • Attribution — an order.placed subscriber marks the cart converted and stores the order id.
  • Admin page — recovery stats, the full funnel, and manual "send now" / "dismiss" actions.

Quick start

yarn add @luluhoc/medusa-plugin-abandoned-cart
module.exports = defineConfig({
  // ...
  plugins: [
    {
      resolve: "@luluhoc/medusa-plugin-abandoned-cart",
      options: {
        storefrontUrl: process.env.STOREFRONT_URL,
        stages: [
          { id: "reminder-1", delay: "4h", template: "d-1a2b3c…" },
          { id: "reminder-2", delay: "24h", template: "d-4d5e6f…" },
          { id: "last-call", delay: "3d", template: "d-7g8h9i…" },
        ],
      },
    },
  ],
})
yarn medusa db:migrate

You also need a Notification Module Provider registered for the channel you send on (email by default) — the plugin composes notifications, the provider delivers them. The template on each stage is that provider's template id.

Then add the recovery route to your storefront, and open Abandoned carts in the admin sidebar.

Full walkthrough →


Documentation

| Guide | What it covers | | --- | --- | | Getting started | Install, wire up a provider, migrate, and confirm the first reminder. | | Configuration | Every option, the duration format, the sweep schedule, and setup recipes. | | How it works | The sweep, the timing model, the status lifecycle, failure handling. | | Notifications | The payload each stage sends, template examples, provider notes. | | Localization | Locale resolution, per-locale templates and data, localized recovery links. | | Storefront integration | Recovery links, the token exchange, drop-in route handlers. | | API reference | Every store and admin route. | | Data model | Tables, columns, module links, and how to query them. | | Recipes | Running the workflows yourself and extending the plugin. | | Troubleshooting | Why nothing sent, why the numbers look wrong, how to test fast. |

Working examples live in examples/: a complete HTML email template and the storefront recovery route.

Using a coding agent? AGENTS.md is a machine-oriented install spec — exhaustive option schema, boot constraints, a deterministic verification sequence, and the failure modes that fail silently. It ships in the npm package, so an agent can read it from node_modules.


At a glance

Optionsstages, template, channel, notificationData, enabled, maxAge, minItems, minSubtotal, requireEmail, onlyRegisteredCustomers, salesChannelIds, resetOnActivity, storefrontUrl, recoveryPath, stopAfterRecovery, batchSize, notificationBatchSize, plus the localization set — locales, defaultLocale, localeMetadataKey, localeByCountry, localeByRegion, localeBySalesChannel, resolveLocale, templates, templatePattern, localeData, storefrontUrlByLocale, recoveryPathByLocale. Reference →

Languages — a cart's locale comes from its metadata, the customer, the country, the region, the sales channel or your own resolveLocale, and picks the stage's template for that locale. Detail →

Timing — stage delays are cumulative and measured from the cart's last activity, so ["1h", "24h"] sends one hour and then 24 hours after the cart goes quiet. Detail →

Schedule — the sweep runs on ABANDONED_CART_CRON (default */15 * * * *), set in the Medusa application's environment. Why →

APIGET /store/abandoned-carts/:token plus six admin routes under /admin/abandoned-carts. Reference →

WorkflowssyncAbandonedCartsWorkflow, sendAbandonedCartNotificationsWorkflow, markAbandonedCartRecoveredWorkflow, markAbandonedCartConvertedWorkflow, all exported from @luluhoc/medusa-plugin-abandoned-cart/workflows. Usage →


Development

yarn install
yarn typecheck          # server-side type check
yarn generate           # generate migrations (needs the DB_* vars in .env)
yarn dev                # watch + publish to the local yalc registry
yarn build              # build for publishing

To test the plugin in a Medusa application:

# in the plugin project
yarn medusa plugin:publish
yarn medusa plugin:develop

# in the Medusa application
yarn medusa plugin:add @luluhoc/medusa-plugin-abandoned-cart
yarn medusa db:migrate
yarn dev

yarn generate needs a reachable Postgres — copy .env.template to .env and fill in the DB_* variables. It writes to src/modules/abandoned-cart/migrations/, which must be committed and shipped with the plugin. Run it once before publishing, and again whenever you change a data model.

Compatibility

Medusa v2.19.0 and later.

License

MIT