Article Image

Designing CampCart: A Lightweight, Offline-First Commerce Widget

May 20, 2026

Simplifying Independent E-commerce

Adding e-commerce to a static website usually requires loading heavy, tracking-laden third-party widgets or maintaining a complex backend database. These solutions introduce security vulnerabilities, drag down performance, and profile visitors.

CampCart provides an alternative: a zero-dependency, secure shopping cart widget running purely in the browser.

We wanted to prove that you can build a complete, highly-responsive shopping cart experience using purely static files and client-side cryptography.
RebelRoot Front-End Developers

Under the Hood: Pure Client-Side State

CampCart relies on a robust JavaScript state machine that manages product entries, quantities, and price calculations on the client. It persists cart items in localStorage securely to preserve the shopping state across page reloads.

Because static sites do not have a server to dynamically calculate prices and generate tokens, they are traditionally prone to price-tampering attacks — where a malicious user edits client-side JS values to checkout with cheaper amounts.

Solving Price-Tampering via Cryptographic Signing

To thwart client-side manipulation without running an active database server, CampCart uses cryptographic payload verification.

When you initialize your static store, product definitions (including IDs, titles, and unit prices) are declared alongside a pre-computed signature generated by your publishing suite using a private key.

When a user initiates checkout:

  1. The widget bundles the items, counts, and prices into a payload.
  2. The payload and the signatures are sent to our lightweight, stateless payment forwarding API.
  3. The API verifies the cryptographic signatures against the store owner's public key. If a price value doesn't match the signature, the checkout transaction is instantly rejected.

Here is how the verification signature is verified inside the serverless API:

// Web Crypto API method to verify static store product details
async function verifyProductSignature(publicKeyPem, productPayload, signatureBase64) {
const enc = new TextEncoder();
const rawKey = pemToDer(publicKeyPem);
const publicKey = await window.crypto.subtle.importKey(
"spki",
rawKey,
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
false,
["verify"]
);
const data = enc.encode(JSON.stringify({
id: productPayload.id,
price: productPayload.price,
currency: productPayload.currency
}));
const signature = Uint8Array.from(atob(signatureBase64), c => c.charCodeAt(0));
return await window.crypto.subtle.verify(
"RSASSA-PKCS1-v1_5",
publicKey,
signature,
data
);
}
// Helper to convert PEM string back to binary DER
function pemToDer(pem) {
const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "-----END PUBLIC KEY-----";
const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length);
const cleanPem = pemContents.replace(/\s+/g, "");
return Uint8Array.from(atob(cleanPem), c => c.charCodeAt(0)).buffer;
}

Performance Benchmarks

By eliminating database handshakes and network overhead during browsing:

Join the RebelRoot Community. Let's Build Better Software Together.