Overview
EU and Polish consumer-protection duties of an online shop, supported in Medusa v2 - Omnibus price history, unit prices, GPSR product safety data, the online withdrawal function and the reviews and personalised pricing disclosures.
@zanreal/medusa-consumer-compliance is a Medusa v2 plugin for a shop that sells
to consumers in Poland (and, with the same rules, elsewhere in the EU). It keeps
the data and runs the processes that consumer law expects of a store's backend,
and hands the frontend everything it needs to show it.
The plugin is headless: it ships no frontend code, and everything a frontend needs is in the Store API, described in Frontend API contract.
Not legal advice. The plugin supports compliance; it does not deliver it. Labels, terms, the withdrawal instructions and every decision listed under open legal questions need a lawyer's review. The legal basis of every rule is cited in Legal basis and compliance matrix.
What it covers
| Duty | What the plugin does |
|---|---|
| Omnibus: lowest price in the 30 days before a reduction | Records every price change per variant and pricing context, computes the reference price by the Polish rules, exposes it with the label the frontend must print. See Omnibus. |
| Unit price | Stores net quantity, unit and exemptions per variant, computes the unit price from the live price. See Unit prices. |
| GPSR product information | Manufacturers and EU responsible persons as reusable records, warnings in Polish, validation of what is missing. See Product safety. |
| Online withdrawal function (Directive 2023/2673) | A two-step Store API flow, per-item eligibility and deadlines, the acknowledgement on a durable medium, an admin register. See Withdrawal. |
| Checkout consents | Consents chosen by the cart contents, enforced when the cart is completed, frozen verbatim on the order. See Checkout consents. |
| Reviews and personalised pricing | Editable texts served by the Store API. See Disclosures. |
What it does not do: render anything in your frontend, decide whether a product is perishable or covered by GPSR, or classify your discount codes. Those are store decisions, and the plugin makes each of them an explicit field instead of a guess.
How it fits together
pricing module ──events──> price history subscriber ──┐
price lists (scheduled) ──hourly sweep────────────────┤
v
consumer_compliance_price_history
│
frontend ── GET /store/products/:id/compliance ──────┤──> Omnibus reference + unit price + GPSR block
frontend ── POST /store/consumer-compliance/withdrawals (+ /confirm) ──> withdrawal record ──> acknowledgement e-mail
admin ── product widgets, Settings > Consumer compliance, Withdrawals registerEverything is a Medusa module with its own tables and migrations, written through workflows. The plugin adds no module links, so installing it touches no core table.
Install
This package is not on npm yet. It installs as a git dependency, pinned to a commit:
{
"dependencies": {
"@zanreal/medusa-consumer-compliance": "github:zanreal-labs/medusa-consumer-compliance#ee3a8f2db91d3845a61d3c4e57d59f47ad7a318a"
}
}Pin to the commit you tested against. There is no published tag yet, so #main
would move under you on the next push; a pinned commit means the same thing
tomorrow that it means today.
The package compiles itself on install - prepare runs medusa plugin:build,
which turns the checked-out source into the .medusa/server output its exports
point at. pnpm 10 and newer refuse to run that script for a dependency they do not
already trust, so a fresh install needs it allowed once:
allowBuilds:
"@zanreal/medusa-consumer-compliance@https://codeload.github.com/zanreal-labs/medusa-consumer-compliance/tar.gz/ee3a8f2db91d3845a61d3c4e57d59f47ad7a318a": trueThe key is the exact tarball URL pnpm resolves the pinned commit to, so it carries the same SHA as the dependency line. Move both together. Then register the plugin:
module.exports = defineConfig({
plugins: [
{
resolve: "@zanreal/medusa-consumer-compliance",
options: {
withdrawal: {
seller: { name: "Shop sp. z o.o.", address: "ul. Prosta 1, 00-001 Warszawa", email: "shop@example.com" },
},
},
},
],
});Then run the migrations and record the current prices once:
npx medusa db:migrate
# then in the admin: Settings > Consumer compliance > Price history > Record current prices nowThe hourly sweep would do the same within the hour. Every option is described in Options and admin API.
Admin
- Product page: a compliance card (GPSR data, Omnibus treatment, withdrawal exception, unit prices per variant) and a price history card (chart, table, reference price, external price windows).
- Order page: the customer's consents (Zgody klienta) and withdrawals submitted for the order.
- Withdrawals (sidebar): the register of every withdrawal statement.
- Settings > Consumer compliance: disclosure texts, manufacturers and responsible persons, the list of products with GPSR gaps, price history status.
The admin is translated into Polish and English.