Plugins: build your own features

Plugins are small JavaScript programs that add features to your store: reports, automations, storefront widgets, integrations. You can write them yourself in the built-in code editor (the same editor as VS Code, with autocompletion for the sp API), ask your AI ("write a ShopPress plugin that…"), upload a plugin file, or install one from the gallery or the shared library. Plugins are part of the Builder and Studio plans and the Plugins module (switch it on under Modules).

They run in a sealed sandbox (QuickJS, WebAssembly):

  • only your store; no other store's data is reachable
  • no file system, no Node.js, no direct internet; outside services only through sp.http.fetch to hosts you approved
  • limits on time, memory and calls
  • deleting data needs your explicit permission

Plugins run at your own risk; test them first (Test = dry run).

The shape of a plugin

plugin = {
  name: "Low stock alert",
  description: "Hourly check for low stock.",
  scopes: ["read_inventory"],            // extra Shopify permissions (optional)
  http: ["hooks.slack.com"],             // outside hosts it may call (optional)
  settings: {                            // a settings form is built from this (optional)
    threshold: { type: "number", label: "Alert at or below", default: 3 },
    webhook:   { type: "secret", label: "Slack webhook URL" },
  },
  tools: {
    check_stock: {
      description: "Variants at or below the threshold.",
      input: { limit: "number?" },       // string | number | boolean, add ? for optional
      schedule: 60,                      // run every 60 minutes (optional, minimum 15)
      on: ["inventory_levels/update"],   // run on Shopify events (optional)
      public: false,                     // callable from the storefront (optional, read-only)
      flow: true,                        // offered in Shopify Flow (optional)
      run(input, sp) {
        const r = sp.shopify.graphql(`{ shop { name } }`);
        return { shop: r.shop.name };
      },
    },
  },
};

run may be normal or async; return any JSON. Tool names use lowercase letters, digits and _.

The sp toolbox

APIWhat it does
sp.shopify.graphql(query, variables)Shopify Admin GraphQL for your store, within granted permissions. Retries automatically when Shopify is busy.
sp.kv.get(key) / set(key, value) / delete(key) / list()Small JSON storage for this plugin (1,000 keys, 100 KB each).
sp.settingsValues from the plugin's settings form (secrets excluded).
sp.secrets.get(name)A secret setting (stored encrypted, never shown again).
sp.http.fetch(url, { method, headers, body })Call an outside HTTPS service on an approved host. Returns { status, ok, headers, text(), json() }.
sp.theme.setBlock(key, html)Save HTML for the ShopPress plugin content theme block with that key. Scripts are removed.
sp.flow.trigger(event, details)Start Shopify Flow workflows that use the ShopPress plugin event trigger.
sp.eventWhat started the run: a Shopify event ({ topic, data }), a Flow call or a storefront request.
sp.triggermanual, mcp, schedule, flow, storefront, or the event topic.
sp.shop{ name, domain, currency, timezone, plan, plus, devStore }. Use sp.shop.plus for Shopify Plus-only features.
sp.utilscsv.parse/stringify, date.now/addDays/daysBetween/format, chunk, slug, escapeHtml.
sp.log(...)Lines shown in the plugin's run log.

Permissions (scopes)

ShopPress installs with product and file access only. A plugin lists extra permissions in scopes; after saving, the Plugins page shows Grant permissions, which opens Shopify's permission window. Until they are granted, the plugin won't run and says which ones are missing.

Available: inventory, locations, orders, draft orders, order edits, fulfillments, returns, customers, content (pages, blogs), navigation, metaobjects, discounts, price rules, shipping, markets, translations, locales, publications, themes (read), reports, product listings, gift cards, and B2B companies (Plus).

Orders and customers include personal data. Shopify allows that data only after the app's data-protection review.

Triggers: when a plugin runs

TriggerHow
By handPlugins page → Run (or Test for a dry run)
By your AIMCP plugin_run or the tool plugin__<slug>__<tool>
On a scheduleschedule: 60 (minutes, 15 to 10,080)
On Shopify eventson: ["products/create", "orders/paid", …], the event is in sp.event
From Shopify Flowflow: true, then use the Run ShopPress plugin action in Flow
From the storefrontpublic: true, then use the ShopPress live plugin theme block

Supported events: products/create, products/update, products/delete, collections/create, collections/update, inventory_levels/update, orders/create, orders/paid, orders/fulfilled, orders/cancelled, orders/updated, refunds/create, draft_orders/create, fulfillments/create, customers/create, customers/update.

Automatic runs (schedule, events, Flow) that fail 5 times in a row pause the plugin. The Plugins page shows why; switch it back on after fixing.

Show plugin output in your theme

See Theme blocks. In short: sp.theme.setBlock("my_banner", html) plus the ShopPress plugin content block with key my_banner. For live, per-product content, mark a tool public: true and add the ShopPress live plugin block.

Lifecycle: install, verify, activate

Like WordPress plugins, every plugin is installed, then activated or deactivated:

  1. Save, upload or install. Upload a .js file or a .shoppress-plugin.json package (made with Export).
  2. Safe-mode verification runs automatically. It checks the manifest and limits, runs the plugin's tests, and dry-runs every tool that needs no input. Missing permissions or unapproved hosts are warnings; crashes are failures.
  3. A new plugin is activated only if verification passes. A new version that fails verification deactivates the plugin, so broken code never runs automatically. The report shows each check.
  4. Deactivate keeps the plugin and its data. Delete removes it with its stored data and logs (export it first if you may want it back).

Safe mode (top of the Plugins page, or MCP plugin_safe_mode) stops all plugins at once: no runs, schedules, events or storefront widgets. Use it if anything looks wrong, then switch plugins back on one by one.

Tests

Add tests to a plugin. They run in dry-run mode (Run tests, MCP plugin_tests_run, and during verification):

tests: {
  returns_a_list: { tool: "products_without_images", input: { limit: 5 }, check: (result) => Array.isArray(result) || "expected a list" },
},

check returns true to pass, or a message explaining what went wrong.

Widgets: HTML, CSS and JavaScript for your storefront

widgets: {
  countdown: {
    label: "Sale countdown",
    html: '<div class="sp-countdown" data-end="2026-12-24T23:59:00Z"></div>',
    css: ".sp-countdown{font-weight:700;padding:8px;background:#111;color:#fff;text-align:center}",
    js: "document.querySelectorAll('.sp-countdown').forEach(function(el){ /* … */ })",
  },
},

Add a widget with the ShopPress widget theme block (plugin slug and widget name), or anywhere in your theme with <div data-shoppress-widget="<plugin>/<widget>"></div> when the ShopPress app embed is on. That includes Custom Liquid sections, where you can mix Liquid and widgets. HTML is cleaned of scripts. The widget's JavaScript runs only after you tick "Allow this plugin's widget JavaScript", because it runs on your live store.

Discounts with ShopPress's Shopify Function

ShopPress includes a rule discount (a Shopify Function). It runs inside Shopify's checkout on every plan. Plugins create automatic discounts that use it and set their rules in the discount's $app.rules metafield:

{ "rules": [
  { "type": "product", "vendor": "Trixie", "minQuantity": 2, "percent": 10, "message": "10% off Trixie (2+)" },
  { "type": "product", "productType": "Wet Cat Food", "amount": 1.5, "message": "£1.50 off" },
  { "type": "order", "minSubtotal": 50, "percent": 5, "message": "5% off orders over 50" }
] }

Product rules can use vendor, productType, productIds and minQuantity, with percent or amount (add eachItem: true to take the amount off each item). Order rules use minSubtotal. Every matching line gets its product discount. Install Discount rules from the gallery for a ready-made plugin: set the rules in its settings and run apply_rules. It needs the discount permission.

Share, back up, get help

  • Library: publish a verified plugin (choose a category and author name). ShopPress reviews it before others can install it. Installed library plugins show updates when the author publishes a new version.
  • Backups: Backups hold all plugins, settings and stored data; restore any time.
  • Support access: "Give access for 72 hours" lets ShopPress support read your plugins and run logs (never secrets) to help fix a problem. End it any time.

Test, run, versions

  • Test runs a dry run. Shopify reads work, but no changes, no kv writes and only GET requests to outside services.
  • Run is for real. Every run is logged (input, time, result or error, your sp.log lines).
  • Every save is a new version; Roll back puts an earlier one back (the last 20 are kept).
  • Turn off is the kill switch: the plugin stops running and its tools disappear from MCP.

Limits

LimitValue
Run time20 seconds
Memory32 MB
Shopify calls per run50
Outside requests per run20 (10 s, 1 MB each)
Code size (incl. widgets)250 KB (widgets: 150 KB)
Result size256 KB
Plugins per storeBuilder 25 · Studio 100
Runs per monthBuilder 50,000 · Studio 300,000

Errors

Plugin errors never break ShopPress or your store. The run log shows the message. Common ones:

MessageFix
needs these Shopify permissions firstGrant permissions on the Plugins page
… is not approved for this pluginAdd the host to plugin.http, then approve it
Dry run: mutations are not sentUse Run instead of Test
This mutation deletes or removes dataRun with Allow deleting after checking
More than 50 Shopify callsProcess fewer items per run (use schedule and sp.kv to continue)
interruptedThe run took over 20 seconds; do less per run

Install a ready-made plugin in one click, then change it freely:

PluginWhat it does
Products without imagesLists active products with no image
Auto-tag new productsTags new products with vendor and type
SEO meta fillerFills empty SEO titles and descriptions
Low stock alertHourly check, starts a Flow workflow for new low-stock items
Free shipping barA banner for your theme (theme block)
More from this brandLive product-page block with the brand's other products
Tag big ordersTags paid orders over an amount (order permission)
Discount rulesAutomatic discounts from rules, using ShopPress's Shopify Function
B2B companies reportCSV of B2B companies (Shopify Plus)