---
title: "Upgrade guide — v21 to v22 — E-commerce"
source: https://support.storeconnect.com/articles/upgrade-guide-v21-to-v22-ecommerce
type: article
format: markdown
site: StoreConnect Support — product and developer documentation for StoreConnect
site_index: https://storeconnect.com/llms.txt
docs_index: https://support.storeconnect.com/llms.txt
note: Append .md to any page or article URL on this site to get its Markdown form.
---
# Upgrade guide — v21 to v22 — E-commerce

This section applies to all stores. Make sure you review every subsection.

The guide assumes you are on the latest v21 website release. Changes that already shipped in v21 patch releases are not repeated here.

Each heading starts with a label. **Action required** means you must do something, or the heading tells you in its first sentence who must. **Review** means check whether the change affects your implementation. If a subsection only applies when you use a feature or have customized a template, it says so in the first sentence, so you can skip it when it does not apply to you.

## Before you upgrade

Use this list to find the subsections that need your attention:

- You have Flows, reports, Liquid templates, or integrations that reference `Balloon_Price__c` or `Setup_Price__c` on **Price Book Entry**: see [Removed fields on Price Book Entry](#action-required-removed-fields-on-price-book-entry).
- You have a custom theme: see every subsection under [Liquid template changes](#liquid-template-changes), in particular the tag option change and the list of base-theme templates that changed.
- You publish content changes, or you use the Website Builder with a single administrator who both edits and publishes: see [Agent access, API scopes, and content change approvals](#review-agent-access-api-scopes-and-content-change-approvals).
- You edit content blocks in the Website Builder or with an AI agent: see [Add the new picklist values after the package upgrade](#action-required-add-the-new-picklist-values-after-the-package-upgrade).
- You use Avalara for tax on the web store: see [Avalara taxes each item at its delivery destination](#review-avalara-taxes-each-item-at-its-delivery-destination).
- You have product bundles nested more than one level deep: see [Nested bundles are limited to one level](#review-nested-bundles-are-limited-to-one-level).
- You monitor the sync error list, or have automation that reacts to failed change events: see [Sync behavior changes](#sync-behavior-changes).
- Every store: see [Add the new picklist values after the package upgrade](#action-required-add-the-new-picklist-values-after-the-package-upgrade).
- You have Flows or Apex on **Product** and use Color, Material, Size, or Pattern traits: see [Product fields for search engine rich results](#review-product-fields-for-search-engine-rich-results).
- You use Advanced promotions (Promotions v2) on the web store: see [Choose the promotions engine for each store](#action-required-choose-the-promotions-engine-for-each-store).
- You use Advanced promotions with products excluded from price reductions, or rewards set to exclude discounted items: see [Promotions respect price reduction exclusions](#review-promotions-respect-price-reduction-exclusions).
- You use Custom Data Mappings on carts and orders: see [Custom fields are copied from the cart to the order](#review-custom-fields-are-copied-from-the-cart-to-the-order).
- You grant Console access through cloned or custom permission sets: see [Record search in the Console header](#action-required-record-search-in-the-console-header).
- You use Pay by Account: see [Pay by Account requires the contact's flag to be set](#review-pay-by-account-requires-the-contacts-flag-to-be-set).
- Your theme overrides the store locator templates: see the template table under [Changed base-theme templates](#action-required-changed-base-theme-templates), because the base change removes your Google Maps API key from a public link.

## Salesforce package changes

### Action required: Removed fields on Price Book Entry

Two fields have been removed from the `PricebookEntry` object and from the StoreConnect Administrator, Order Manager, and Sync permission sets. Neither field was used by a released subscription feature, but anything that still references them breaks after the upgrade.

| Object | Removed field | Label | Replacement |
|---|---|---|---|
| `PricebookEntry` | `Balloon_Price__c` | Subscription Balloon Price | None. The field was not read by StoreConnect |
| `PricebookEntry` | `Setup_Price__c` | Subscription Setup Price | None. The field was not read by StoreConnect |

The fields with the same names on `Subscription__c` are not affected.

Before removing any reference, confirm the field is not used for a purpose outside StoreConnect, for example a custom Flow, report, or integration your org relies on independently. If it is, decide where that data should live before the field is deleted.

1. Search your Flows, Process Builder processes, validation rules, and Apex for references to `s_c__Balloon_Price__c` and `s_c__Setup_Price__c` on **Price Book Entry**, and remove or migrate them.
2. Search your reports, dashboards, and list views for either field and remove it.
3. Remove the fields from any **Price Book Entry** page layouts and custom permission sets.
4. After the package upgrade, delete the fields from your org by deploying the cleanup zip in [How to delete deprecated metadata](how-to-delete-deprecated-metadata). The fields stay in your org until you do.

### Action required: Add the new picklist values after the package upgrade

A package upgrade does not add new picklist values to fields that already exist in your org. Three fields gained values during this release and StoreConnect writes some of them, so a missing value causes a sync error.

| Object | Field | New values | Why it matters |
|---|---|---|---|
| `Shipment__c` | `State__c` (Status) | `preparing`, `on_loan`, `returned`, `cancelled` | The POS writes `preparing` for takeaway orders at a fulfillment station and `on_loan` and `returned` for rental fulfillments. A missing value rejects the sync |
| `Content_Block__c` | `Template__c` (Content Template) | `featured_category_products`, `video`, `custom` | Needed to select those block templates, including custom block templates |
| `Authentication_Provider__c` | `Provider__c` | `login_gov`, `keycloak_openid`, `openid`, `saml`, `singlekey_id` | Needed to configure those single sign-on providers |

The `custom` value matters most if your org added its own values to the **Content Template** picklist for theme block templates, such as `event_card` for a `blocks/event_card` template. When you edit one of those blocks in the Website Builder, StoreConnect saves its template as `custom` and moves your key into **Custom Template** (`Custom_Template__c`), even if you did not change the template. The block still renders the same theme template. If the picklist has no `custom` value, publishing that change fails with `bad value for restricted picklist field: custom`.

1. After the package upgrade, open the **StoreConnect Console**, select **Setup**, then **Manage picklist values**.
2. For each object and field listed, select **Apply new values**.
3. Repeat until the Console reports that every picklist is up to date.

The full procedure is in [Managing StoreConnect upgrades](managing-storeconnect-upgrades).

### Action required: Record search in the Console header

The StoreConnect Console header gains a record search across 76 StoreConnect objects, including theme templates, locales, variables, and assets, which Salesforce global search cannot find because they have no tab. It runs on a new Apex class, `ConsoleSearchController`. The upgrade grants that class to the packaged permission sets that carry the Console tab, but not to any permission set you cloned or built yourself.

1. If every Console user holds a standard StoreConnect permission set, no action is needed.
2. If you grant Console access through a cloned or custom permission set, open it in **Setup > Permission Sets**, go to **Apex Class Access**, and add `ConsoleSearchController`. Without it the search shows an error for those users.

Twelve objects that the search covers are also now searchable in Salesforce global search.

### Review: Address book object

`Address__c` is a new object that stores a customer's saved addresses for reuse at checkout. Each record belongs to a **Contact** and carries the **Account**, and a contact can flag one address as the default shipping address and one as the default billing address. Permissions for the object are included in the StoreConnect Administrator, Order Manager, and Sync permission sets, and the package adds an **Addresses** tab and an **Addresses** related list on **Account** and **Contact**.

The existing billing and shipping address fields on **Account** are unchanged. They are still used when a contact has no saved addresses, and they remain the source for reports and integrations. The address book is available on the web store only.

1. If you use only the standard StoreConnect permission sets, no action is needed.
2. If you have custom permission sets, navigate to **Setup > Permission Sets**, open each custom set, and assess whether access to `Address__c` is appropriate for that set's audience.
3. If you have validation rules or automation on **Account** or **Contact** address fields, decide whether saved addresses should follow the same rules.

See [Address Object Reference](address-object-reference) for full field documentation.

### Review: Audit log

`Audit_Log__c` is a new append-only object that records security-relevant activity, with its own tab, three list views (recent security events, failed logins, failed payments), and **Audit Logs** related lists on **Account**, **Contact**, **Store**, **Order**, **Cart**, **Payment**, **Register**, and **Outlet**. A companion custom metadata type, `StoreConnect_Audit_Event__mdt`, defines the twenty-one event types and the retention period for each.

Three new fields on `Store__c` control recording per store: **Audit Log Level** (`OFF`, `ESSENTIAL`, `STANDARD`, `VERBOSE`), **Audit Log Categories** (blank records every category), and **Audit Log Retention (Days)**, which can extend retention but never shorten it. The org-wide default level is `STANDARD`.

After the package upgrade, Salesforce records three event types straight away: a contact's email address changing, an invitation being sent, and a password reset being requested. After the website upgrade, the web store and POS record the rest: sign in and sign out, failed logins, signup, password changes and resets, payment attempts, successes and failures, POS register logins, shift start and end, and fraud screening decisions. Sign out is recorded at `INFO` severity, so it is only captured at `VERBOSE`. A scheduled job purges records once their retention has elapsed.

Read access is granted through the new **StoreConnect Audit Viewer** permission set. The StoreConnect Administrator permission set does not include it.

1. Decide the level for each store. Set **Audit Log Level** on the **Store** record to `OFF` or `ESSENTIAL` if you do not want the default volume of records.
2. Assign the **StoreConnect Audit Viewer** permission set to anyone who needs to see audit records, including StoreConnect Console users.
3. If you use the StoreConnect Sync permission set as a template for a custom integration user, note that the sync user can create audit records but cannot edit or delete them.

See [Audit Log Object Reference](audit-log-object-reference) and [StoreConnect Audit Event Object Reference](storeconnect-audit-event--mdt-object-reference) for field details.

### Review: Agent access, API scopes, and content change approvals

The package adds the Salesforce side of AI agent access and a review step for staged content changes. Three fields on the standard **User** object hold a person's agent token: `API_Token__c`, `API_Token_Active__c`, and `API_Token_Expires_At__c`. You do not need to add them to a page layout, because the StoreConnect Console manages them. A new `API_Scopes__c` field on `Store_Role__c` sets what a person holding that role can do through the API.

On upgrade, any existing editor-level content changes **Store User Role** with no scopes set receives a default bundle: content, catalog, and themes read and write, publish staged changes, store read, and site extraction read. Roles that already have scopes, and approver-level roles, are left as they are.

Publishing a content change now needs an approver-level **Store User Role**, and by default the approver cannot be the change's author. The **Publish Own Changes** scope lifts that restriction for a role. It is granted to no role on upgrade. The new **StoreConnect Content Change Approver** permission set gives a reviewer edit access to `Content_Change__c`, including its **Status**, and read-only access to the records a change stages.

Two new fields on `Content_Change__c` support review: `Preview_URL__c`, which opens the staged edits on the storefront, and `Origin_Store_Id__c`, which records the store the change was authored against. On `Content_Block__c`, the **Content Template** picklist gains `featured_category_products`, `video`, and `custom`, and a new `Custom_Template__c` field names the theme snippet to render when the template is `custom`. Check that those values reached your org: see [Add the new picklist values after the package upgrade](#action-required-add-the-new-picklist-values-after-the-package-upgrade).

1. If you do not use content changes or AI agents, no action is needed.
2. If one person both stages and publishes content changes, add the **Publish Own Changes** scope to their **Store User Role**, or their changes cannot be published until a second person approves them.
3. Assign the **StoreConnect Content Change Approver** permission set to anyone who reviews changes, in addition to their approver-level **Store User Role**.
4. Review the default scopes applied to your existing editor-level roles and narrow them if needed.

See [Manage agent access](manage-agent-access), [Configure agent permissions](configure-agent-permissions), and [Review and approve a content change](review-and-approve-a-content-change).

### Review: Feed objects

Three new objects define customizable feed endpoints: `Query__c` selects the records, `Feed__c` defines the formats and template, and `Store_Feed__c` mounts a feed on a store path or pushes it to a destination. Permissions are included in the StoreConnect Administrator and Sync permission sets. The existing `Data_Feed__c` object is unchanged and continues to work.

No action is needed unless you want to publish a feed. See [Feed Object Reference](feed-object-reference) and [Store Feed Object Reference](store-feed-object-reference).

### Review: New fields on Order

| New field | Purpose |
|---|---|
| `Memo__c` | A short free-text note, up to 80 characters |
| `Outlet_Id__c` | Lookup to the outlet that created the order |
| `Checkout_Deposit_Amount__c` | The deposit a customer chose to pay at web checkout when checkout deposits are enabled |
| `Risk_Review__c` | `Pending Review`, `Released`, or `Rejected`. Set by fraud screening when a risk provider is configured. A **Fraud Review Queue** list view shows orders at `Pending Review` |
| `Cancellation_Reason__c`, `Cancelled_At__c`, `Cancelled_By_User_Id__c` | Who canceled the order, when, and why |

Review whether any of these fields should be added to your **Order** page layouts. The package adds a **Cancellation** section to the StoreConnect order record page.

`Total_Tax_Amount__c` on **Order** and `Tax_Amount__c` on **Order Product** now store four decimal places so that order totals do not drift on low-value, high-quantity orders. If you have reports or integrations that compare these fields to whole cents, review them.

### Review: New fields on Order Product

| New field | Purpose |
|---|---|
| `Cancellation_Reason__c`, `Cancelled_At__c`, `Cancelled_By_User_Id__c` | Who canceled the line, when, and why |
| `Notes__c` | Free-text notes entered against the line, up to 10,000 characters |
| `External_Tax_Detail__c` | Per-jurisdiction tax breakdown from an external tax provider such as Avalara, stored as JSON |
| `Total_Points_Amount__c` | Points used to buy the whole line, so an uneven split across the quantity stays exact |
| `Unit_Discount_Points__c` | Per-unit points discount |
| `Unit_Manual_Discount__c` | The per-unit discount an operator applied by hand, recorded separately from catalog markdowns and promotions |
| `Bundle_Lead_Item_Id__c` | Lookup to the lead item of the bundle this line belongs to. Backfilled from Salesforce CPQ bundle data on upgrade |

These fields are populated by StoreConnect. Review whether any should be added to your **Order Product** page layouts or reports.

### Review: New fields on Cart and Cart Item

`Cart__c` gains `Checkout_Deposit_Amount__c`. `Cart_Item__c` gains `Notes__c` and `Unit_Discount_Points__c`. These mirror the Order and Order Product fields above and are populated automatically.

### Review: Delivery date, shipping notes, and print tracking on Shipment and Cart Fulfillment

`Requested_Delivery_Date__c` and `Shipping_Notes__c` are new on both `Cart_Fulfillment__c` and `Shipment__c`. They are captured by the POS arrange-delivery flow and copied to the shipment when the order completes. `Shipment__c` also gains `Fulfillment_Station_Id__c`, `Auto_Printed_At__c`, `First_Printed_At__c`, `First_Printed_Register_Id__c`, `Last_Printed_At__c`, and `Last_Printed_Register_Id__c` for fulfillment docket printing at the POS.

Review whether the delivery date and notes should appear on your **Shipment** page layouts or in warehouse reports.

### Review: Pricing rules on Shipping Carrier Product

Five new fields on `Shipping_Carrier_Product__c` adjust carrier-quoted rates before they are shown to customers: `Fixed_Price__c`, `Markup_Percentage__c`, `Markup_Amount__c`, `Min_Price__c`, and `Max_Price__c`. Two validation rules reject negative values and a maximum below the minimum. Existing records have no rules set and are unchanged.

See [Shipping Carrier Product Object Reference](shipping-carrier-product-object-reference).

### Review: Product fields for search engine rich results

**Product** gains fields that the storefront publishes as structured data for search engine rich results: **Rating Value**, **Review Count**, and **Best Rating**; **Shipping Charges** (`Free` or `Billed`) and **Shipping Cost**; **Warranty Duration** and **Warranty Unit**; **Return Policy Category**, **Return Window Days**, **Return Policy Country**, and **Restocking Fee**; and **Color**, **Material**, **Size**, and **Pattern**. **Store** gains **Default Return Policy Category**, **Default Return Window Days**, and **Default Return Policy Country**, which a product uses unless it sets its own. A validation rule on both objects requires **Return Policy Country** to be a two-letter upper-case country code. The fields are available to the StoreConnect Administrator, Sync, Order Manager, and Content Change Approver permission sets and appear on the StoreConnect **Product** and **Store** Lightning record pages.

The four attribute fields fill themselves from traits. If a product has a trait whose **Trait Type** is named Color (in either the US or British spelling), Material, Size, or Pattern, the trait value is copied into the matching field whenever the trait is added or changed, and removing the trait clears it. A variant with no trait of its own takes the value from its master product.

**The upgrade runs a background job that writes every product and variant with a matching trait once.** Your own automation on **Product**, including record-triggered Flows and Apex triggers, runs for each of those updates.

1. If you have automation on **Product** that sends notifications, calls external systems, or counts updates, review it before the package upgrade and decide whether it should ignore the backfill.
2. If your org uses its own product or store record pages or classic page layouts, add the fields you want to use.
3. Review whether any product should publish a rating, warranty, or return policy. Nothing is published until the fields are set.

### Review: Excluded Channels on Product

`Excluded_Channels__c` (label: Excluded Channels) is a new multi-select picklist on **Product** with the values `web` and `pos`. Blank, the default, means the product is sold everywhere, so existing products are unchanged. A listed channel hides the product from that channel: from storefront browsing, search, category pages, the sitemap, product pages, related products, and the Google Merchant feed for `web`, and from the products synced to POS devices for `pos`. A product already in a cart or order stays visible there. The REST products API returns every product unless it is called with a `channel` parameter.

Review whether any products should be hidden from a channel. If you maintained separate catalogs or inactive products to achieve this, assess whether this field can replace them.

### Review: Canonical Path Override on Product and Product Category

`Canonical_Path_Override__c` (label: Canonical Path Override) is a new text field on **Product** and **Product Category**. When set, the storefront uses it as the page's canonical URL instead of the page's own URL. It is meant for a migration window where old URLs are served in place by Route Mappings and the canonical should stay the URL search engines already index. A validation rule accepts only a store-relative path starting with `/`, with no domain, spaces, query string, or anchor. The field is available to the permission sets that carry **Meta Title**: StoreConnect Administrator, Sync, Order Manager, and Content Change Approver.

Blank, the default, changes nothing. See [Route mapping](route-mapping).

### Review: Cart Item lookup on Order Product

`Cart_Item_Id__c` (label: Cart Item) is a new lookup on **Order Product** to the `Cart_Item__c` the line was created from. It is populated for orders placed after the upgrade and is blank on existing orders. No action is needed unless you want to report on it.

### Review: Alternative Verification Methods on Form

`Alternative_Verification_Methods__c` is a new multi-select picklist on `Form__c` with one value, **Same-site origin (cached pages)**. It only matters if you turn on cacheable pages (see [Cacheable pages served by your CDN](#review-cacheable-pages-served-by-your-cdn)): a custom form submitted from a cached page carries no security token and is rejected unless the form selects this method. Changes to the field are recorded in the form's field history. The upgrade does not add the field to your **Form** page layout, so add it if you adopt cacheable pages.

### Review: Other new fields

| Object | New field | Purpose |
|---|---|---|
| `Store__c` | `Favicon_Id__c` | A media record of image type shown in the browser tab. See [Add a favicon to your website](add-a-favicon-to-your-website) |
| `Contact` | `Confirmed_At__c` (Account Confirmed At) | When the customer confirmed their account. Blank means it has not been confirmed through the store |

### Review: Nested bundles are limited to one level

A bundle may contain a sub-bundle, but that sub-bundle's components cannot themselves be bundles. The package now blocks a three-level chain when you save a product component, in either direction. Records that already violate the rule are left in place and are not affected until you edit them.

If you rely on deeper nesting, restructure those bundles into a single level before you edit them. See [Product bundles](product-bundles).

### Review: Redesigned package email templates

All eighteen email templates in the `storeConnect_Templates` folder have been rebuilt on a shared design: a teal header band with the store logo, a 600 pixel centered card, and a footer carrying the store name and domain. Several field references in the old templates were also corrected.

The package upgrade does not replace the email templates already in your org, so your customers keep receiving your current emails and nothing changes. New installs receive the new design. If you want the redesigned templates in an existing org, contact StoreConnect support and ask for them.

### Review: Media upload file types

The media upload picker no longer accepts `.raw` or `.jpgxr` images. It now accepts `.bmp`, `.ico`, `.jp2`, and `.tif`, common audio formats under the video type, and any non-executable file under the **File** type. Media already stored in a removed format is unaffected. See [Uploading media](uploading-media).

### Review: Person Account conversion

Orgs that use Person Accounts can have StoreConnect convert a new store customer's business **Account** and **Contact** pair into a Person Account automatically. The feature is off until the `Person_Account_Conversion_Record_Type` custom metadata setting names a Person Account record type. Existing customers are not converted in bulk: an eligible existing business pair converts only when the store later sends an update that includes the link between the **Contact** and the **Account**. If the org already converts customers with its own Flow or trigger, deactivate it before you set the record type, or signup confirmations fail with `INVALID_PERSON_ACCOUNT_OPERATION`. See [Using Person Accounts with StoreConnect](person-accounts).

### Review: Console trait management

Product traits can now be built and assigned from the StoreConnect Console, and `Trait_Category__c`, `Trait_Type__c`, and `Trait_Value__c` gain dedicated record pages. Existing trait data is unchanged. See [Work with the trait builder](trait-builder).

### Review: Deprecated CustomSetting component and hardened custom settings access

The `CustomSetting` Aura component is deprecated and will be removed in a future version. Access to StoreConnect custom settings from Lightning components has also been tightened: the controller now exposes a single method that returns only an allow-listed set of non-sensitive values rather than the full settings record. This only affects developers who built custom Lightning components on either. Plan to migrate them.

### Review: Custom data mappings reject colliding field names

A custom data mapping whose target field name collides with an existing field on the object is now rejected at save time. Existing mappings are not changed. If a mapping save fails after the upgrade, rename the target field.

### Review: Store connection setup uses OAuth

Connecting a store to Salesforce from the StoreConnect Console now opens a browser tab to authorize through Salesforce instead of asking for a username, password, and verification code. The setup page guides you through authorizing as a different sync user and offers a copyable authorization link if the tab was closed. This only matters when you connect a new store or reconnect an existing one.

### Review: Rebuilt New Theme Asset form

The **New Theme Asset** form is rebuilt on the current Lightning interface with drag-and-drop upload. The file now uploads when you save rather than when you pick it, so an abandoned form no longer leaves stranded files in cloud storage. Opening the form from a theme's related list pre-fills and locks the **Theme**. Files over 5 GB are rejected.

### Review: Salesforce release compatibility

The package includes fixes for Salesforce Summer '26 and Winter '27, covering Lightning Web Security restrictions, Lightning base component sizing changes, API version 67 and later Apex default-value behavior, and Console styling. If you pinned an earlier package version to avoid a Salesforce release regression, the fix is in this upgrade.

### Review: Other package fixes included in the v21 patch releases

These fixes ship with the package upgrade and need no action. They are listed so you can retire any workaround you put in place:

- Sync update events now always carry a `SystemModstamp`, including REST PATCH, Bulk API, Flow, and same-second saves, so downstream consumers can order changes.
- Order line items missing a **Price Book Entry** at sync time resolve it from the parent order's price book instead of failing.
- Polls skip object names that are not installed in the org, which removes the "Failed to process batch: Attempt to de-reference a null object" alerts when a new store connects.
- The sync summary batch no longer aborts on an unresolvable object name, and duplicate entries in a sync payload no longer roll back the whole change-event batch.
- Cascading deletes of more than ten record types no longer fail with "Cannot have more than 10 chunks in a single operation".
- A new customer whose account converts to a Person Account can now confirm their signup.
- A staged boolean content change accepts `t` and `f` values.
- The Media Manager folder rename no longer crashes in Chrome, the Salesforce payment component loads on the order action, the setup wizard links resolve, and **Open Storefront** in the Console header includes the store's path prefix.
- Saving an **Outlet User** now also sends the linked Salesforce **User** to the store, so a staff member whose user never synced can sign in to POS. If a staff member still cannot sign in after upgrading, open their **Outlet User** record and save it.
- Flows that update StoreConnect-managed records no longer fail with "Invalid field sC_Id__c".
- Deleting a **Web Domain** record in a refreshed sandbox no longer removes the domain from production. **Get sandbox** now deletes the Web Domain records copied from production, so recreate the sandbox store's custom domain after setup. See [Refresh a StoreConnect sandbox](refresh-a-storeconnect-sandbox).
- Content change filters and search work on Salesforce Winter '27.

## Sync behavior changes

### Review: Failed change events retry automatically, and some errors are hidden or made permanent

Three changes affect anyone who watches the sync error list or has automation keyed on failed change events:

- **Automatic retry.** A scheduled job retries recent failed change events, so transient failures clear without manual intervention.
- **Transient errors are hidden.** Failures caused by a parent record that has not arrived yet (foreign key not found) are retried in the background and no longer appear in the sync error list or its counts.
- **Duplicate-rule errors are permanent.** A change event blocked by a Salesforce duplicate rule is marked permanent and left out of automatic retry, because a retry cannot succeed while the rule still matches. StoreConnect can instead attach the incoming record to the matching **Account** or **Contact**. This is off by default, and StoreConnect support turns it on for your org on request.

Sync is also faster: a full repoll of a large object takes around a third less time, and processed change events are archived by background jobs instead of a scheduled batch, so archiving starts sooner.

1. If you have monitoring that expected duplicate-rule errors to clear on their own, update it to treat them as needing attention.
2. If you want StoreConnect to attach incoming records to matching accounts and contacts, [log a case](log-a-case) with StoreConnect support. See [Resolve duplicate account sync errors](resolve-duplicate-account-sync-errors).
3. Review any reports built on `Change_Event__c` that counted every failed event, because transient failures are now excluded from the counts shown in the StoreConnect Console.

See [How to find and resolve sync errors](how-to-find-and-resolve-sync-errors).

### Review: Per-store duplicate resolution

Whether StoreConnect resolves duplicate accounts, contacts, and leads can now be overridden for a single store with the `duplicates.account.resolution`, `duplicates.contact.resolution`, and `duplicates.lead.resolution` store variables, each set to `enabled` or `disabled`. Unset, the store follows the org-wide setting. No action is needed unless one store needs different handling.

### Review: Account deletes verify child records with Salesforce

When an **Account** is deleted or merged in Salesforce, the store no longer deletes its synced contacts outright. It asks Salesforce for each child record first, so contacts re-parented by a merge survive and only records Salesforce confirms as deleted are removed. No action is needed.

## Liquid template changes

### Action required: Tag option values that come from a variable are no longer rendered as Liquid

This applies to every theme. The standard theme already complies, so you only need to change templates you wrote or customized.

A tag option is a `key: value` pair after a tag name, such as `{% render "badge", label: product.summary_content %}`. Previously, a string passed to an option was itself run as a Liquid template, so stored text containing `{{ ... }}` or `{% ... %}` was executed. That meant merchant-entered and customer-entered text was being run as code. Now a value that comes from a variable is read as data and printed as-is, braces included. Markup you write directly inside the tag, such as `label: "Hi {{ current_customer.first_name }}"`, still renders. The same rule applies to `{% update %}`.

Whenever a value containing `{{` or `{%` is printed rather than executed, the Web Console shows an error naming the option and the value, so affected templates are easy to find.

1. Open the Web Console and load your home page, a product page, the cart, and each checkout step. Look for errors that name a tag option.
2. For each one, move the markup into the template. Build the value with `{% capture %}` and pass the captured variable to the tag, or write the markup inside the option string. The examples in [Liquid tags](liquid-tags) show both forms.
3. If a template cannot be fixed before you go live, contact StoreConnect support about the temporary `liquid_interpolate_tag_option_values` setting. It restores the old behavior for your whole tenant, is not recommended, and should be turned off again as soon as the templates are updated, because it lets anyone who can type into a product description or form field run template code on your storefront.

### Action required: Changed base-theme templates

This applies only if your theme overrides any of the templates below. The base theme changed in these places. An override is a complete copy, so it does not pick up the new behavior and in some cases blocks a feature or breaks a payment flow. Compare each override you have against the new base version and merge the change.

| Base template | What changed | If you do not merge |
|---|---|---|
| `layouts/theme` | Renders the store favicon, passes the current controller to the CSP snippet, treats the card capture page like the Salesforce payment page, and emits the URL segment meta tags with `{%- default route_segment_meta_tags: nil -%}` at the top and `{{ route_segment_meta_tags }}` in the head | No favicon. The card capture page used by POS subscription card capture and the embedded save-card form is not rendered with the reduced layout. Custom URL paths have no effect on the storefront's own scripts |
| `snippets/content_security_policy_header` | The default policy now allows `frame-src` for `*.squarecdn.com`, and sets `frame-ancestors 'self'` on the card capture page | Only matters when `content_security_policy_type` is `enforce` and you rely on the default policy. The Square card element is blocked, and the card capture page cannot load inside the POS |
| `snippets/account/menu`, `pages/account` | New **Address book** and **Payment methods** sections | Customers cannot reach the address book or saved payment methods from the account menu |
| `snippets/checkout/customer_information/address`, `billing_address`, `form` | A saved-address selector and a "save this address" checkbox for signed-in customers | Customers cannot pick a saved address at checkout. Orders still complete |
| `snippets/checkout/payment_information/submit_button`, `select_and_payment`, `show_wallets_only`, `additional_info`, and every `payment_providers/*_form` | The submit button reads **Save card** for save-card-only carts, and saved payment methods are offered as a quick-pay option | Save-card-only checkouts show **Pay now**. Saved cards are not offered |
| `snippets/checkout/shipping_information/form` | A per-group delivery selector when multi-shipping is enabled | Multi-shipping cannot be used |
| `snippets/shared/cart_items/item`, `shared/cart_items/pricing`, `shared/order_total`, `orders/order_summary` | Promotion and discount breakdown lines, and applied vouchers rendered from `voucher.label` and `voucher.identifier` | Promotion lines are not itemized. Templates using the removed `order_summary.voucher` translation show a missing translation |
| `snippets/orders/show` | Shows a notice when the order is held for fraud review | Customers whose order is held see no explanation |
| `components/cart-menu` | Passes `skip_paypal_fastlane` to the wallets snippet | The PayPal Fastlane flow is rendered inside the mini-cart dropdown, where it does not fit |
| `components/checkout/vouchers`, new `snippets/checkout/vouchers/*`, removed `payment_providers/vii_form` | Vii gift cards move from a payment method form into the vouchers component, beside StoreConnect vouchers | Vii gift cards cannot be applied, and an override that renders `vii_form` fails |
| `components/checkout/payment_information/page` | Adds the checkout deposit component and renders the payment form for save-card-only carts | Deposit amounts cannot be entered, and a save-card-only cart shows no payment form |
| `snippets/shared/account/address_form` | Takes `type` and `required_attribute` parameters so the address book can reuse it | The address book add and edit forms do not work |
| `helpers/component` | Supports deferred loading (`defer`) with a loading indicator and marks batched components with `data-batch` | The `defer` and `batch` options on components have no effect |
| `pages/additional_payment`, new `snippets/additional_payment/vouchers`, `snippets/shared/order_total`, `snippets/orders/order_summary`, `components/orders/order_summary` | Vouchers and gift cards can be applied on the balance payment page, and the order total nets them off the amount due | Customers cannot apply a voucher when paying a balance |
| `snippets/account/fulfillments/fulfillments` | Adds a delivery method column | Customers do not see the carrier and service for each delivery |
| `snippets/account/subscriptions/payment_new` | Uses the `image_url` filter in place of `img_url` | None today. `img_url` still works |
| `snippets/products/in_your_cart` | Passes `before_promotions: false` so the line states the price it charges | The in-your-cart line shows the pre-promotion price |
| `snippets/products/product/bundle/nested_bundle_card` | Adds a quantity picker for a bundle inside a bundle | Customers cannot choose a sub-bundle quantity |
| `pages/locations`, `snippets/locations/forms/near`, `snippets/locations/result_card` | Removes your Google Maps API key from the public directions link, which now uses `?api=1` | Your Google Maps API key is exposed in a link on every store locator result. Merge this one even if you merge nothing else |

New templates you may want to copy into your theme if you customize these areas: `snippets/account/addresses/*`, `snippets/account/profile/payment_methods*`, `snippets/checkout/payment_information/saved_payment_methods`, `components/checkout/deposit`, `components/checkout/shipping_rates/page`, and `components/account/addresses_list`.

1. In the **Website Builder**, list the templates your theme overrides and compare the list with the table above.
2. For each match, open the base version of the template, copy the changed section into your override, and keep your own customizations.
3. After the upgrade, place a test order through checkout with each of your payment providers, and open the account area as a signed-in customer.

### Review: Removed translation keys

This applies only if your theme or translations reference one of these keys. The keys were removed from the default translations and now render as a missing translation.

| Removed key | Replacement |
|---|---|
| `order_summary.voucher` | Render `voucher.label` from the applied voucher |
| `products.add_to_cart.quantity_label` | None. The key was used by a storefront template that no longer exists |
| `checkout.gateways.vii.*` (eight keys) | None. Vii gift cards are applied through the vouchers component, which has its own translations |

### Action required: `shipping.set` controller action is deprecated

This applies only if you have Liquid controller templates that call `shipping.set`. The action still works and logs a deprecation warning in the Web Console. It will be removed in a future release. Update your controllers using the replacement in the table below.

| Deprecated action | Replacement |
|---|---|
| `shipping.set` | `shipping.update` |

Two further actions complete the programmatic shipping lifecycle: `shipping.add` attaches a shipping method to the cart, and `shipping.remove` removes it. See [Liquid controller actions](liquid-controller-actions).

### Review: Templates that do not parse are rejected when staged

A theme template staged through a content change, including one written by an AI agent, is now rejected if it does not parse, instead of publishing a template that renders blank. Liquid render errors on a live store are also written to the production log, once per template per store, so a blank section can be traced. No action is needed.

### Review: New Liquid capabilities

No changes to existing templates are required. Review these if you maintain custom templates:

- Controller actions `shipping.add`, `shipping.update`, `shipping.remove`, `outlet.set`, and `outlet.clear`. Setting an outlet for a web session applies outlet-level pricing and stock.
- Filters `image_tag` and `image_url` for responsive images. The `deserialize` filter now also reads XML.
- The `{% audit_event %}` tag, and additional content types on `{% api %}`.
- `current_customer.addresses` and `current_customer.preferred_shipping_address` for the address book, and fulfillment drops on orders.
- Components can be deferred so a slow section loads after the rest of the page, marked `dynamic` so they are never frozen into a cached page, and `batch`ed so a theme can fetch several in one call. See [Liquid theme components](theme-components).
- Theme JavaScript that builds a storefront path by hand should call `window.StoreConnect.storePath()` so the path follows the store's custom URL segments.

## Behavior changes

### Review: Guests can only set a password from the session that placed the order

The "set a password" step shown to a guest after checkout now works only in the browser session that completed that checkout. Previously anyone who could open a guest order page could set a password on the customer's contact. A customer who returns later through a link is shown a message and can use the normal registration or password reset instead. The refusal is recorded in the audit log. No configuration is needed.

### Review: Content block link targets accept more URL schemes

A **Link Target** on a content block that starts with `mailto:`, `tel:`, `sms:`, `//`, `#`, or `?` is now passed through as written. Previously only `http` and `https` links were, and anything else was joined onto the store path and returned a 404. Review any content block where you worked around this.

### Review: Custom fields are copied from the cart to the order

At web and API checkout, custom data on the cart is copied onto the order, and custom data on each cart item onto its order item, for every custom field the order or order item is configured to hold as editable through a Custom Data Mapping. The copy runs once, when the order is created. If you built a Flow or integration to carry cart custom fields onto the order, assess whether it is still needed.

### Action required: Choose the promotions engine for each store

This subsection applies if you use Advanced promotions (Promotions v2) on the web store.

In v21, the web store ran both promotion engines together. A promo code was looked up in Advanced promotions first and then in standard promotions, and automatic Advanced promotions applied on every store they were set up for. In v22, each store runs one engine on the web store, chosen by the store variable `promotions.version`:

| Value | What the web store runs |
|-------|-------------------------|
| `v1`, or not set (default) | Standard promotions only. An Advanced promotion code returns "The requested promotion is unavailable", and automatic Advanced promotions do not apply. |
| `v2` | Advanced promotions only. A standard promotion code returns "The requested promotion is unavailable". |

The variable takes a single value, and there is no setting that runs both engines on the web store. Registers run Advanced promotions whatever this variable says.

1. If the store has active standard promotions that you still need, recreate them as Advanced promotions before you switch. See [Configure Promotions v2](configure-advanced-promotions).
2. Open the **Store** record.
3. In the **Store Variables** related list, add a store variable with the key `promotions.version` and the value `v2`. Keep one record with this key per store; with two, the store can read either value.
4. Apply an Advanced promotion code to a test cart on the web store.
5. Repeat these steps for each store that uses Advanced promotions.

The discount now shows in the cart totals, and the code no longer returns "The requested promotion is unavailable". See [Store variables](store-variables).

### Review: Promotions respect price reduction exclusions

These changes affect Advanced promotions:

- A product or price book entry with **Exclude From Price Reductions** set to `promotions` now takes no reward, adds nothing to a subtotal reward's base, and no longer counts toward a promotion's conditions. A subtotal reward's exclude scopes are honored the same way. Previously such lines could still be discounted.
- A reward set to exclude discounted items now also skips a line that is on sale (priced below its list price) or carries a share of a whole-sale discount. Previously the reward stacked on those reductions.
- A promotion's start and end dates, and its weekly frequency, are judged in the promotion's own time zone rather than UTC, so a promotion no longer starts late or reappears after it ends for stores away from UTC.
- An automatic promotion that has ended is removed from an existing cart the next time the cart is repriced. Previously its discount stayed on the cart.
- A percentage shipping promotion is sized on the delivery charge before tax, like every other reward. Previously tax was discounted twice.
- `Promotion2__c` gains `Channels__c` (label: Channels), a multi-select of `web` and `pos`. Blank, the default, applies the promotion everywhere, so existing promotions are unchanged. Set it to keep a promotion online-only or in-store-only; a cart from the headless API counts as web. The field is editable by the StoreConnect Administrator and Sync permission sets and readable by Order Manager.

Review promotions that relied on stacking, and place a test order with an excluded product after upgrading. See [Exclude products from price reductions](exclude-products-from-price-reductions) and [Advanced promotions](advanced-promotions).

### Review: Account Confirmed At is recorded on the Contact

**Account Confirmed At** on the **Contact** records when the customer confirmed their account. Blank means the account has not been confirmed through the store. No action is needed. See [Store security settings](store-security-settings).

### Review: Pay by Account requires the contact's flag to be set

This applies only if you offer Pay by Account. A contact whose **Can Purchase For Account** flag has not synced to the store, for example a contact just created at checkout, was previously allowed to pay by account. Pay by Account now denies unless the flag is `true`, matching the other account-level privileges.

1. Confirm **Can Purchase For Account** is set on every contact who should pay by account.
2. If you create contacts by automation, set the flag at creation so it reaches the store with the contact.

### Review: Carts whose order is complete are no longer resumed

A stale Salesforce refresh could set a completed cart back to open, so a returning customer resumed it and a second checkout overwrote the finished order. Carts whose linked order is past Draft in Salesforce, or finalized by the store, are no longer offered for resumption, and express checkout creates a new cart instead of reusing one whose order is done. No configuration is needed.

### Review: Australia Post goods description on labels

This applies only if you use the Australia Post shipping provider. A short summary of the parcel contents, one line per item, can be printed on the auxiliary label. It is off until enabled in the provider's **API Options**, and applies to domestic shipments only.

### Review: Avalara taxes each item at its delivery destination

This applies only to stores using Avalara on the web store. Tax invoices are now also filed with the provider for orders placed through the cart API, as they already were for storefront checkouts and renewals. Web checkout now sends Avalara a destination address per cart item based on where that item is delivered. A Click and Collect order is taxed at the collection location, including when the customer chose only a stock location rather than a collection point. Previously the whole cart was taxed at the customer's shipping address. Place a test Click and Collect order after upgrading and confirm the tax matches your expectation.

### Review: Features that appear automatically unless you override their templates

These need no configuration, but they are rendered by base-theme templates. They appear for customers only where your theme does not override the templates involved. If it does, merge the base changes listed in [Changed base-theme templates](#action-required-changed-base-theme-templates) first.

- **Address book.** Signed-in customers can save addresses in the account area and pick them at checkout. Rendered by `snippets/account/menu`, `pages/account`, and the `snippets/checkout/customer_information/*` address templates.
- **Saved payment methods.** Customers can save a card in the account area and reuse it at checkout. Rendered by `snippets/account/menu`, `pages/account`, and the `snippets/checkout/payment_information/*` templates. Only Stripe, Stripe ACH, and Square support saving a payment method, so the section is empty on other gateways. See [Payment methods](payment-methods).

### Review: Optional features controlled by store variables

These are off until you set the variable. No action is needed to keep current behavior.

| Store variable | What it enables |
|---|---|
| `checkout.deposit.enabled`, `checkout.deposit.minimum_percentage` | Customers choose a deposit amount at web checkout. See [Accept deposits for purchases](deposits) |
| `registration.address_required` set to `false` | Address fields become optional at account registration |
| `shipping.multi_shipping_enabled` | A cart whose items have incompatible delivery options checks out as several deliveries |
| `subscriptions.guest_renewal_payment_enabled` | A subscription renewal order can be paid in full through the additional payment page without signing in |
| `route.<segment>`, `route.<segment>.former` | Custom URL paths: rename a built-in URL segment such as `cart` or `account` per store, and choose whether the old path keeps serving (`200`), redirects (`301`), or is retired (`404`) |
| `routing.matchable_url_extensions`, `routing.matchable_url_status` | Legacy URL extension matching: treat a trailing extension such as `.html` as optional on content pages and categories, with a `301`, `302`, or in-place `200` response |
| `page_cache.types`, `page_cache.ttl`, `page_cache.stale` | Cacheable pages served by your CDN. See the next subsection |
| `assets.error_cache_seconds` | How long a CDN may keep a not-found answer for a theme asset. Default `180` seconds; found assets are cached for the life of their content hash |
| `catalog.category_paths.hierarchical` | Category links, canonical tags, and the sitemap use the category's full hierarchical path, and flat category URLs redirect to it |
| `shipping.provider_zone_filtering_enabled` | Only shipping providers whose **Zone** matches the delivery address are asked for rates. Providers with no zone serve every destination |

### Review: Cacheable pages served by your CDN

A store can let a CDN such as Cloudflare serve its public pages from a cached copy. Caching is off until `page_cache.types` lists the page types to cache, chosen from `home`, `page`, `article`, `product`, `category`, `search`, and `locations`. Cart, checkout, account pages, logged-in and membership-restricted pages, and any visit that already has a session or saved cart are never cached.

Turning it on changes how forms behave on cached pages: a cacheable page carries no security token, so add-to-cart and the cookie banner are verified by their origin instead, and a custom form is accepted only when its **Form** record selects **Same-site origin (cached pages)**. Components that must differ per visitor, such as the cart badge, use the `dynamic` option. Theme JavaScript that reads the CSRF meta tag fails on a cached page unless the theme calls the optional bootstrap endpoint.

If you adopt cacheable pages, review your custom forms and any theme JavaScript that reads the CSRF token before setting `page_cache.types`.

### Review: Fraud screening

Orders can be screened by a fraud decisioning provider before the gateway is charged. Screening is off until a provider is configured for the store, and starts in monitor mode, which logs decisions without blocking. When a provider is configured and set to enforce, declined orders are held with `Risk_Review__c` set to `Pending Review` and appear in the **Fraud Review Queue** list view on **Order**. Every screening outcome is written to the audit log.

### Review: login.gov single sign-on

login.gov is available as an SSO authentication provider for stores serving US federal government customers. It is configured on an `Authentication_Provider__c` record with the `login_gov` provider value and requires an RS256 private key. No action is needed unless you adopt it.

---

## Follow StoreConnect

- [Email Newsletter](https://storeconnect.com/c/lp-newsletter)
- [LinkedIn Newsletter](https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7444956928444862464)
- [YouTube](https://www.youtube.com/channel/UCngKdP2x8l1wcbAKW3tvU8g)
- [LinkedIn](https://www.linkedin.com/company/storeconnect)
- [X / Twitter](https://x.com/storeconnecthq)

## Popular Links

- [Partners](https://storeconnect.com/partners)
- [Become a Partner](https://storeconnect.com/become-a-partner)
- [News](https://storeconnect.com/articles/news)
- [Events](https://storeconnect.com/articles/events)
- [Feature Comparison](https://storeconnect.com/how-we-compare)
- [Download a free trial](https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000FMkeKUAT)
- [Book a Demo](https://storeconnect.com/contact)

## Documentation

- [Help documentation](https://support.storeconnect.com/help-documentation)
- [AI agents](https://support.storeconnect.com/ai)
- [Videos & tutorials](https://support.storeconnect.com/videos-tutorials)
- [Developer reference](https://support.storeconnect.com/developer-reference)
- [Release notes](https://support.storeconnect.com/release-notes)
- [Troubleshooting](https://support.storeconnect.com/troubleshooting)
- [Trust Center](https://trust.getstoreconnect.com/)
- [Status Page](https://status.storeconnect.com/)

## Contact

- info@getstoreconnect.com
- US +1 415 745 3230
- AUS +61 2 8365 2308

100 S Ashley Dr, Suite 600-2461
Tampa FL 33602-600 USA

Level 22, Sydney Place
180 George Street
Sydney, NSW, 2000, AUS

## Machine-readable

- [Site index for agents](https://storeconnect.com/llms.txt): curated map of the StoreConnect site in llms.txt format
- [Documentation index for agents](https://support.storeconnect.com/llms.txt): full technical and product documentation map

Every page and article on this site has a Markdown rendering: append `.md` to its URL.

Continue in Markdown: [Help documentation](https://support.storeconnect.com/help-documentation.md) · [Developer reference](https://support.storeconnect.com/developer-reference.md) · [Videos & tutorials](https://support.storeconnect.com/videos-tutorials.md) · [Release notes](https://support.storeconnect.com/release-notes.md)

---

StoreConnect Support — https://support.storeconnect.com/articles/upgrade-guide-v21-to-v22-ecommerce