DEV Community

Cover image for Shopify Theme Devtools: Debug Liquid Like It's JavaScript
Yakhyo Ismoildjonov
Yakhyo Ismoildjonov

Posted on

Shopify Theme Devtools: Debug Liquid Like It's JavaScript

If you've ever spent hours hunting down a Liquid error buried somewhere in your Shopify theme, or wondered "what the hell is in this product object right now?", this tool is for you.

I built Shopify Theme Devtools — an in-browser developer panel that brings Chrome DevTools-level debugging to Shopify Liquid development. No more {{ product | json }} scattered throughout your templates. No more refreshing the page to check cart state. No more guessing.


The Problem with Shopify Theme Debugging

Shopify's Liquid templating is powerful, but debugging it is painful:

  • No native debugger — You can't step through Liquid code
  • Silent failures — Errors often render as empty strings or cryptic messages buried in HTML
  • Context blindness — You can't easily see what data is available in your current template
  • Cart state mystery — Testing cart logic requires manually adding/removing items
  • Metafield hunting — Finding and testing metafield values across resources is tedious

Most developers resort to sprinkling {{ some_object | json }} throughout their code, refreshing, copying the output, and pasting into a JSON formatter. Over and over.

There had to be a better way.


Introducing Shopify Theme Devtools

Shopify Theme Devtools is a single Liquid snippet that injects a full-featured debugging panel into your development theme. It's like having Chrome DevTools, but specifically designed for Shopify Liquid.

Key Features at a Glance

Feature What It Does
Objects Inspector Browse all Liquid objects (shop, product, cart, etc.) with search
Live Console Evaluate Liquid expressions in real-time with autocomplete
Cart Panel Manipulate cart state, view history, restore snapshots
Error Detection Automatically finds Liquid errors, Drop leaks, missing assets
Network Monitor Capture and replay Shopify API requests
Metafields Viewer Explore metafields across all resources
SEO Inspector Validate meta tags, Open Graph, JSON-LD

Installation: 60 Seconds to Better Debugging

npx shopify-theme-devtools init --inject
Enter fullscreen mode Exit fullscreen mode

That's it. This command:

  1. Copies the bridge snippet to your snippets/ folder
  2. Automatically adds the render tag to your theme.liquid
  3. Detects and injects your metafields.json schema

Or install manually:

npx shopify-theme-devtools init
Enter fullscreen mode Exit fullscreen mode

Then add this line to layout/theme.liquid just before </body>:

{% render 'theme-devtools-bridge' %}
Enter fullscreen mode Exit fullscreen mode

Security Note

The panel only renders on unpublished/development themes. It checks theme.role != 'main' before loading, so it's completely safe to commit to your repository. Your production store will never see it.


Deep Dive: The Objects Inspector

The Objects Inspector is probably where you'll spend most of your time. It gives you a live, searchable view of every Liquid object available in the current template context.

Browsing Objects

Click through the tree to explore nested properties:

shop
├── name: "My Awesome Store"
├── email: "hello@mystore.com"
├── currency: "USD"
├── metafields
│   └── custom
│       └── announcement_bar: "Free shipping over $50!"
└── ...
Enter fullscreen mode Exit fullscreen mode

One-Click Path Copying

Click any property key to copy its Liquid path to your clipboard:

  • Click title under product → copies product.title
  • Click [0] under variants → copies product.variants[0]
  • Click price under that → copies product.variants[0].price

No more guessing the correct path syntax.

Deep Search

Type in the search box to find properties anywhere in the object tree. Looking for a specific metafield key? Search for it. Need to find where inventory_quantity lives? Search finds it instantly.


Deep Dive: The Liquid Console

This is where Shopify Theme Devtools really shines. The Console panel gives you a live Liquid expression evaluator — think of it as a REPL for Liquid.

Basic Usage

> product.title
"Classic Cotton T-Shirt"

> product.price | money
"$29.99"

> cart.item_count
3

> shop.name | upcase
"MY AWESOME STORE"
Enter fullscreen mode Exit fullscreen mode

Supported Liquid Filters

The evaluator supports 50+ Liquid filters, including Shopify-specific ones:

> product.title | upcase
"CLASSIC COTTON T-SHIRT"

> product.title | downcase | split: ' ' | first
"classic"

> product.price | money_with_currency
"$29.99 USD"

> cart.items | size
3

> product.variants | first | json
{"id": 12345, "title": "Small / Blue", ...}

> product.tags | join: ', '
"cotton, summer, sale"
Enter fullscreen mode Exit fullscreen mode

Array Navigation

Navigate complex data structures with bracket notation:

> product.variants[0].title
"Small / Blue"

> product.images[0].src
"https://cdn.shopify.com/..."

> cart.items[0].properties._gift_wrap
"Yes"
Enter fullscreen mode Exit fullscreen mode

Command History

Use the up/down arrow keys to navigate through previous expressions. Your history persists across page navigations.

Autocomplete

Press Tab to autocomplete object paths as you type. The console knows what properties are available and suggests them.


Deep Dive: Liquid Error Detection

One of the most valuable features is automatic error detection. The Console panel continuously scans your page for common Liquid issues.

Error Types Detected

Error Type Example What It Means
Liquid error Liquid error: undefined method 'size' Runtime error in your Liquid code
Syntax error Liquid syntax error: Unknown tag 'endif' Invalid Liquid syntax
Drop leaks #<ProductDrop:0x00007f...> Raw Ruby object rendered (usually from missing `
Missing snippets {% raw %}Liquid error: Could not find snippet 'missing-file' Referenced snippet doesn't exist
Schema errors Liquid error: Invalid JSON in schema Malformed JSON in section schema
JSON filter errors {"error":"not found"} Failed `

Smart Fix Suggestions

Each error comes with context-aware suggestions:
{% raw %}

❌ Liquid error: undefined method 'price' for nil:NilClass
   📍 Found in: sections/product-card.liquid
   💡 Suggestion: Check if 'product' exists before accessing 'price'. 
      Use: {% if product %}{{ product.price }}{% endif %}
Enter fullscreen mode Exit fullscreen mode

Drop Object Detection

This catches a sneaky bug that's easy to miss. If you accidentally render a Liquid object without the | json filter:

<!-- Wrong -->
<script>
  const product = {{ product }};
</script>

<!-- Correct -->
<script>
  const product = {{ product | json }};
</script>
Enter fullscreen mode Exit fullscreen mode

The first version renders as #<ProductDrop:0x00007f...>, breaking your JavaScript. Devtools catches this automatically.


Deep Dive: Cart Panel

Testing cart-dependent features (discounts, upsells, shipping calculators) usually means manually adding items, checking state, removing them, repeat. The Cart Panel changes this.

Live Cart State

See your current cart state in real-time:

Cart (3 items, $89.97)
├── Classic Cotton T-Shirt (Qty: 2) — $59.98
│   └── properties: { _gift_wrap: "Yes" }
├── Leather Belt (Qty: 1) — $29.99
└── attributes: { note: "Please gift wrap" }
Enter fullscreen mode Exit fullscreen mode

Quantity Controls

Adjust quantities directly from the panel. Changes reflect immediately in both the panel and your theme.

Cart History & Snapshots

Every cart mutation is recorded with a timestamp:

12:34:52 — Added "Classic Cotton T-Shirt" (Qty: 1)
12:35:10 — Updated "Classic Cotton T-Shirt" (Qty: 1 → 2)
12:35:45 — Added "Leather Belt" (Qty: 1)
Enter fullscreen mode Exit fullscreen mode

Click any snapshot to restore that exact cart state. Testing "empty cart" vs "3 items" vs "10+ items" becomes instant.

Cart Scenarios

Save named cart configurations for quick testing:

  • "Empty Cart"
  • "Single Item"
  • "Gift Card Only"
  • "Mixed Products + Subscription"
  • "Over Free Shipping Threshold"

One click to load any scenario.

Cart Tests

Create validation rules that run automatically when the cart changes:

// Rule: Gift items must have _gwp_source property
{
  type: "property_dependency",
  name: "GWP Validation",
  condition: { property: "_is_gwp", value: "true" },
  required: ["_gwp_source", "_gwp_campaign"]
}

// Rule: Max 5 of any single item
{
  type: "quantity",
  name: "Per-Item Limit",
  max_per_item: 5
}
Enter fullscreen mode Exit fullscreen mode

16 pre-built templates cover common scenarios.


Deep Dive: Network Panel

The Network Panel captures and lets you inspect all Shopify API requests.

Request Logging

Automatically captures:

  • Cart API (/cart/add.js, /cart/change.js, /cart/update.js)
  • Product API (/products/*.json)
  • Collection API (/collections/*.json)
  • Search API (/search/suggest.json)
  • Storefront GraphQL

Request Details

For each request, see:

  • Method, URL, status code
  • Request headers and body
  • Response headers and body
  • Timing information

Edit & Replay

Modify any captured request and resend it:

// Original request
POST /cart/add.js
{ "id": 12345, "quantity": 1 }

// Edit and replay with different quantity
POST /cart/add.js
{ "id": 12345, "quantity": 5 }
Enter fullscreen mode Exit fullscreen mode

Cart State Diff

After cart mutations, see exactly what changed:

  item_count: 3 → 4
+ items[3]: { title: "New Item", quantity: 1 }
  total_price: 8997 → 11996
Enter fullscreen mode Exit fullscreen mode

Export Options

  • Copy as cURL — For terminal debugging
  • Copy as Fetch — For browser console testing

Additional Panels

Metafields Viewer

Browse metafields across all resources:

product.metafields
├── custom
│   ├── care_instructions: "Machine wash cold"
│   ├── material: "100% Cotton"
│   └── sustainability_score: 8
└── reviews
    ├── rating: 4.5
    └── count: 127

shop.metafields
└── custom
    └── announcement: "Free shipping over $50!"
Enter fullscreen mode Exit fullscreen mode

SEO Inspector

Validate your SEO implementation:

  • Meta Tags — title, description, canonical
  • Open Graph — og:title, og:image, og:description
  • Twitter Cards — twitter:card, twitter:title
  • JSON-LD — Product, Organization, BreadcrumbList schemas

Errors are highlighted with fix suggestions.

Localization Panel

For multi-market stores:

  • Current market, currency, language
  • Available markets with quick switcher
  • Country data and shipping zones

Analytics Viewer

Detects installed tracking:

  • Google Analytics (GA4, Universal)
  • Facebook Pixel
  • TikTok Pixel
  • Pinterest Tag
  • Custom scripts

Storage Inspector

Browse and edit:

  • localStorage
  • sessionStorage
  • Cookies (with expiration and flags)

Keyboard Shortcuts

Action Mac Windows
Toggle Panel Cmd+Shift+D Ctrl+Shift+D
Evaluate Expression Enter Enter
Autocomplete Tab Tab
Command History / /

Tab Customization

Like Chrome DevTools, you can customize your layout:

  • Right-click any tab to show/hide it
  • Drag tabs to reorder them
  • Hidden tabs are completely unloaded (saves memory)
  • "Reset to Defaults" restores original layout

Configuration Options

Local Development Mode

For development with hot reload:

{%- assign devtools_local = true -%}
Enter fullscreen mode Exit fullscreen mode

Then run:

npm run dev  # Starts at localhost:9999
Enter fullscreen mode Exit fullscreen mode

Self-Hosted Assets

If you prefer not to use the CDN:

npx shopify-theme-devtools init --local
Enter fullscreen mode Exit fullscreen mode

This copies JS/CSS to your assets/ folder.

Metafields Schema

To show all defined metafields (not just ones with values), the CLI automatically detects your .shopify/metafields.json:

npx shopify-theme-devtools sync  # Update metafields schema
Enter fullscreen mode Exit fullscreen mode

How It Works (Technical Details)

For the curious:

  1. Context Extraction — The Liquid bridge renders theme objects as a JSON blob using | json filters
  2. Async Data Loading — Product variants and cart data are fetched via Shopify's JSON APIs for live data
  3. Expression Evaluation — Uses LiquidJS to evaluate expressions client-side
  4. Shadow DOM Isolation — All styles are scoped to prevent theme CSS conflicts
  5. Session Persistence — Logs, cart history, and preferences survive page navigations

Tech Stack

  • Lit — Lightweight Web Components (fast, no virtual DOM)
  • LiquidJS — Liquid template engine for expression evaluation
  • Vite — Fast build tooling

Browser Support

  • Chrome 90+
  • Firefox 90+
  • Safari 14+
  • Edge 90+

Real-World Use Cases

Debugging a Broken Product Page

> product
null

// Aha! Product object isn't available. Check your template assignment.
Enter fullscreen mode Exit fullscreen mode

Testing Discount Logic

> cart.total_price | money
"$89.97"

> cart.total_discount | money
"$10.00"

> cart.items | map: 'line_level_discount_allocations' | flatten | size
2
Enter fullscreen mode Exit fullscreen mode

Finding Available Metafields

Search "metafield" in Objects Inspector to see all metafields across every resource, with their current values.

Testing Cart Edge Cases

  1. Save current cart as "Baseline" scenario
  2. Clear cart
  3. Add edge case items (subscription + one-time, quantity limits, etc.)
  4. Test your theme
  5. One-click restore to "Baseline"

Get Started

npx shopify-theme-devtools init --inject
Enter fullscreen mode Exit fullscreen mode

Then press Cmd+Shift+D (or Ctrl+Shift+D) to open the panel.

Links:

Wrapping Up

If you're building Shopify themes, you deserve better debugging tools than {{ thing | json }}. Shopify Theme Devtools brings the debugging experience you're used to from other frameworks into the Liquid world.

Give it a try and let me know what you think. What features would you add? Drop a comment below or open an issue on GitHub.

Happy debugging! 🛠️

Tags: #shopify #webdev #javascript #opensource #devtools #ecommerce #liquidtemplating #debugging

Top comments (2)

Collapse
 
charlottetowell profile image
Charlotte Towell

This is beyond awesome! Cannot wait to check this out and start using at work tomorrow. Thank you for making such a needed tool!

Collapse
 
yakohere profile image
Yakhyo Ismoildjonov

I appreciate your comment. Since it’s still in the early stages, please don’t hesitate to submit any issues you encounter. Thanks!