Skip to content
Last updated

🏷️ Metafields & Tags

Shopify Metafields & Tags Reference

Appstle Subscriptions uses Shopify metafields and tags to store subscription data, power storefront widgets, and enable automation workflows. This reference covers every metafield and tag — what it contains, when it's set, and how to use it in your integration.


📦 Metafields Overview

All metafields use the namespace appstle_subscription and are managed through the Shopify GraphQL Admin API (MetafieldsSetMutation).

Metafields are set on four Shopify resource types:

ResourceCountVisibilityDescription
Shop15+ keysPublic (readable by any app/theme)App configuration, widget settings, selling plans, build-a-box data
Selling Plan1 keyPublicIndividual selling plan metadata
Order1 keyPublicSubscription context for each order
Customer1 keyPublicAll subscription contracts for the customer

Namespace visibility: All subscription metafields use the appstle_subscription namespace (no $app: prefix), which means they are readable by other apps, themes, and Liquid templates.


🏪 Shop Metafields

Shop metafields store the app's configuration and are used by the storefront widget, checkout extensions, and build-a-box features. They are written by SubscribeItScriptUtils.updateShopMetafieldsForSettings() whenever a merchant saves settings.

When updated: On every settings save in the Appstle admin, and on selling plan or bundle configuration changes. Updates are synchronous (immediate).

Core Configuration

appstle_subscription / setting

PropertyValue
Typejson
ResourceShop
PurposeCore widget and app configuration — UI settings, asset paths, selling plans, labels, and validation rules
Updated whenMerchant saves settings in the Appstle admin
{
  "widgetEnabled": true,
  "sellingPlans": [...],
  "assetPaths": {
    "js": "https://cdn.appstle.com/...",
    "css": "https://cdn.appstle.com/..."
  },
  "labels": {...},
  "validationRules": {...}
}

appstle_subscription / labels

PropertyValue
Typemulti_line_text_field
ResourceShop
PurposeLocalized UI labels and translations for the subscription widget
Updated whenMerchant saves label translations
Also set byLabelTranslationsServiceImpl

appstle_subscription / shop_info

PropertyValue
Typejson
ResourceShop
PurposeShop metadata including money format, feature flags, and API tokens

Selling Plan Metafields

appstle_subscription / selling_plans

PropertyValue
Typejson
ResourceShop
PurposeFree-product selling plans only
Also set bySubscriptionGroupServiceImpl

appstle_subscription / all_Selling_Plans

PropertyValue
Typejson
ResourceShop
PurposeALL selling plans (including paid plans)
Also set bySubscriptionGroupServiceImpl

Note: The key uses camelCase (all_Selling_Plans) — this is intentional and must not be changed.

Checkout Validation

appstle_subscription / checkout_validation

PropertyValue
Typejson
ResourceShop
PurposeCheckout validation rules including duplicate subscription restrictions and per-customer limits
{
  "preventDuplicateSubscriptions": true,
  "maxSubscriptionsPerCustomer": 5,
  "rules": [...]
}

Widget Templates

appstle_subscription / widget_template_html

PropertyValue
Typemulti_line_text_field
ResourceShop
PurposeCustom widget template HTML (only set if merchant has configured a custom template)

appstle_subscription / all_widget_template_html

PropertyValue
Typejson
ResourceShop
PurposeMap of all available widget templates

Build-a-Box Metafields

Build-a-box bundles use multiple metafield keys for configuration, styling, and validation.

KeyTypePurpose
bundlejsonBundle/build-a-box configuration
bab_subscription_cssjsonBuild-a-box subscription CSS styles
bab_customization_cssjsonBuild-a-box customization CSS
bab_validation_infojsonBuild-a-box validation rules
bab_setting_infojsonBuild-a-box settings
bab_info_0, bab_info_1, ...jsonIndividual build-a-box bundle details (one per enabled bundle, dynamically indexed)
total_babintegerTotal count of enabled build-a-box bundles

Build-a-box metafields are set by SubscriptionBundlingServiceImpl.handleMetafieldInputBuildABoxInfo(). The bab_info_* keys are zero-indexed — if a merchant has 3 bundles, the keys will be bab_info_0, bab_info_1, and bab_info_2.


📋 Selling Plan Metafields

appstle_subscription / selling_plan

PropertyValue
Typejson
ResourceSelling Plan
PurposeIndividual selling plan metadata (frequency, billing policy, discounts)
Set bySubscriptionGroupServiceImpl.createOrUpdateSellingPlans()
Updated whenSelling plan is created or modified
{
  "frequencyCount": 1,
  "frequencyInterval": "MONTH",
  "billingPolicy": {
    "interval": "MONTH",
    "intervalCount": 1
  },
  "discountType": "PERCENTAGE",
  "discountValue": 10.0
}

📦 Order Metafields

appstle_subscription / details

PropertyValue
Typejson
ResourceOrder
PurposeFull subscription contract context for this order
Set byAbstractSubscriptionService.updateOrderMetafields() (subscription-async)
Updated whenOrder is created via subscription (initial or recurring billing)
Update mechanismQueued via SQS, processed asynchronously

This metafield contains a complete snapshot of the subscription context at the time the order was created:

{
  "customer": {
    "id": "gid://shopify/Customer/1234567890"
  },
  "subscriptionContract": {
    "id": "gid://shopify/SubscriptionContract/9876543210",
    "status": "ACTIVE",
    "sellingPlanIds": ["gid://shopify/SellingPlan/111"],
    "sellingPlanNames": ["Monthly Subscription - 10% off"],
    "variantIds": ["gid://shopify/ProductVariant/222"],
    "variantNames": ["Default Title"],
    "currentCycle": 3,
    "groupPlanNames": ["Subscribe & Save"],
    "cancellationReason": null
  },
  "lineItems": [
    {
      "variantId": "gid://shopify/ProductVariant/222",
      "title": "Premium Coffee Beans",
      "productId": "gid://shopify/Product/333",
      "sellingPlanId": "gid://shopify/SellingPlan/111",
      "sellingPlanName": "Monthly Subscription - 10% off",
      "sku": "COFFEE-PREMIUM-1KG"
    }
  ],
  "firstOrder": {
    "id": "gid://shopify/Order/444",
    "createdAt": "2025-01-15T10:30:00Z"
  }
}

👤 Customer Metafields

appstle_subscription / subscriptions

PropertyValue
Typejson
ResourceCustomer
PurposeAll subscription contracts for this customer with full details
Set byAbstractSubscriptionService.setCustomerMetaFields() (subscription-async)
Updated whenAny subscription contract changes (created, updated, paused, cancelled, billing attempt)
Update mechanismQueued via SQS (subscription-update-customer-metafields.fifo), processed asynchronously by subscription-async
[
  {
    "id": "gid://shopify/SubscriptionContract/9876543210",
    "status": "ACTIVE",
    "sellingPlanNames": ["Monthly Subscription - 10% off"],
    "nextBillingDate": "2025-04-15T10:30:00Z",
    "lineItems": [
      {
        "title": "Premium Coffee Beans",
        "variantId": "gid://shopify/ProductVariant/222",
        "sku": "COFFEE-PREMIUM-1KG"
      }
    ]
  }
]

Important: Customer metafield updates are asynchronous. The main app queues the update via SQS, and subscription-async processes it. There may be a delay of a few seconds between a contract change and the metafield reflecting that change.


🏷️ Tags Overview

Appstle Subscriptions applies tags to Orders and Customers. All tags are merchant-configurable through the Appstle admin under Settings.

Tags are applied using the Shopify GraphQL Admin API (TagsAddMutation / TagsRemoveMutation).


📦 Order Tags

Order tags are static strings (no Liquid template support) that identify whether an order is the initial subscription order or a recurring billing order.

First-Time Order Tag

PropertyValue
Config fieldfirstTimeOrderTag
Default valueappstle_subscription_first_order
Applied whenInitial subscription order is created
Applied bySubscriptionCreateService and AbstractSubscriptionService.updateShopifyOrderDetails() (subscription-async)
RemovedNever (order tags are permanent)

Recurring Order Tag

PropertyValue
Config fieldrecurringOrderTag
Default valueappstle_subscription_recurring_order
Applied whenEach subsequent billing attempt creates an order
Applied bySubscriptionBillingAttemptService and AbstractSubscriptionService.updateShopifyOrderDetails() (subscription-async)
RemovedNever (order tags are permanent)

Configuring Order Tags

  1. Go to Appstle AdminSettings
  2. Find the Order Tags section
  3. Enter your desired tag values (or keep the defaults)
  4. Save settings

Backfill endpoint: If you need to apply tags to orders that were created before tags were configured, use the MiscellaneousResource.applyMissedOrderTags() API endpoint to backfill missed tags.


👤 Customer Tags

Customer tags are dynamic — they change as subscription status changes. They support Liquid template syntax with access to subscription data variables, enabling highly customized tags.

Tag Lifecycle & Mutual Exclusivity

Customer tags follow a strict priority hierarchy — only one status tag is active at a time:

ACTIVE > PAUSED > INACTIVE
StatusConditionConfig FieldDefault Value
ActiveCustomer has 1+ ACTIVE subscription contractscustomerActiveSubscriptionTagappstle_subscription_active_customer
PausedCustomer has PAUSED contracts but no active onescustomerPausedSubscriptionTagappstle_subscription_paused_customer
InactiveCustomer has no active or paused contracts (all cancelled)customerInActiveSubscriptionTagappstle_subscription_inactive_customer

When status changes:

  1. The previous status tag is removed (TagsRemoveMutation)
  2. The new status tag is added (TagsAddMutation)
  3. The applied tag is tracked in the database (SubscriptionContractDetails.customerTag column)

When Customer Tags Are Applied

EventAction
Subscription contract createdActive tag applied
Subscription pausedActive tag removed → Paused tag applied (if no other active contracts)
Subscription resumedPaused tag removed → Active tag applied
Subscription cancelledTag recalculated based on remaining contracts
Billing attempt succeeds/failsTag recalculated
Subscription event processedTag recalculated

Processing locations:

  • subscription app: SubscriptionContractDetailsServiceImpl.updateCustomerTags()
  • subscription-async: AbstractSubscriptionService.updateCustomerTags() — triggered from contract creation, status changes, and subscription events
  • Deferred updates: Via AWS Step Functions state machine for batched/delayed processing

Liquid Template Variables

Customer tags support Liquid template syntax, allowing you to create dynamic, data-driven tags. Wrap variables in double curly braces: {{variable}}.

Available Variables

VariableTypeDescriptionExample Value
{{customer.id}}StringShopify customer GIDgid://shopify/Customer/1234567890
{{contract.id}}StringSubscription contract GIDgid://shopify/SubscriptionContract/9876
{{contract.sellingPlanIds}}StringComma-separated selling plan IDsgid://shopify/SellingPlan/111
{{contract.sellingPlanNames}}StringComma-separated selling plan namesMonthly Subscription - 10% off
{{contract.variantIds}}StringComma-separated variant IDsgid://shopify/ProductVariant/222
{{contract.variantNames}}StringComma-separated variant namesDefault Title
{{contract.currentCycle}}NumberCurrent billing cycle number3
{{contract.cancellationReason}}StringCancellation reason (if cancelled)Too expensive
{{order.id}}StringFirst order GIDgid://shopify/Order/444
{{order.createdAt}}StringFirst order creation date (ISO 8601)2025-01-15T10:30:00Z

Line item variables (available within the contract context):

VariableTypeDescription
sellingPlanIdStringSelling plan ID for this line item
variantIdStringVariant ID
variantTitleStringVariant title
titleStringProduct title
productIdStringProduct ID
skuStringSKU
sellingPlanNameStringSelling plan name

Example Liquid Templates

Static tag (default behavior):

appstle_subscription_active_customer

Dynamic tag with selling plan name:

active_subscriber_{{contract.sellingPlanNames}}

Result: active_subscriber_Monthly Subscription - 10% off

Dynamic tag with cycle count:

subscriber_cycle_{{contract.currentCycle}}

Result: subscriber_cycle_3

Dynamic tag with product SKU:

subscribed_to_{{contract.variantNames}}

Result: subscribed_to_Default Title

Configuring Customer Tags

  1. Go to Appstle AdminSettings
  2. Find the Customer Tags section
  3. Enter your desired tag templates for each status (Active, Paused, Inactive)
  4. Use Liquid variables for dynamic tags, or plain text for static tags
  5. Save settings

🔗 Subscription Contract Custom Attributes

In addition to metafields and tags, Appstle supports Shopify's native customAttributes on subscription contracts. These are key-value pairs that can be transferred from the original order.

Transfer Settings

These settings control whether data from the original order is copied to the subscription contract:

SettingDefaultDescription
transferOrderNotesToSubscriptiontrueTransfer order notes (text memo) to the subscription contract
transferOrderNoteAttributesToSubscriptiontrueTransfer order note attributes (key-value pairs) to the subscription contract
transferOrderLineItemAttributesToSubscriptiontrueTransfer line item attributes to the subscription contract

Configure these in Appstle AdminSettings.


📊 Summary Tables

All Metafields at a Glance

ResourceNamespaceKeyTypeVisibility
Shopappstle_subscriptionsettingjsonPublic
Shopappstle_subscriptionwidget_template_htmlmulti_line_text_fieldPublic
Shopappstle_subscriptionall_widget_template_htmljsonPublic
Shopappstle_subscriptionbundlejsonPublic
Shopappstle_subscriptionlabelsmulti_line_text_fieldPublic
Shopappstle_subscriptionselling_plansjsonPublic
Shopappstle_subscriptioncheckout_validationjsonPublic
Shopappstle_subscriptionbab_subscription_cssjsonPublic
Shopappstle_subscriptionbab_customization_cssjsonPublic
Shopappstle_subscriptionshop_infojsonPublic
Shopappstle_subscriptionbab_validation_infojsonPublic
Shopappstle_subscriptionbab_setting_infojsonPublic
Shopappstle_subscriptionall_Selling_PlansjsonPublic
Shopappstle_subscriptionbab_info_[0-N]jsonPublic
Shopappstle_subscriptiontotal_babintegerPublic
Selling Planappstle_subscriptionselling_planjsonPublic
Orderappstle_subscriptiondetailsjsonPublic
Customerappstle_subscriptionsubscriptionsjsonPublic

All Tags at a Glance

ResourceTagDefault ValueLiquid SupportPermanent?
OrderFirst-time order tagappstle_subscription_first_orderNoYes
OrderRecurring order tagappstle_subscription_recurring_orderNoYes
CustomerActive subscription tagappstle_subscription_active_customerYesNo (swapped on status change)
CustomerPaused subscription tagappstle_subscription_paused_customerYesNo (swapped on status change)
CustomerInactive subscription tagappstle_subscription_inactive_customerYesNo (swapped on status change)

GraphQL Mutations Used

MutationPurpose
MetafieldsSetMutationCreate or update metafields on any resource
TagsAddMutationAdd tags to orders or customers
TagsRemoveMutationRemove tags from customers

❓ FAQ

Can I read subscription metafields from my Liquid theme?

Yes. All subscription metafields use the appstle_subscription namespace (no $app: prefix), so they are accessible in Liquid templates via {{ shop.metafields.appstle_subscription.setting }}, {{ customer.metafields.appstle_subscription.subscriptions }}, etc.

How quickly are customer metafields updated after a contract change?

Customer metafield updates are queued via SQS (subscription-update-customer-metafields.fifo) and processed asynchronously. Typical latency is a few seconds, but during high-traffic periods it may take longer.

Can I use the same tag template for Active and Paused?

Technically yes, but this defeats the purpose of mutual exclusivity. The system removes one and adds the other — if they're identical, the tag will be briefly removed and re-added, which could cause issues with automations that react to tag changes.

What happens to customer tags when a customer has multiple subscriptions?

Tags follow a priority hierarchy: Active > Paused > Inactive. If a customer has both active and paused subscriptions, the active tag takes precedence. The inactive tag is only applied when ALL contracts are cancelled.

Can I backfill order tags for existing orders?

Yes. Use the applyMissedOrderTags API endpoint to backfill tags on orders that were created before your tag configuration was set up.