Merchant Settings
Merchant Settings
Extensions can declare a settings schema that defines configurable fields. Merchants fill in these fields from the dashboard's extension configuration panel. Your extension reads the values at runtime and adjusts its behavior accordingly.
This lets merchants customize your extension — choosing a display color, toggling features, entering API keys, selecting options — without you needing to build a separate settings page.
How It Works
- You define a
settings_schemaarray in your extension config. - The platform renders a settings form for merchants in the dashboard (Settings > Apps > [App] > Extensions).
- The merchant fills in the fields and saves.
- Your extension reads the values from
{{settings.key}}(JSON mode) orselorax.settings(sandbox mode).
Settings Field Types
| Type | Description | Rendered As |
|---|---|---|
text | Single-line text input | Text field |
number | Numeric input | Number field |
toggle | Boolean on/off switch | Toggle switch |
select | Dropdown with predefined options | Select dropdown |
textarea | Multi-line text input | Text area |
color | Color value | Color picker |
Settings Schema Format
Each field in the settings_schema array is an object with these properties:
| Field | Type | Required | Description |
|---|---|---|---|
key | string | Yes | Unique identifier for this setting. Used to read the value at runtime. |
label | string | Yes | Human-readable label shown to the merchant. |
type | string | Yes | One of: text, number, toggle, select, textarea, color |
default | any | No | Default value when the merchant has not configured a value. |
description | string | No | Help text shown below the field. |
placeholder | string | No | Placeholder text for text/textarea/number fields. |
required | boolean | No | Whether the merchant must fill in this field. Default: false |
options | array | select only | Array of { label, value } objects for the dropdown. |
Example Schema
{
"extension_id": "discount-banner",
"target": "checkout.block",
"title": "Discount Banner",
"mode": "json",
"settings_schema": [
{
"key": "enabled",
"label": "Enable Banner",
"type": "toggle",
"default": true,
"description": "Show or hide the discount banner in checkout."
},
{
"key": "banner_text",
"label": "Banner Text",
"type": "text",
"default": "Use code SAVE10 for 10% off!",
"placeholder": "Enter banner message...",
"required": true
},
{
"key": "discount_percent",
"label": "Discount Percentage",
"type": "number",
"default": 10,
"description": "The discount percentage to apply."
},
{
"key": "banner_color",
"label": "Banner Color",
"type": "color",
"default": "#2563eb",
"description": "Background color of the banner."
},
{
"key": "banner_position",
"label": "Banner Position",
"type": "select",
"default": "top",
"options": [
{ "label": "Top of page", "value": "top" },
{ "label": "Bottom of page", "value": "bottom" },
{ "label": "Inline with items", "value": "inline" }
]
},
{
"key": "custom_css",
"label": "Custom CSS",
"type": "textarea",
"default": "",
"placeholder": "Optional custom styles...",
"description": "Advanced: enter custom CSS to style the banner."
}
],
"ui": { ... }
}Reading Settings in JSON Mode
In JSON extensions, use template expressions to access merchant settings:
{
"type": "Banner",
"props": {
"title": "{{settings.banner_text}}",
"status": "info",
"when": "{{settings.enabled}}"
}
}The {{settings.key}} syntax resolves to the merchant's configured value, or the default value from the schema if the merchant has not configured it.
Full JSON Example
Here is the complete discount banner extension using merchant settings:
{
"extension_id": "discount-banner",
"target": "checkout.block",
"title": "Discount Banner",
"mode": "json",
"settings_schema": [
{
"key": "enabled",
"label": "Enable Banner",
"type": "toggle",
"default": true
},
{
"key": "banner_text",
"label": "Banner Text",
"type": "text",
"default": "Use code SAVE10 for 10% off!",
"required": true
},
{
"key": "discount_percent",
"label": "Discount Percentage",
"type": "number",
"default": 10
},
{
"key": "banner_color",
"label": "Banner Color",
"type": "color",
"default": "#2563eb"
},
{
"key": "banner_position",
"label": "Banner Position",
"type": "select",
"default": "top",
"options": [
{ "label": "Top of page", "value": "top" },
{ "label": "Bottom of page", "value": "bottom" }
]
}
],
"ui": {
"type": "Card",
"props": {
"padding": "none",
"when": "{{settings.enabled}}"
},
"children": [
{
"type": "Banner",
"props": {
"title": "{{settings.banner_text}}",
"status": "info"
}
},
{
"type": "Text",
"props": {
"content": "Discount: {{settings.discount_percent}}% off your order",
"align": "center",
"variant": "body",
"weight": "semibold"
}
}
]
}
}When a merchant sets enabled to false, the entire card is hidden. When they change banner_text, the banner message updates. No code change or redeployment is needed.
Reading Settings in Sandbox Mode
In sandbox extensions, merchant settings are available on the selorax.settings object. This is populated automatically when the host sends the selorax:init message.
const { selorax, Card, Banner, Text, BlockStack } = require('@selorax/ui');
selorax.ready();
const settings = selorax.settings;
if (settings.enabled) {
selorax.render(
Card({ padding: 'none' },
BlockStack({ gap: 'md' },
Banner({
title: settings.banner_text || 'Special offer!',
status: 'info'
}),
Text({
content: `Discount: ${settings.discount_percent || 10}% off your order`,
align: 'center',
weight: 'semibold'
})
)
)
);
} else {
// Extension is disabled by merchant — render nothing or a minimal placeholder
selorax.render(
Text({ content: '' })
);
}Reacting to Settings Changes
If the merchant updates settings while your extension is loaded, the host sends a selorax:context_update message. Register a listener to re-render:
selorax.onContextUpdate((context) => {
// Settings may have changed — re-render
render();
});Dashboard UI for Merchants
When a merchant navigates to Settings > Apps and selects an installed app, they see a list of extensions with their settings. The dashboard renders each setting field based on the settings_schema:
togglefields appear as on/off switches.textfields appear as text inputs with optional placeholder.numberfields appear as numeric inputs.selectfields appear as dropdown menus with the defined options.textareafields appear as multi-line text areas.colorfields appear as color pickers.
Each field shows its label and description. Required fields are marked. The merchant clicks "Save" to persist their settings, which are stored in the installation metadata under extension_config[extension_id].merchant_settings.
Merchants can also:
- Enable/disable each extension with a toggle.
- Reorder extensions that share the same target (e.g., multiple blocks on the order detail page).
Example: Configurable Shipping Estimator
This example shows a product detail block that estimates shipping cost based on merchant-configured rates.
Extension Config
{
"extension_id": "shipping-estimator",
"target": "product.detail.block",
"title": "Shipping Estimator",
"mode": "json",
"settings_schema": [
{
"key": "enabled",
"label": "Show Estimator",
"type": "toggle",
"default": true
},
{
"key": "flat_rate",
"label": "Flat Shipping Rate (BDT)",
"type": "number",
"default": 60,
"description": "Standard shipping cost."
},
{
"key": "free_threshold",
"label": "Free Shipping Threshold (BDT)",
"type": "number",
"default": 2000,
"description": "Orders above this amount get free shipping."
},
{
"key": "free_shipping_text",
"label": "Free Shipping Message",
"type": "text",
"default": "Free shipping on orders over {{threshold}}!",
"description": "Message shown when free shipping applies."
},
{
"key": "estimation_method",
"label": "Estimation Method",
"type": "select",
"default": "flat",
"options": [
{ "label": "Flat rate", "value": "flat" },
{ "label": "Weight-based", "value": "weight" },
{ "label": "Zone-based", "value": "zone" }
]
}
],
"ui": {
"type": "Card",
"props": {
"title": "Shipping",
"when": "{{settings.enabled}}"
},
"children": [
{
"type": "BlockStack",
"props": { "gap": "sm" },
"children": [
{
"type": "KeyValue",
"props": {
"label": "Shipping Cost",
"value": "{{settings.flat_rate}} BDT"
}
},
{
"type": "KeyValue",
"props": {
"label": "Free Shipping Over",
"value": "{{settings.free_threshold}} BDT"
}
},
{
"type": "Badge",
"props": {
"content": "{{settings.estimation_method}}",
"variant": "info"
}
}
]
}
]
}
}What the Merchant Sees
-
In Settings > Apps > Shipping Estimator, the merchant sees a form with five fields:
- A toggle for "Show Estimator" (default: on)
- A number input for "Flat Shipping Rate" (default: 60)
- A number input for "Free Shipping Threshold" (default: 2000)
- A text input for "Free Shipping Message"
- A dropdown for "Estimation Method" with three options
-
The merchant changes the flat rate to
80and the threshold to1500, then saves. -
On the product detail page, the "Shipping" card now shows "80 BDT" as the shipping cost and "1500 BDT" as the free shipping threshold.
No redeployment, no code change, no developer involvement.
Tips
-
Always provide defaults. If a merchant installs your app and never touches settings, the extension should work with sensible defaults.
-
Keep the schema small. Five to ten settings is a good maximum. If you need more complex configuration, use a settings page (
settings.pagetarget) instead. -
Use
descriptiongenerously. Merchants are not developers. Explain what each setting does in plain language. -
Validate on the backend. Settings are user input. If your
call_backendaction uses a setting value, validate it server-side. -
Use
togglefor feature flags. If a merchant might want to turn off part of your extension, expose it as a toggle rather than requiring them to uninstall.
What's Next
- Extension Platform Overview — Architecture and target reference
- JSON Extensions — Build UIs that react to settings with template expressions
- CLI Reference — Deploy extensions with settings schemas
- Metafields — Store custom data alongside settings