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
That's it. This command:
- Copies the bridge snippet to your
snippets/folder - Automatically adds the render tag to your
theme.liquid - Detects and injects your
metafields.jsonschema
Or install manually:
npx shopify-theme-devtools init
Then add this line to layout/theme.liquid just before </body>:
{% render 'theme-devtools-bridge' %}
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!"
└── ...
One-Click Path Copying
Click any property key to copy its Liquid path to your clipboard:
- Click
titleunderproduct→ copiesproduct.title - Click
[0]undervariants→ copiesproduct.variants[0] - Click
priceunder that → copiesproduct.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"
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"
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"
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 %}
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>
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" }
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)
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
}
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 }
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
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!"
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 -%}
Then run:
npm run dev # Starts at localhost:9999
Self-Hosted Assets
If you prefer not to use the CDN:
npx shopify-theme-devtools init --local
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
How It Works (Technical Details)
For the curious:
-
Context Extraction — The Liquid bridge renders theme objects as a JSON blob using
| jsonfilters - Async Data Loading — Product variants and cart data are fetched via Shopify's JSON APIs for live data
- Expression Evaluation — Uses LiquidJS to evaluate expressions client-side
- Shadow DOM Isolation — All styles are scoped to prevent theme CSS conflicts
- 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.
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
Finding Available Metafields
Search "metafield" in Objects Inspector to see all metafields across every resource, with their current values.
Testing Cart Edge Cases
- Save current cart as "Baseline" scenario
- Clear cart
- Add edge case items (subscription + one-time, quantity limits, etc.)
- Test your theme
- One-click restore to "Baseline"
Get Started
npx shopify-theme-devtools init --inject
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)
This is beyond awesome! Cannot wait to check this out and start using at work tomorrow. Thank you for making such a needed tool!
I appreciate your comment. Since it’s still in the early stages, please don’t hesitate to submit any issues you encounter. Thanks!