From Idea to App Store: Building the AI-Signed Shopify App

How we built a trust badge embedded app for Shopify using Remix, Polaris, and theme extensions — and what we learned along the way.

AI-Signed is our website trust verification platform. It runs 43 automated checks against a domain, scores it, and generates an embeddable trust badge. The standalone product works well for sites where the merchant controls their HTML, but Shopify stores operate differently. Merchants cannot paste arbitrary scripts into their themes without workarounds. They expect to install an app, click a button, and see the badge appear. So we built one.

This article covers the full arc of building the AI-Signed Shopify app: the tech stack decisions, the configuration pitfalls that cost us days, and the App Store submission process. If you are considering building a Shopify app, this should save you some pain.

The Tech Stack

Framework Remix v2.16
UI React 18 + Polaris v13
Database PostgreSQL 17
ORM Prisma
Deployment Docker Compose
CLI Shopify CLI v3.91.0
Extension Theme App Extension
Billing Managed Pricing

Shopify's official app template for Remix gave us a solid starting point. It comes with session management, OAuth scaffolding, and Polaris wired up out of the box. We extended it with two Prisma models: Session for Shopify OAuth tokens and ShopInstallation for tracking each store's configuration, badge preferences, and scan results.

Architecture: Docker and Internal Networking

The app runs as two Docker containers orchestrated by docker-compose: the Remix app itself and a PostgreSQL 17 instance. Both sit on the same Docker network as the AI-Signed backend, which means the Shopify app can reach the trust verification API over an internal hostname rather than traversing the public internet. Scan requests, badge generation calls, and remediation data all flow through this internal bridge. This keeps latency low and avoids exposing internal endpoints to the outside world.

The Prisma schema keeps things lean. Session management follows Shopify's recommended pattern. ShopInstallation stores the shop's myshopify domain, their custom domain (if configured), badge placement preferences, and the latest scan metadata. When a merchant opens the app, the dashboard fetches their current trust score from the AI-Signed backend and caches summary data locally to avoid redundant scans.

The Flat TOML Problem

This was the first real gotcha. Shopify theme app extensions require a TOML configuration file to define the extension's metadata, but there are two TOML formats in the Shopify ecosystem and the documentation does not make the distinction obvious.

Standard Shopify app extensions use a unified shopify.app.toml where everything lives in a single file with nested sections. Theme app extensions, however, require a flat TOML format in their own directory. The flat format uses simple top-level keys like name, type, and target instead of the nested [extensions] tables you see in the unified config.

We initially set up our theme extension using the unified format because that is what the main app config uses. The Shopify CLI accepted it without complaint during local development. It was only when we tried to deploy the extension that we hit cryptic validation errors. The fix was restructuring the extension's TOML to the flat format, but finding this answer required reading through GitHub issues rather than the official docs, which conflated the two formats.

If your theme app extension deploys fail with vague TOML errors, check whether you are using flat format. The extension directory needs its own config file with flat top-level keys, not the nested structure from your main app TOML.

Theme Extension: Loading the Badge

The theme extension itself is straightforward in concept but particular in execution. It defines an app block that merchants can place in their theme using Shopify's theme editor. The block contains a Liquid template that renders a container element and loads the AI-Signed badge SVG dynamically from ai-signed.com/badge/{domain}.svg.

The badge is an SVG rather than a raster image because it needs to display the current trust score, grade, and verification date. The SVG is generated on each request by the AI-Signed backend based on the latest scan data. This means the badge always reflects the current state of the store's trust score without requiring the merchant to manually update anything.

One challenge with theme extensions is that they run in a sandboxed context. You cannot inject arbitrary JavaScript or make fetch calls from the extension's Liquid template the way you would in a normal theme snippet. We worked around this by having the block simply render an <img> tag pointing to the badge SVG endpoint, which keeps things simple and avoids the sandbox restrictions entirely.

Deep Links for One-Click Badge Install

Getting merchants to actually place the badge in their theme is a UX challenge. Even with a theme extension installed, the merchant still needs to open the theme editor, find the app block, and drag it into position. We reduced this friction using Shopify's deep link mechanism.

The app dashboard includes a "Place Badge" button that generates a URL with the addAppBlockId parameter set to {client_id}/{block_filename}. Clicking this link opens the theme editor with the badge block pre-selected, ready to drop into the page. It takes the merchant from "I installed the app" to "the badge is on my store" in two clicks instead of a multi-step manual process through the theme editor.

Managed Pricing vs. Billing API

This was the second major gotcha, and it cost us more time than the TOML issue. Shopify offers two approaches to billing: the Billing API (programmatic charge creation through GraphQL) and Managed Pricing (configured through the Partners dashboard). The documentation presents them as interchangeable options, but they are not.

We initially implemented the Billing API because it seemed like the more flexible approach. You create a recurring charge via GraphQL, redirect the merchant to Shopify's confirmation page, and handle the callback. The implementation worked in development. But when we went to submit to the App Store, we discovered that the Billing API has compatibility constraints with certain app distribution models and submission requirements that Managed Pricing handles automatically.

Managed Pricing is configured entirely through the Partners dashboard. You set the price ($5.99/month in our case), the trial period (7 days), and the billing interval. Shopify handles the subscription flow, the merchant approval screen, and the grace periods. The app code does not need to interact with billing at all. It simply checks whether the shop has an active subscription through the session data.

The tradeoff is flexibility. You cannot do usage-based billing, tiered pricing that changes dynamically, or promotional discounts through Managed Pricing. But for a simple flat-rate subscription, it is dramatically simpler and avoids an entire category of App Store review issues.

If your Shopify app has a straightforward monthly subscription, start with Managed Pricing. Only reach for the Billing API if you need usage-based billing or dynamic pricing tiers. The Billing API is not just more complex to implement; it introduces compatibility issues that Managed Pricing sidesteps entirely.

The Dashboard and Remediation System

The merchant-facing dashboard is built with Polaris v13, Shopify's React component library. Polaris enforces a consistent look and feel across all Shopify apps, which is both a constraint and a benefit. Merchants get a familiar interface; developers get pre-built components for cards, data tables, banners, and navigation.

The dashboard displays four main sections: the overall trust score, a category-by-category breakdown (SSL, headers, performance, content, accessibility, and more), detailed remediation guides, and badge placement controls.

The remediation system is where the app delivers the most value beyond the badge itself. Each of the 43 trust checks includes a step-by-step fix guide, classified by difficulty (easy, moderate, advanced) and by where the fix needs to happen (Shopify admin, theme code, DNS, or third-party service). A merchant who fails the "missing HSTS header" check sees a guide explaining what HSTS is, why it matters, and the exact steps to enable it through their Shopify domain settings. A check for missing alt text includes instructions for the specific Shopify admin screens where images are managed.

This classification system matters because Shopify merchants have wildly varying technical ability. A store owner who hired someone to set up their theme can handle "go to Settings > Domains" but cannot edit Liquid templates. The difficulty ratings let them prioritize the fixes they can actually do themselves and flag the rest for their developer.

Settings and Custom Domains

The settings page handles three things: custom domain configuration, badge placement preferences, and plan information. The custom domain field is important because many Shopify stores use a custom domain rather than their myshopify.com subdomain. The badge SVG is keyed by domain, so the app needs to know which domain to request the badge for. If a merchant enters their custom domain, the app triggers a scan against that domain and updates the badge URL accordingly.

App Store Submission and Review

The Shopify App Store review process is thorough and largely automated. Before a human reviewer ever looks at your app, Shopify runs automated checks against a series of requirements that trip up most first-time submissions.

The key automated checks include: OAuth implementation must follow the exact redirect flow with session tokens, all redirect URLs must be pre-registered and use HTTPS, the app must handle mandatory compliance webhooks (customers/data_request, customers/redact, shop/redact) even if it does not store customer data, all requests from Shopify must validate the HMAC signature, and all endpoints must be served over TLS.

The compliance webhooks are worth calling out. Even if your app never touches customer data, Shopify requires you to implement these three webhook endpoints and return a 200 response. They are part of GDPR compliance and the automated checker will reject your submission if they are missing or return errors. Our implementation logs the webhook payload and returns a success response since AI-Signed does not store any customer PII.

Extension deployment goes through shopify app deploy via the Shopify CLI v3.91.0. This pushes both the app version and the theme extension in a single command. The CLI validates the extension's TOML config, bundles the Liquid templates and assets, and uploads everything to Shopify's CDN. Versioning is handled by Shopify; each deploy creates a new version that goes through review before becoming available to merchants.

Lessons Learned

Building a Shopify app is not like building a standalone SaaS. The platform enforces opinions at every level: how you authenticate, how you bill, how you render UI, how you extend themes, and how you distribute. Some of these opinions are well documented. Others you discover through failed deployments and rejected submissions.

The three things we would do differently on the next Shopify app: start with Managed Pricing from day one instead of prototyping with the Billing API, read the theme extension docs separately from the main app extension docs since they are different systems with different configuration formats, and build the compliance webhooks into the initial scaffold rather than adding them before submission.

The AI-Signed Shopify app is live in the Shopify App Store at $5.99/month with a 7-day free trial. Merchants install the app, run a scan, get a trust score and remediation roadmap, and place a verified trust badge on their store. It connects the Shopify ecosystem to the same 43-check verification engine that powers the standalone AI-Signed platform.

← Back to Blog Next: Proxmox Home Lab Cluster →

Want us to build something like this for you?

Get in Touch