Shopify CRO Audit Pipeline
A URL becomes a branded 17-slide PowerPoint conversion-rate audit — desktop + mobile capture, six parallel LLM specialists, delivery to Drive.
- Role
- Full-Stack Engineer
- Year
- 2026
- Discipline
- SaaS
- Stack
- 7 technologies
What it does
- Submit a URLThrough a branded form; choose whether to build extra business-context, and whether to deliver the report to Drive.
- Capture desktop + mobileIn parallel via headless Playwright — full-page screenshots, viewport-only hero shots, rendered HTML, and Lighthouse + CrUX metrics from PageSpeed Insights.
- Detect business contextCheap Gemini Flash-Lite call — industry, persona, business model, value prop, primary conversion goal.
- Analyse against six pillarsSufficient Product Info & USPs, Trust Building, Efficiency & Discovery, Checkout Optimization, AOV & LTV, and Urgency. Six parallel Gemini Pro specialists, synthesised into a unified findings list with per-pillar scores, per-section scores, and an ICE-ranked experiment backlog.
- Render a branded 17-slide deckVia python-pptx — cover, executive summary, business context, six-pillar overview, section scorecard, captures, per-section walkthroughs (Homepage / PDP / Cart / Trust / Mobile / Email / Performance with CWV tiles), priority table, 30-day action plan, closing.
- DeliverPPTX to a shared Google Drive folder via OAuth, with a download endpoint as fallback.
- Live audit detail pageFive-stage subway-rail visualization, ticking elapsed counter, cancel-with-confirm during the cancellable phases, status-aware hero (live / completed / cancelled / failed).
- Per-user ledgerMulti-tenant audit history with ownership-enforced routes; users only see their own audits and can never address another user’s by ID.
Tech stack
Backend
Python 3.14, FastAPI, SQLAlchemy 2, Alembic, PostgreSQL (SQLite for dev), Pydantic v2, httpx, Playwright (run in a subprocess to sidestep uvicorn’s Windows asyncio policy), python-pptx, google-genai, anthropic, google-api-python-client, google-auth-oauthlib.
Frontend
React 19, Vite 6, TypeScript, Tailwind v4 with @theme tokens, custom-built UI primitives (Button, Input, Checkbox, Card, Badge), React Router 7, a variable display font bundled in-tree.
LLM integration
Pluggable provider abstraction (Gemini + Claude), shared JSON schemas across providers, prompt-caching ready, six parallel specialist calls + one synthesis call per audit, structured output via Gemini’s response_schema and Claude’s tool-use pattern.
Browser automation
Playwright (Chromium), launched in an isolated subprocess per audit so capture is insulated from the parent event loop; two contexts in parallel (desktop 1440×900 + iPhone 14 mobile preset); networkidle avoided in favor of domcontentloaded + soft load wait to keep beacon-heavy sites from stalling.
Performance data
Google PageSpeed Insights v5 API for both strategies; CrUX field metrics + Lighthouse lab metrics; non-fatal — audits continue when PSI rate-limits or 5xxs.
Drive delivery
OAuth installed-app flow (works on personal / Google One Pro accounts where service accounts can’t), refresh token stored as path / raw JSON / base64 in one env var, drive.file scope only.
Auth
Shopify OAuth with role mapping (owner / staff / collaborator), HS256 session JWTs persisted in localStorage with 8h TTL, optional Clerk sign-in path verified against Clerk’s JWKS, ownership-enforcing 404s on all ID-scoped routes.
Engineering highlights
Pluggable LLM provider abstraction
Same LLMClient Protocol drives Gemini and Claude implementations; swap providers per-audit via env var without touching the runner. Schemas are defined once and reused across providers so outputs stay comparable.
Six-pillar parallel analysis
Specialist calls fan out via asyncio.gather(..., return_exceptions=True) so a single specialist failing doesn’t kill the audit; synthesis works with whatever returned. No agent framework — asyncio.gather is the right shape for stateless fan-out, framework overhead bought nothing.
Subprocess Playwright capture
Capture runs in a child Python process (asyncio.run + Proactor on Windows) so the parent uvicorn — which inherits Selector — never has to deal with subprocess spawn. Sidesteps the NotImplementedError cliff entirely.
Cooperative cancellation
Cancel endpoint flips audit status; the runner polls between every step, refusing to advance. Cancellation is a first-class status (cancelled, distinct from failed) with its own finding-step state and UI treatment. Cancel is also gated by phase — disabled once the runner enters the final 5s report + deliver window where nothing useful can be saved.
Single-process pipeline
No Celery, no Redis, no external worker — audits run as asyncio.create_task from the POST handler, gated by an in-process asyncio.Semaphore (default 2 concurrent). Stranded audits from a server restart get reset on lifespan startup.
17-slide branded PPTX template
Pure python-pptx, no Node subprocess. Variable display font bundled in-tree; logo + icon brand assets embedded directly; pinwheel-style mark drawn programmatically when a reverse-tone variant is needed; CWV thresholds encoded for the Performance slide; ISSUE / WIN / OPPORTUNITY badges consistent with the kind classification on every finding.
Audit detail = operational instrument
Vertical subway-rail pipeline visualization with one node per stage; current stage gets an indeterminate orange progress bead; LIVE pulse + ticking elapsed counter; status-aware hero swaps between Live / Complete / Cancelled / Failed so the page’s center of gravity matches the moment.
API health by exception
Polls /health every 30s; renders nothing while online or first-checking, surfaces only when degraded (slow response) or offline. Avoids "all green dot" noise; alerts only when there’s something to alert about.
What it demonstrates
- Productizing AI — turning an open-ended LLM capability into a fixed template + repeatable methodology + branded deliverable that can be sold for a fixed fee with a 24-hour SLA. The methodology is encoded as prompt structure, not a marketing slogan.
- Multi-provider LLM integration. Provider abstraction lets the operator swap Gemini for Claude in a single env var without touching any business logic — useful when one provider rate-limits, costs spike, or quality regresses on a specific audit type.
- Long-running async work in a single process. Fan-out + fan-in across six concurrent multimodal LLM calls, integrated with browser automation, file generation, and a third-party upload — without introducing a queue, broker, or worker pool until the math actually demands one.
- Brand system as code. A consistent visual identity expressed across two surfaces (PPTX + React) from one set of tokens + assets, enforced in code (report.py constants + index.css @theme block + DESIGN.md spec). Brand changes propagate via one commit.
- Cross-platform Windows-first dev experience. Subprocess capture, event-loop policy guards, font bundling for both runtime + viewer, Device Guard-aware npm scripts.
Stack at a glance
FastAPI · React 19 · TypeScript · PostgreSQL · Alembic · Tailwind v4 · Playwright · python-pptx · Gemini 2.5 Pro / Flash-Lite · Anthropic Claude (pluggable) · Google PageSpeed Insights · Google Drive (OAuth installed-app) · Shopify OAuth + JWT · Clerk
Ecommerce AI Discoverability Audit
Seven-pillar GEO/AEO diagnostic with evidence-backed findings, a 0–10 composite score, and a 90-day remediation roadmap — rendered to a brand-styled report.
Next case · 04Shopify Product Bulk Operations Suite
Standalone Shopify app: FastAPI on the backend, React 19 on the frontend, one process owning the full pipeline. No external CLI, no job queue glue.