Snipcart

snipcart.comcontributed by Samuele Ongaro

ALMOST

A weekend of work, and real gaps remain.

A shopping cart you drop into any static site with a script tag and some data attributes — no backend required, with checkout and payments handled for you.

Promptfree, for everyone, and the only version there is
Build me a shopping cart that replaces Snipcart — and know why this is ALMOST.

The appeal is **a cart with no backend at all**: a script on a static site, and a working shop. You cannot have that without a server somewhere, so the honest version is a small server of your own. What it buys you: prices that cannot be tampered with, tax computed properly, and orders that exist. What you take on: being the one who is called when a payment does not arrive.

STACK
- Node 20+ with Fastify — the small backend the static site does not have
- SQLite through better-sqlite3, WAL mode
- One payment provider, hosted checkout, so no card data touches this
- A cart script under 12KB gzipped, from my own domain
- Caddy in front

THE RULE THAT MATTERS MOST
- **The price comes from the server, never from the page.** A product identifier goes up, a price comes back. Anything else means somebody edits the markup and buys a laptop for one euro, and it is the single most common flaw in cart scripts
- The same applies to quantity limits, shipping, discounts and tax. The browser displays; the server decides
- The order total is recomputed on the server immediately before the payment session is created, from the product identifiers and quantities alone

THE DATA MODEL
- products: id, sku, name, description, price_cents, currency, tax_category, weight_grams, stock, is_active, metadata_json — the catalogue lives here, or is synced from your source of truth
- variants: id, product_id, sku, name, price_delta_cents, stock
- carts: id, token, items_json, subtotal_cents, currency, created_at, updated_at, abandoned_at, converted_at
- orders: id, number, cart_id, email, name, shipping_address_json, billing_address_json, subtotal_cents, shipping_cents, tax_cents, discount_cents, total_cents, currency, status, provider_ref, placed_at, fulfilled_at, cancelled_at
- order_items: id, order_id, product_id, variant_id, sku, name, unit_price_cents, quantity, tax_rate, tax_cents — copied at the time of order, so a later price change never rewrites history
- discounts: id, code, kind, value, min_subtotal_cents, max_uses, used_count, expires_at, product_scope_json
- shipping_rates: id, name, condition_json, price_cents
- provider_events: id, event_id, kind, payload_json, processed_at — idempotency lives here
- Order numbers from a sequence table, allocated in the transaction that places the order

CHECKOUT
- Cart in the browser held as identifiers and quantities only, persisted by a token so it survives a reload
- Every cart change validated against the server: stock, limits, availability
- Checkout collects email and address, then creates a payment session from the server-computed total
- **The order is created from the verified webhook**, never from the browser returning to a success page. Somebody who closes the tab after paying must still have an order
- Idempotency by event id, and out-of-order delivery handled
- Stock decremented in the same transaction as the order, with a check that fails the order rather than going negative

TAX AND SHIPPING
- For digital goods sold across borders the rate is usually the buyer's, not yours. Collect the country, apply the rate, and store two pieces of non-conflicting evidence of where they were. That evidence requirement is what people discover a year late
- For physical goods, the rules differ again and depend on where you ship from. Write in the README which jurisdictions you have covered and when you last checked, and take advice
- Shipping rates as rules on weight, destination and subtotal. Free over a threshold is the common case and should be one row

AFTER THE ORDER
- A receipt immediately, with the itemised total and the tax breakdown a customer may need. Deliverability matters here because a missing receipt is a support message: SPF, DKIM and DMARC on your own domain
- An order status page at a token URL, no account
- Digital delivery through signed expiring links with a download limit
- Abandoned cart email once, at most, if you have an address and consent. Once — a sequence of three is why people mark mail as spam
- Refunds through the provider, with the order updated from the webhook

OPERATIONS
- .env: DATABASE_PATH, STORAGE_PATH, BASE_URL, SESSION_SECRET, SMTP_URL, PROVIDER_KEY, PROVIDER_WEBHOOK_SECRET, ALLOWED_ORIGINS
- Migrations on boot, each once; reconcile nightly against the provider and alert on any disagreement
- Nightly backup off the machine — this holds orders and money
- Health endpoint checking the database, mail and the provider

WHAT MATTERS MOST
Server-side pricing and webhook idempotency. Try to buy something at a price you edited in the browser, and replay a payment event twice. If either succeeds, nothing else in the shop matters.

What you lose

  • A checkout that works on a purely static site, with no server to run or secure
  • Payments, tax rules and shipping rates configured rather than coded
  • Abandoned-cart mails and an order dashboard included

If you would rather not build

  • Stripe Checkout on its own
  • Lemon Squeezy, for digital goods with tax handled

What it costs

read from their page 17 Aug 2026

PlanBilled monthlyBilled yearlyLast read
—$20/mo—17 Aug 2026

Their pricing page is where these came from. Seeing a different price? Tell us.

The escape hatch

open source · no votes, no paid placement

Medusa

$0

A commerce backend for when a static cart is no longer enough.

medusajs/medusafree · open source

Vendure

$0

A TypeScript commerce framework with a plugin system.

vendurehq/vendurefree · open source

Why this verdict

our own opinion · changed only by a person

56/100

Verdict kinda at 56. Stripe Checkout does most of it; the discipline that makes it safe is never trusting a price from the browser.

History

tracked since 10 Aug 2026 · nothing is ever overwritten

Interest · last 30 dayspeak 3/day
views012330 Aug4 Sept9 Sept14 Sept19 Sept24 Sept28 Sept
— views— prompt copies none yet— votes none yet

Questions about Snipcart

answered from the record above

Is Snipcart free?

No — the plan we track is $20 a month. 2% of sales, replaced by a $20/month minimum fee for shops under $1,000 of monthly sales.

Can you replace Snipcart by building your own?

ALMOST. A weekend of work, and real gaps remain. Replacement score 56 out of 100, build time a weekend. Read what you lose before you decide.

How much does Snipcart cost?

$20 a month on Standard — $240 a year. Recorded 17 Aug 2026.

What do you lose by replacing Snipcart?

A checkout that works on a purely static site, with no server to run or secure; Payments, tax rules and shipping rates configured rather than coded; Abandoned-cart mails and an order dashboard included. If any of those carry weight for you, keep paying.

Is there an open-source alternative to Snipcart?

Yes: Medusa, Vendure. The prompt on this page is for when you want it your way instead.

Related entries

same category first, most replaced first

All 27 in Commerce & contracts

Not sending yet

Every week, something stops being worth paying for.

New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.

free forever · no tracking pixel · stored here, never passed to anyone

Esc