Inspiration

Online shopping depends on promises that can quietly change after checkout: an arrival date slips, a return window shrinks, or a sale becomes final. A screenshot is easy to save, but it does not make the evidence tamper-evident or clearly explain what changed between visits. PromiseProof was built to give shoppers a private, inspectable record of the exact promise they relied on.

What it does

PromiseProof is a local-first Chrome extension. Instead of capturing an entire page, a shopper selects only the promise that matters. The extension then:

  1. Captures the selected text, a tight screenshot crop, and a sanitized DOM excerpt. Scripts, event handlers, and live form values are removed before storage.
  2. Lets the shopper permanently redact unrelated pixels before the evidence is signed.
  3. Canonicalizes and hashes the evidence, then signs it with an Ed25519 key generated on the device.
  4. Encrypts the bundle with AES-256-GCM before saving it to IndexedDB.
  5. Recaptures the same promise later and deterministically calls out changes to text, price, date, availability, or return policy.
  6. Exports a readable PDF and a self-contained ZIP that an offline, networking-disabled verifier can independently check.
  7. Fails verification immediately when even one byte of the exported evidence is changed.

For a shopper, the impact is simple: a support conversation can move from "I swear it used to say Friday" to a precise record of what was captured, when it was captured, and whether the bundle is still intact. The evidence stays on the shopper's device unless they explicitly export it.

How we built it

PromiseProof is a TypeScript pnpm-workspace monorepo. The product combines a Manifest V3 Chrome extension, a React 19 interface, an on-demand content-script selection overlay, an offline verifier, and focused packages for capture, evidence, encrypted storage, comparison, export, and optional digest anchoring.

The cryptographic path uses RFC 8785 canonical JSON, SHA-256, @noble/ed25519, Web Crypto AES-256-GCM, and AES key wrapping. Dexie provides IndexedDB storage, PDF-Lib and JSZip produce the portable dispute packet, and Zod validates evidence schemas. Vitest, Playwright, and axe cover the release path. All demo storefronts are original synthetic fixtures, not copied merchant pages.

Optional Sigstore Rekor support can publish only a digest, never the screenshot, URL, or selected text. That feature is off by default, and this submission does not claim a real public Rekor receipt because the permanent live-log smoke test was not run.

Challenges

The hardest part was making "verified" mean more than a green label. Both the extension and offline verifier use the same defined Ed25519 implementation so signature behavior cannot silently diverge across runtimes. The end-to-end journey also mutates an exported bundle and requires verification to fail.

Pixel redaction created another product challenge. Redactions must alter the actual bytes before signing, but a mistaken selection must not trap the shopper. The shipped preview preserves the clean image in memory and supports "Undo last redaction" before rebuilding the final pixels.

We also chose detector honesty over inflated precision. Two equivalence gaps remain: regional representations of the same date and return windows phrased in weeks versus days. The raw change is still caught, but those cases are not yet labeled as precisely as we want.

Accomplishments

  • 20/20 controlled storefront fixture pairs passed, including price, date, availability, unchanged-page, currency-format, and scripted-injection cases.
  • 197 unit tests passed with zero failures.
  • Lint, strict type checking across all eight workspace projects, and the production build passed.
  • 4/4 browser journeys passed, including the full capture-to-offline-verification path.
  • The tested screens had zero critical or serious axe accessibility violations.
  • A one-byte tamper test turns the offline verifier red instead of trusting the bundle's label.

Honest limits

PromiseProof proves bundle integrity and chronology. It does not prove that a merchant lied, that a page statement was true, or that the evidence is legally enforceable. The measured results use synthetic storefronts, not real shoppers or merchants. Five planned human usability sessions have not yet been run. The verified browser path is Chromium; Firefox and Edge parity remain future work.

What we learned

Verifiability is a behavior, not a visual style. It requires the failure case, a documented privacy boundary, reproducible evidence, and clear language about what the product cannot prove.

What's next

Next steps are real-shopper usability sessions, a full redaction history with keyboard-adjustable regions, better date and duration equivalence, and broader browser testing.

Built With

  • accessibility
  • chrome
  • cryptography
  • dexie
  • ed25519
  • indexeddb
  • local-first
  • manifest-v3
  • playwright
  • privacy
  • react
  • typescript
  • vitest
  • zod
Share this project:

Updates