Skip to main content

Shopify Image Audit

CI Python 3.11+ ruff tests

A Lighthouse-based image audit tool for Shopify stores. Produces per-image scores, role assignments, optimisation recommendations, and a before/after comparison workflow that proves image-optimisation ROI to paying customers.

Designed for the 99–199 € audit-on-demand business model: run the audit, deliver a customer-ready HTML report, optionally compare live metrics after the customer implements the recommendations.


Quickstart

End-user install (PyPI)

# Recommended: pipx creates an isolated env
pipx install shopify-image-audit

# Alternative: pip into a venv
python -m venv .venv && source .venv/bin/activate
pip install shopify-image-audit

The PDF renderer (audit report --pdf) requires native libraries (libpango, libcairo, libgdk-pixbuf). On Linux:

sudo apt-get install -y libpango-1.0-0 libpangoft2-1.0-0 libcairo2 libgdk-pixbuf-2.0-0

The lighthouse Node CLI is required for audit run <url>. Install with npm i -g lighthouse (or pass --lhr <file> to use a pre-existing report). The binary can be overridden via --lighthouse-bin PATH or $LIGHTHOUSE_BIN; see docs/integrations/LIGHTHOUSE.md for the full install guide and CI recipes.

Developer install (from source)

git clone https://github.com/xopsio/shopify-image-audit.git
cd shopify-image-audit
python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e ".[dev]"

# Verify the install
audit version
pytest -q                                              # 695 tests

CLI commands

The tool ships with a single Typer app. Run audit --help for the full list; below are the high-value entry points.

audit run <url> — full Lighthouse + audit pipeline

audit run https://kauppa.myshopify.com --device mobile --runs 3 \
    --out-dir artifacts
# -> artifacts/lhr_run1.json, audit_result.json (schema-compliant)

audit baseline <lhr.json> --save baseline.json — capture baseline

audit baseline fixtures/before_after/before_lcp.json \
    --save baseline.json \
    --url https://demo.myshopify.com
# -> Baseline saved to baseline.json

audit compare <baseline> <current> — before/after (file or URL)

# File vs file (offline)
audit compare baseline.json fixtures/before_after/after_lcp.json \
    -o comparison.html --json comparison.json

# File vs live URL (fetches via PageSpeed Insights API)
audit compare baseline.json https://demo.myshopify.com \
    --strategy mobile --api-key YOUR_KEY \
    -o comparison.html

# HTML report includes a per-image delta table (bytes, score, status per image).
# PDF export via --pdf flag.

Exit codes: 0 success, 2 invalid args, 10 backend failure.

audit report <audit_result.json> — HTML or PDF report

audit report baseline.json -o report.html          # HTML
audit report baseline.json -o report.pdf --pdf     # PDF (WeasyPrint)

audit measure <url> — live PageSpeed metrics only

audit measure https://demo.myshopify.com --strategy mobile
# -> JSON metrics to stdout (or --output metrics.json)

audit shopify <auth|inventory> <store> — Shopify Admin API

# Verify a token
audit shopify auth mystore.myshopify.com --access-token shpat_xxx
# -> Token valid, prints shop info

# List all image URLs (products + theme assets)
audit shopify inventory mystore.myshopify.com --access-token shpat_xxx -o inventory.json

Read-only scopes required (read_products, read_themes, read_shop). See docs/integrations/SHOPIFY_ADMIN.md for token-acquisition steps.

audit score <audit_input.json> --ranker {heuristic|ml}

audit score extracted.json                    # default: heuristic
audit score extracted.json --ranker ml        # weighted feature ensemble

Full reference: docs/spec/cli_v0_1.md.


Scoring algorithms

The pipeline assigns each image a role, a score (0–100), and a recommendation. Two rankers ship, switchable via --ranker ml:

Ranker Formula Use case
heuristic (default) bytes per displayed pixel (bpp) + LCP penalty fast, predictable baseline
ml weighted ensemble: f_size, f_density, f_format, f_dim_match + LCP strictness richer signal, more honest scoring

Both produce the same output contract (role + score + recommendation). The ML ranker is a hand-coded feature ensemble, not a statistical model — see src/audit/ranker_ml.py for the design rationale (no model deps, deterministic, fully explainable via ml_features()).


Configuration

Repeated options can be set once in ~/.config/shopify-image-audit/config.toml (or $XDG_CONFIG_HOME/shopify-image-audit/config.toml):

[defaults]
device = "mobile"    # run / baseline / schedule add
strategy = "mobile"  # measure / compare
parallel = 4         # shopify batch / schedule run-all (0 = unlimited)

[pagespeed]
api_key = "AIza..."  # or --api-key / $PAGESPEED_API_KEY

[report]
brand_color = "#ff6b35"   # report / compare branding

Precedence: CLI flag > env var > config > default. A broken config warns and falls back to defaults — it never blocks a run. Full reference (13 keys / 5 sections) in CONTRIBUTING §5b.


Architecture

src/
├── audit/                    # scoring + reporting
│   ├── models.py             # Pydantic v2 schemas (AuditResult, ComparisonResult, ImageDelta)
│   ├── parser.py             # Lighthouse / fixture JSON parser
│   ├── ranker_heuristic.py   # default ranker (bpp-based)
│   ├── ranker_ml.py          # opt-in ML-style ranker (weighted ensemble)
│   └── report.py             # HTML/PDF report renderer (split into _render_* funcs)
├── core/                     # core algorithms
│   ├── image_extractor.py    # LHR image audit extraction
│   ├── image_signals.py      # shared displayed_area, assign_role, _safe_int
│   └── baseline_manager.py   # save/load baselines + compare() + per-image matching
├── engine/                   # orchestration + CLI
│   ├── cli.py                # Typer app (run, measure, baseline, compare, shopify, ...)
│   ├── cli_helpers/          # extracted CLI helpers (validators, dispatchers, table, errors)
│   └── audit_orchestrator.py # run_audit() pipeline
└── integrations/             # external APIs
    ├── pagespeed_api.py      # PageSpeed Insights (measure + fetch_lighthouse_json)
    └── shopify_admin.py      # Shopify Admin API (auth, products, theme_assets)

src/audit/schemas/audit_result.schema.json  # JSON Schema contract (validated by tests)
tests/                              # 695 tests, single-writer (ZCode)
docs/examples/                       # live demo report + comparison JSON
docs/integrations/                   # Shopify Admin API token guide

The codebase is governed by a single ZCode agent (see docs/governance.md v1.3).


Testing

pytest -q                                # 695 tests, single-writer discipline
pytest --cov=src --cov-report=term       # ~91% coverage
ruff check src/ tests/                   # 0 violations

The CI workflow runs pytest -q + ruff check on Python 3.11 and 3.12 for every PR. Branch protection on main requires both checks to pass before merge. See .github/workflows/ci.yml.


Customer deliverables (Phase 1)


Roadmap

  • ✅ Sprint 1 — v0.1.0 baseline (parser, ranker, orchestrator, CLI, HTML report, 103 tests)
  • ✅ Sprint 2 — before/after workflow, customer docs, ML ranker, live URL compare, CI, governance cleanup (276 tests)
  • ✅ Sprint 3 — PDF export, per-image deltas, Shopify Admin API, v0.2.0 release prep (390 tests)
  • ✅ Sprint 4 — Branded reports, ROI-ranked recs, audit history, v0.3.0 (489 tests)
    • Branded report templates (--brand-logo, --brand-color)
    • ROI-ranked recommendations (ComparisonRecommendation model)
    • Audit history + trend view (HistoryStore, audit history list/show)
  • ✅ Sprint 5 — Snapshot tests, CLI coverage, error decorator wiring, history diff, v0.4.0 (546 tests)
    • Snapshot testing infrastructure (syrupy) for HTML renderers
    • CLI coverage for all 10 commands
    • Error decorator wiring + consistency pass (RuntimeError → exit 10)
    • audit history diff with stable entry-ids
    • CHANGELOG.md and --cov-fail-under=85 CI gate
  • ✅ Sprint 6 — Coverage close-out, test isolation, multi-store batch, observability, v0.5.0 (606 tests)
    • tests/test_table_snapshots.py (Rich Console captures)
    • Zero CWD-relative writes in tests
    • audit shopify batch --stores-file for multi-store inventory
    • engine._logging with 6 structured log hooks
    • CONTRIBUTING.md, --cov-fail-under=90
  • ✅ Sprint 7 — Scheduled re-audit, dependency hygiene, PageSpeed cache, v0.6.0 (642 tests)
    • audit schedule list/add/remove/run-all + crontab runbook
    • Dependabot + SLSA build-provenance attestation
    • PageSpeed response cache (PAGESPEED_CACHE_TTL)
    • Report footer version drift fixed
  • ✅ Sprint 8 — UX polish, test architecture, shared run_parallel, v0.7.0 (665 tests)
    • "Did you mean: X?" suggestions on every typo site
    • tests/conftest.py + tests/__init__.py (single source of truth for REPO_ROOT + fixtures)
    • Shared run_parallel helper (batch + scheduler share it)
    • audit schedule run-all --parallel (deferred from Sprint 7)
    • [pdf] extra — WeasyPrint no longer required by default
    • docs/tutorial.md walkthrough
  • ✅ Sprint 9 — Doc hygiene, wheel packaging, security polish, v0.7.1 (672 tests)
    • JSON schema ships inside the wheel (importlib.resources-readable)
    • PAGESPEED_API_KEY env var + API-key redaction in error messages
    • schedules.json written with 0600 permissions
    • Issue templates (bug report + feature request)
    • Doc hygiene: canonical env-var reference, drift-free test counts
  • ✅ Sprint 10 — Type safety + SBOM, v0.8.0 (672 tests)
    • Mypy CI-gate, zero type: ignore comments
    • ImageDict TypedDict contract across the pipeline
    • CycloneDX SBOM in release artifacts (complements SLSA provenance)
  • ✅ Sprint 11 — User-side TOML config, v0.9.0 (695 tests)
    • ~/.config/shopify-image-audit/config.toml (13 keys / 5 sections)
    • Precedence: CLI flag > env var > config > default
    • Broken config warns + falls back — never blocks a run
  • ✅ Sprint 12 — Repo hygiene + format gate, v0.9.1 (695 tests)
    • ruff format applied across the whole repo (53 files)
    • ruff format --check added to CI (no future drift)
    • 4 Dependabot PRs merged (rich constraint widened, GitHub Actions bumps)
  • ✅ Sprint 13 — Strict mypy, v0.10.0 (695 tests)
    • mypy --strict clean across 30 source files (zero ignore comments)
    • ParamSpec + TypeVar preserves decorator signatures
    • 26 mechanical annotation fixes (dict[str, Any], list[Any], return-type annotations)
  • ✅ Sprint 14 — ImageDelta schema, v0.10.1 (698 tests)
    • ImageDelta.before/.after are ImageItem (was dict[str, Any])
    • Closes the Sprint 13 strict-mypy follow-up — no more cast() in baseline_manager.py
    • extra="forbid" on ImageItem now protects against future drift
  • ✅ Sprint 15 — TypedDict hierarchy, v0.11.0 (705 tests)
    • LighthouseJson + AuditEntry + Categories + PerformanceCategory
    • CachedPageSpeedResponse (envelope) + CachedEntry (cache)
    • run_audit() parses LighthouseJson directly
  • ✅ Sprint 16 — Lighthouse install validation, v0.12.0 (715 tests)
    • --lighthouse-bin PATH flag + $LIGHTHOUSE_BIN env override
    • 10-minute per-run timeout (no more infinite hangs)
    • docs/integrations/LIGHTHOUSE.md (install, CI recipes, troubleshooting)
    • 6/6 _run_lighthouse testing gap closed (+ 4 resolver tests)
  • ✅ Sprint 17 — Rich Progress bar, v0.13.0 (721 tests)
    • Live progress bar for audit shopify batch and audit schedule run-all
    • on_done callback in run_parallel (per-item observer hook)
    • Transient bar erases on completion; per-store post-mortem lines remain the canonical output

Further reading

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shopify_image_audit-0.13.0.tar.gz (130.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

shopify_image_audit-0.13.0-py3-none-any.whl (93.8 kB view details)

Uploaded Python 3

File details

Details for the file shopify_image_audit-0.13.0.tar.gz.

File metadata

  • Download URL: shopify_image_audit-0.13.0.tar.gz
  • Upload date:
  • Size: 130.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for shopify_image_audit-0.13.0.tar.gz
Algorithm Hash digest
SHA256 0b84160b5a9b1650b64d9e5825fdd7faffd7d615da63e8b94e9c1b46a8c72c75
MD5 be3dedebfc593431a8743f9dfe25693c
BLAKE2b-256 e27525d50ba0e1c09c1f9b2f33cb22ee8b003c47d321bd113cc9dfde9a7ed7f5

See more details on using hashes here.

Provenance

The following attestation bundles were made for shopify_image_audit-0.13.0.tar.gz:

Publisher: release.yml on xopsio/shopify-image-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shopify_image_audit-0.13.0-py3-none-any.whl.

File metadata

File hashes

Hashes for shopify_image_audit-0.13.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e66999a0d29621fb1422371910d7fb54053d8adc0f6489df834b189caea927e3
MD5 0742e6c711b42be94600868423f89efc
BLAKE2b-256 9e61135a8b6dd0e45177227ed2d0aabf843c080af3ec9ba6aab076e26d05f08e

See more details on using hashes here.

Provenance

The following attestation bundles were made for shopify_image_audit-0.13.0-py3-none-any.whl:

Publisher: release.yml on xopsio/shopify-image-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page