Shopify Plugin


Complete Shopify e-commerce integration that syncs products, orders, customers, inventory, and fulfillment data to PostgreSQL with real-time webhook support.

Overview

The Shopify plugin provides complete synchronization between your Shopify store and a local PostgreSQL database. It enables:

  • Faster Reporting - Query your entire store history without API calls
  • Custom Analytics - Build complex reports with SQL that are not possible in Shopify
  • Cross-System Integration - Join Shopify data with other systems (CRM, ERP, etc.)
  • Offline Access - Your data is always available, even without internet
  • Real-Time Updates - Webhooks keep your local data in sync
  • Historical Analysis - Full historical data for trend analysis

Installation

# Install the plugin
nself plugin install shopify

# Verify installation
nself plugin status shopify

Configuration

Environment Variables

# Required - Shopify store domain
SHOPIFY_SHOP_DOMAIN=your-store.myshopify.com

# Required - Admin API access token
# Create at: Settings > Apps > Develop apps > Create an app
SHOPIFY_ACCESS_TOKEN=shpat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Required - PostgreSQL connection string
DATABASE_URL=postgresql://user:password@localhost:5432/nself

# Optional - Webhook HMAC secret
SHOPIFY_WEBHOOK_SECRET=your_webhook_secret

# Optional - API version (default: 2024-01)
SHOPIFY_API_VERSION=2024-01

# Optional - Server configuration
PORT=3003
HOST=0.0.0.0

Creating Access Token

  1. Go to Shopify Admin > Settings > Apps and sales channels
  2. Click "Develop apps" > "Create an app"
  3. Name your app (e.g., "nself Sync")
  4. Click "Configure Admin API scopes"
  5. Enable the following scopes:
    • read_products - Products and collections
    • read_orders - Orders and transactions
    • read_customers - Customer data
    • read_inventory - Inventory levels
    • read_locations - Location data
    • read_fulfillments - Fulfillment data
    • read_draft_orders - Draft orders
    • read_discounts - Discount codes
  6. Click "Install app"
  7. Copy the Admin API access token

Development Store

Use a Shopify development store for testing. Development stores are free and have full API access for building and testing integrations.

Usage

Initialize Database Schema

# Create all required tables
nself-shopify init

# Or via nself CLI
nself plugin shopify init

Sync Data

# Sync all data from Shopify
nself-shopify sync

# Sync specific resources
nself-shopify sync --resources products,orders,customers

# Incremental sync (only changes since last sync)
nself-shopify sync --incremental

Start Webhook Server

# Start the server
nself-shopify server

# Custom port
nself-shopify server --port 3003

# The server exposes:
# - POST /webhook - Shopify webhook endpoint
# - GET /health - Health check
# - GET /api/* - REST API endpoints

CLI Commands

Product Commands

# List all products
nself-shopify products list

# Search products
nself-shopify products search "keyword"

# Filter by status
nself-shopify products list --status active
nself-shopify products list --status draft
nself-shopify products list --status archived

# Filter by vendor
nself-shopify products list --vendor "Brand Name"

# Get product details
nself-shopify products get 123456789

# List product variants
nself-shopify products variants 123456789

# Show inventory levels
nself-shopify products inventory 123456789

Order Commands

# List all orders
nself-shopify orders list

# Filter by financial status
nself-shopify orders list --status paid
nself-shopify orders list --status pending
nself-shopify orders list --status refunded

# Filter by fulfillment status
nself-shopify orders list --fulfillment unfulfilled
nself-shopify orders list --fulfillment fulfilled

# Filter by date range
nself-shopify orders list --since 2024-01-01 --until 2024-12-31

# Get order details
nself-shopify orders get 123456789

# List order line items
nself-shopify orders items 123456789

Customer Commands

# List all customers
nself-shopify customers list

# Search customers
nself-shopify customers search "john@example.com"

# Get customer details
nself-shopify customers get 123456789

# View customer orders
nself-shopify customers orders 123456789

# Top customers by total spent
nself-shopify customers top --limit 20

Inventory Commands

# List all inventory
nself-shopify inventory list

# Low stock alerts
nself-shopify inventory low-stock --threshold 10

# Inventory by location
nself-shopify inventory list --location "Main Warehouse"

# Get inventory level for variant
nself-shopify inventory get variant_123456

Fulfillment Commands

# List fulfillments
nself-shopify fulfillments list

# Filter by status
nself-shopify fulfillments list --status pending
nself-shopify fulfillments list --status success

# Get fulfillment details
nself-shopify fulfillments get 123456789

Status Command

# Show sync status
nself-shopify status

# Output:
# Store: your-store.myshopify.com
# Products: 1,234 (45 variants)
# Orders: 5,678 (open: 23)
# Customers: 3,456
# Inventory Items: 2,345
# Last Sync: 2026-01-24 12:00:00

Webhook Setup

Shopify Admin

  1. Go to Settings > Notifications > Webhooks
  2. Create webhooks for each topic:
    • URL: https://your-domain.com/webhooks/shopify
    • Format: JSON
  3. Topics to subscribe:
    • orders/create, orders/updated, orders/paid, orders/fulfilled
    • products/create, products/update, products/delete
    • customers/create, customers/update
    • inventory_levels/update

Shopify CLI

shopify app webhook forward --topic orders/create \
  --path /webhooks/shopify --port 443

Synced Resources

ResourceTableNotes
Shopshopify_shopsStore settings and metadata
Productsshopify_productsFull product catalog
Product Variantsshopify_product_variantsSize, color, etc.
Product Imagesshopify_product_imagesAll product images
Collectionsshopify_collectionsSmart and custom collections
Customersshopify_customersCustomer profiles
Customer Addressesshopify_customer_addressesShipping addresses
Ordersshopify_ordersAll order data
Order Line Itemsshopify_order_line_itemsIndividual line items
Fulfillmentsshopify_fulfillmentsFulfillment records
Refundsshopify_refundsRefund records
Transactionsshopify_transactionsPayment transactions
Inventory Itemsshopify_inventory_itemsInventory tracking
Inventory Levelsshopify_inventory_levelsStock quantities
Locationsshopify_locationsWarehouse locations
Draft Ordersshopify_draft_ordersUnpaid orders
Abandoned Checkoutsshopify_abandoned_checkoutsRecovery opportunities
Discount Codesshopify_discount_codesPromo codes

Analytics Views

ViewDescription
shopify_sales_by_dayDaily sales totals
shopify_top_productsBest selling products
shopify_low_stockLow inventory alerts
shopify_customer_ltvCustomer lifetime value
shopify_order_summaryOrder status breakdown

Example Queries

-- Daily sales report
SELECT
    DATE(created_at) as date,
    COUNT(*) as order_count,
    SUM(total_price) as revenue,
    AVG(total_price) as avg_order_value
FROM shopify_orders
WHERE financial_status = 'paid'
  AND created_at > NOW() - INTERVAL '30 days'
GROUP BY DATE(created_at)
ORDER BY date DESC;

-- Top products by revenue
SELECT
    p.title,
    p.vendor,
    COUNT(DISTINCT li.order_id) as order_count,
    SUM(li.quantity) as units_sold,
    SUM(li.price * li.quantity) as revenue
FROM shopify_products p
JOIN shopify_product_variants v ON p.id = v.product_id
JOIN shopify_order_line_items li ON v.id = li.variant_id
JOIN shopify_orders o ON li.order_id = o.id
WHERE o.financial_status = 'paid'
  AND o.created_at > NOW() - INTERVAL '30 days'
GROUP BY p.id, p.title, p.vendor
ORDER BY revenue DESC
LIMIT 20;

-- Customer lifetime value
SELECT
    c.id,
    c.email,
    c.first_name,
    c.last_name,
    COUNT(DISTINCT o.id) as total_orders,
    SUM(o.total_price) as lifetime_value,
    MIN(o.created_at) as first_order,
    MAX(o.created_at) as last_order
FROM shopify_customers c
JOIN shopify_orders o ON c.id = o.customer_id
WHERE o.financial_status = 'paid'
GROUP BY c.id, c.email, c.first_name, c.last_name
HAVING COUNT(DISTINCT o.id) > 1
ORDER BY lifetime_value DESC
LIMIT 100;

-- Inventory alerts
SELECT
    p.title as product,
    v.title as variant,
    v.sku,
    il.available,
    l.name as location
FROM shopify_inventory_levels il
JOIN shopify_inventory_items ii ON il.inventory_item_id = ii.id
JOIN shopify_product_variants v ON ii.id = v.inventory_item_id
JOIN shopify_products p ON v.product_id = p.id
JOIN shopify_locations l ON il.location_id = l.id
WHERE il.available <= 10
  AND p.status = 'active'
ORDER BY il.available ASC;

GraphQL Access

query GetRecentOrders {
  shopify_orders(
    order_by: { created_at: desc }
    limit: 20
  ) {
    id
    order_number
    total_price
    fulfillment_status
    created_at
    shopify_customer {
      email
      first_name
      last_name
    }
    shopify_order_line_items {
      title
      quantity
      price
    }
  }
}

Environment Handling

Development

ENV=dev
SHOPIFY_STORE=your-store-dev       # Use development store
SHOPIFY_ACCESS_TOKEN=shpat_dev

Use a Shopify development store for dev/staging.

Production

ENV=prod
SHOPIFY_STORE=your-store           # Production store
SHOPIFY_ACCESS_TOKEN=shpat_live

Rate Limits

Shopify has a 2 requests/second limit for the Admin API. The plugin automatically handles rate limiting with a 0.5s delay between requests.

Uninstall

# Remove plugin and data
nself plugin remove shopify

# Keep database tables
nself plugin remove shopify --keep-data

Webhook Configuration

Supported Webhook Topics

  • orders/create - New order placed
  • orders/updated - Order modified
  • orders/paid - Order payment received
  • orders/fulfilled - Order fulfilled
  • orders/cancelled - Order cancelled
  • products/create - New product created
  • products/update - Product modified
  • products/delete - Product deleted
  • customers/create - New customer registered
  • customers/update - Customer modified
  • inventory_levels/update - Stock level changed
  • fulfillments/create - Fulfillment created
  • refunds/create - Refund issued
  • checkouts/create - Checkout started
  • checkouts/update - Checkout modified
  • And more...

Setting Up Webhooks

  1. Go to Shopify Admin > Settings > Notifications
  2. Scroll to "Webhooks"
  3. Click "Create webhook"
  4. Configure:
    • Event: Select the event type
    • Format: JSON
    • URL: https://your-domain.com/webhook
    • API version: 2024-01
  5. Copy the "Webhook signing secret" to SHOPIFY_WEBHOOK_SECRET

Troubleshooting

Authentication Errors

Error: [API] Invalid API key or access token

Test your credentials:

curl -H "X-Shopify-Access-Token: $SHOPIFY_ACCESS_TOKEN" \
  "https://$SHOPIFY_SHOP_DOMAIN/admin/api/2024-01/shop.json"

Rate Limiting

Error: Exceeded 2 calls per second for api client

The plugin handles rate limiting automatically. If you see persistent errors:

  • Reduce concurrent operations
  • Use incremental sync instead of full sync

Webhook Signature Failed

Error: Webhook signature verification failed

Solutions:

  1. Verify SHOPIFY_WEBHOOK_SECRET matches Shopify admin
  2. Ensure you are using the raw request body
  3. Check that Content-Type is application/json

Debug Mode

LOG_LEVEL=debug nself-shopify sync

Integration Examples

Inventory Alerts

// Check for low inventory
async function checkLowInventory(threshold: number = 10) {
  const result = await hasura.query({
    query: `
      query LowInventory($threshold: Int!) {
        shopify_inventory(
          where: { available: { _lte: $threshold } }
        ) {
          product_id
          variant_id
          available
          shopify_variant {
            title
            sku
            shopify_product {
              title
            }
          }
        }
      }
    `,
    variables: { threshold }
  });

  return result.shopify_inventory;
}

Order Fulfillment Dashboard

-- Fulfillment status overview
CREATE VIEW fulfillment_dashboard AS
SELECT
  fulfillment_status,
  COUNT(*) AS order_count,
  SUM(total_price) AS total_value,
  AVG(EXTRACT(EPOCH FROM (NOW() - created_at)) / 3600)::int AS avg_hours_pending
FROM shopify_orders
WHERE created_at > NOW() - INTERVAL '30 days'
GROUP BY fulfillment_status
ORDER BY order_count DESC;

Customer Lifetime Value

query CustomerLTV {
  shopify_customer_value(
    order_by: { total_spent: desc }
    limit: 100
  ) {
    customer_id
    email
    orders_count
    total_spent
    average_order_value
    first_order_date
    last_order_date
  }
}

Support

Related

Last Updated: January 2026 | Plugin Version 1.0.0 | Shopify API Version 2024-01