Skip to content
Engineering

Why we built Content Vault on top of Shopify checkout

Every digital platform we looked at had a custom checkout that broke native conversion optimization. We bet on the platform instead.

SS
Seva Safris · · 12 min read

When we started building Content Vault, we made a decision that felt risky at the time: we would not own the checkout. Every competing platform had custom payment flows, custom cart mechanics, and custom order management. We decided to build entirely on top of Shopify's native checkout instead.

The conversion problem nobody talks about

Shopify has spent hundreds of millions of dollars optimizing their checkout conversion rate. They test relentlessly — button placement, form field order, trust signals, mobile keyboard behavior. When you replace that checkout with your own, you lose all of it.

We looked at four competing platforms before building. All four had conversion rates 8-14% lower than a comparable Shopify-native checkout. For a merchant doing $50,000/month in digital subscriptions, that's a significant amount of revenue left on the table every single month.

What we had to give up

Building on Shopify checkout means accepting their constraints. You cannot inject arbitrary JavaScript. You cannot add custom fields mid-flow. You work within Shopify Functions and Checkout Extensions, which have real limitations.

  • Subscription pricing must be modeled as Shopify selling plans
  • Drip scheduling state lives in metafields, not a custom database
  • Fulfillment hooks run through Shopify's webhook system with its retry semantics
  • Customer portal is an embedded Shopify UI, not a standalone SPA

These constraints forced us to be creative. They also forced us to be disciplined. Every architecture decision had to work within Shopify's mental model, which meant it was automatically compatible with the rest of the Shopify ecosystem.

The selling plan architecture

Shopify's selling plan API was designed for physical product subscriptions — replenishment use cases like coffee beans or pet food. We had to map our digital content concepts onto it carefully.

graphql
# Our selling plan shape for a drip subscription
mutation sellingPlanGroupCreate($input: SellingPlanGroupInput!) {
  sellingPlanGroupCreate(input: $input) {
    sellingPlanGroup {
      id
      sellingPlans(first: 5) {
        edges {
          node {
            id
            name
            billingPolicy {
              ... on SellingPlanRecurringBillingPolicy {
                interval
                intervalCount
              }
            }
          }
        }
      }
    }
  }
}

The key insight was treating each content tier as a selling plan group variant, not a separate product. This keeps the Shopify product catalog clean and makes tier upgrades a simple subscription modification rather than a cancel-and-resubscribe flow.

“Working within platform constraints doesn't mean accepting worse outcomes. It means finding the leverage points the platform already built for you.”

— Seva Safris

What we'd do differently

The main thing we underestimated was webhook reliability. Shopify webhooks are eventually consistent, which is fine for most use cases but creates edge cases in content drip scheduling. We now maintain a reconciliation job that runs every 15 minutes to catch any subscription state drift. If we were starting over, we'd build that reconciliation layer from day one.

SS

Seva Safris

Founder · Content Vault

Seva Safris is the founder of Content Vault. Builds subscription tools for Shopify merchants.

Written by operators, not interns.

Monthly notes on subscription metrics, pricing experiments, and what's working for real Shopify merchants. No spam, unsubscribe anytime.

Related reading

Want to try Content Vault?

Turn your digital files into a recurring subscription on Shopify in minutes.

Install free on Shopify