Skip to main content

Architecture Overview

Runtime components

The embedded document loads App Bridge and Polaris web components from Shopify’s CDN. Admin navigation is rendered with s-app-nav; route loaders and actions authenticate with authenticate.admin.

Request and trust boundaries

The storefront does not trust a customer ID supplied in JSON. The server uses Shopify’s signed logged_in_customer_id from the app-proxy request.

Storefront and checkout flow

The theme app embed fetches public configuration through the signed app proxy. In Simple mode, the browser evaluates the entered date of birth and sends a bounded self-certification event to the server, which recalculates the applicable minimum age before recording a successful pass. Enhanced document verification is server-gated by the Enterprise entitlement, enabled settings, and provider readiness. A successful provider callback updates the verification record. For logged-in customers, the app publishes a $app.identity_status customer metafield. For guests, the storefront writes _age_identity_verified and _age_verified_at cart attributes. Checkout enforcement is published as a $app.checkout_gate shop metafield. The all-plan cart block reads enforcement and customer state through /apps/age-verification/status. The checkout UI extension uses the same shop and customer metafields, but that checkout-step surface renders only on Shopify Plus. Both checkout surfaces no-op when enforcement is unavailable. They never treat a missing configuration or a network failure as a verified identity result.

Data model and PII minimization

The main Prisma records are:
  • Shop, ShopSubscription, and AppSettings for installation, billing, and merchant configuration.
  • Customer and Verification for Shopify-linked customers and verification lifecycle state.
  • VerificationWebhookEvent for provider-event deduplication.
  • VerificationAttempt and VerificationRateLimitCounter for abuse controls.
  • CustomerDataExport for Shopify customer-data requests.
  • AuditLog and ComplianceAuditLog for operational and tamper-evident audit history.
  • MerchantApiCredential for hashed bearer API credentials (Enterprise).
The Verification model stores provider session identifiers, status, the minimum age used, and an optional derived verified age. It has no date-of-birth, document-image, or biometric field. The identity provider remains the system of record for identity documents. The Didit callback stores the derived age for a verified decision, not the raw date of birth. On the Stripe rollback path, the callback reads date-of-birth data to make the age decision without persisting that date.

Shopify privacy webhooks

The three compliance topics perform data work:
  • CUSTOMERS_DATA_REQUEST creates a CustomerDataExport for merchant review.
  • CUSTOMERS_REDACT requests provider redaction, deletes the customer’s verification and export records, removes linked operational audit rows, and deletes the local customer record.
  • SHOP_REDACT requests redaction for the shop’s verification sessions, deletes stored sessions, purges the protected compliance chain through its authorized whole-shop function, and deletes the shop.
APP_UNINSTALLED marks the shop uninstalled and removes sessions. The scheduled cleanup later cancels stale identity sessions, requests redaction for retained verification sessions, deletes uninstalled shops after the configured retention period, and prunes expired rate-limit counters.

Billing

Billing is app-managed through Shopify’s Billing API. Plans: Free $0, Pro $2.99/mo ($29.90/yr), Enterprise $9.99/mo ($99.90/yr). Each shop gets one 14-day trial on the first active paid subscription.

Deployment

The app runs as a containerized web service. A separate scheduled job handles post-uninstall data cleanup, and database migrations are applied before each release.