What is Shopify checkout extensibility?
Shopify checkout extensibility is the set of defined customisation points — checkout UI extensions, Shopify Functions, Web Pixels and the Branding API — that replaced direct editing of checkout.liquid. Instead of a merchant or agency owning a copy of the checkout template’s markup, Shopify owns the checkout page itself and exposes specific, bounded places where a store can add content, change branding, or run custom logic.
That’s a structural change, not a cosmetic one. Under checkout.liquid, a store’s checkout page was effectively a forked template: every Shopify checkout update had to be manually reconciled against whatever custom code sat in that store’s copy. Under checkout extensibility, Shopify ships checkout updates centrally, and a store’s customisations live in separate extensions that Shopify runs alongside the standard checkout rather than inside a forked copy of it.
For a team running ops on Shopify Plus, this matters less as a checkout-page detail and more as an operations problem: every custom field, every tracking pixel, and every discount rule that used to live in one file now has to be re-homed in the extension point built for it, and a piece left behind fails silently rather than throwing an error.
What are the four extension points, and what does each one actually do?
Checkout extensibility is built from four distinct pieces, and confusing which one does what is where most migration plans go wrong before they start.
Checkout UI extensions add or modify visible content at a fixed set of target points in the checkout flow — for example purchase.checkout.block.render for a general content block, or purchase.checkout.delivery-address.render-before for content placed just before the delivery address form. Each target name is specific to a location in the checkout flow, and an extension only renders where its declared target matches.
Shopify Functions run server-side logic during checkout — deciding which discounts apply, which payment methods are offered, which shipping rates show, or how cart items are validated. A Function is compiled to WebAssembly and executed on Shopify’s infrastructure, which means it can enforce a rule (like “this discount code only works with this payment method”) in a way a customer’s browser can’t bypass, unlike a client-side script that determined the same thing in checkout.liquid.
Web Pixels are the replacement for inline tracking scripts. Instead of a <script> tag pasted into checkout.liquid, a Web Pixel subscribes to standard checkout events — checkout_started, checkout_completed, payment_info_submitted and others — and fires the corresponding analytics or ad-platform call from a sandboxed context that Shopify manages.
The Branding API (and its admin counterpart, Settings > Checkout > Branding) controls colours, typography, corner radius, logo placement and button styling. It replaces CSS overrides that used to target checkout.liquid’s markup directly.
The distinction that trips teams up: UI extensions and the Branding API change what the checkout looks like; Functions change what checkout decides; Web Pixels change what checkout reports. A migration plan that treats all four as “checkout customisation” and doesn’t separate them by purpose ends up missing whichever category nobody was explicitly responsible for — usually pixels, because they don’t visibly break anything when they stop working.
What does a Plus store lose by staying on checkout.liquid?
The honest answer is: whatever Shopify’s current upgrade guide and shopify.dev say, checked at the time you’re reading this — not a fixed list from memory. Shopify has been moving stores off checkout.liquid on a schedule it controls, and the specifics of what stops working and when have changed as the migration has progressed. The two places to check are Settings > Checkout in your own admin, which reports your store’s actual status and any deadline that applies to it, and shopify.dev’s checkout extensibility documentation, which carries the platform-wide position.
What doesn’t change regardless of the exact date: a store still on checkout.liquid does not get new Shopify checkout features as they ship, because those features are built against the extensibility model, not the legacy template. For a $3M–$30M brand running promotions, testing new payment methods, or trying to reduce checkout abandonment, that gap compounds — every checkout improvement Shopify ships lands on extensibility stores first, and sometimes only.
How do you audit checkout.liquid before migrating?
Before writing a single extension, list everything checkout.liquid is currently doing. This audit is the actual proprietary work of the migration — everything after it is mechanical.
Go through the file (or, if it’s already been removed, whatever documentation, staging backup, or version history exists) and record:
- Every
<script>tag, and what each one does — analytics, ad pixels, a chat widget, a custom validation rule. - Every conditional field — a gift message box, a delivery instructions field, a B2B PO number field — and where in the checkout flow it appears.
- Every discount or eligibility rule that lived in Liquid logic rather than in Shopify’s native discount engine.
- Every CSS override and what visual effect it produced.
- Every third-party app that injected code into checkout via script tags, since several older Shopify apps did this before checkout extensibility existed.
Each row on that list maps to exactly one of the four extension points: checkout UI extensions, Functions, Web Pixels or the Branding API. A script that fires an analytics event becomes a Web Pixel. A conditional field becomes a checkout UI extension targeting the right render point. A discount rule becomes a Function. A CSS override becomes a Branding API setting, or — if the visual change isn’t something Branding covers — a UI extension.
The step most teams get wrong is doing this audit after the store has already been switched to extensibility, working backward from “what broke” instead of forward from a checklist. By the time a missing pixel shows up as a reporting gap, it’s often been silently under-tracking conversions for days.
How do you set up checkout UI extensions?
- Install the Shopify CLI and run the extension scaffold command from within your app’s project directory, selecting the checkout UI extension template.
- Choose the extension target that matches where the old content appeared. Common targets include
purchase.checkout.block.renderfor a standalone content block,purchase.checkout.contact-information.render-after, andpurchase.checkout.delivery-address.render-before— the exact target list is maintained on shopify.dev and worth checking against, since new targets have been added over time. - Build the extension’s UI using Shopify’s checkout UI extension components (these are constrained, sandboxed components — not arbitrary HTML — which is part of why extensions can’t break the surrounding checkout the way an inline script could).
- Use the CLI’s local development preview to see the extension rendered inside a real checkout before deploying.
- Deploy the extension as part of your app and activate it for the store through the checkout editor in Settings > Checkout.
A field that collected data in checkout.liquid — a gift message, a delivery note — needs its extension to write that value somewhere retrievable, typically as a cart or order attribute via the extension’s API, so the value still reaches order processing and fulfilment the way the old field did.
How do you move discount and shipping logic into Shopify Functions?
Any rule that used to run as Liquid conditional logic in checkout.liquid — “hide this payment method for orders under $50”, “apply this discount only alongside that shipping method”, “validate that a B2B PO number is present before allowing submission” — belongs in a Shopify Function, not in a UI extension.
The practical setup:
- Scaffold a Function using the Shopify CLI, choosing the Function type that matches the rule — a payment customization Function, a delivery customization Function, a cart/checkout validation Function, or a discount Function, depending on what the rule actually decides.
- Write the Function’s logic in a supported language (JavaScript/TypeScript and Rust are both common choices for Shopify Functions, compiled to WebAssembly at deploy time).
- Deploy and attach the Function to the store through the relevant admin settings — payment customizations and delivery customizations each have their own activation point separate from the checkout editor used for UI extensions.
- Test the Function against every cart and customer state it’s meant to handle, not just the common case — a discount eligibility Function that only gets tested against one cart composition will miss the edge case a customer eventually hits.
The reason this matters more than it looks like it should: a rule left as client-side JavaScript can be inspected and worked around by anyone who opens their browser’s developer tools. A rule enforced as a Function runs on Shopify’s side and can’t be.
How do you move tracking and pixels off checkout.liquid?
Pixel migration is the step most teams get wrong, and it earns its own section because the failure mode is invisible until someone notices a number is off.
- In the Shopify admin, go to Settings > Customer events.
- For each analytics or ad platform previously wired into checkout.liquid’s script box, add it as a Web Pixel — either through a pre-built app integration where the vendor offers one, or as a custom Web Pixel extension you build and deploy.
- Map each old script’s behaviour to the standard checkout events Web Pixels expose:
checkout_started,checkout_contact_info_submitted,checkout_address_info_submitted,payment_info_submitted, andcheckout_completedcover most of what a conversion pixel needs. - For any tracking that depended on custom logic beyond a standard event — say, a script that only fired for orders above a threshold — that condition needs to be rebuilt inside the Web Pixel’s own code, since it no longer has access to the page’s DOM or Liquid variables the way an inline script did.
- Place a real test order and confirm the event fires in each platform’s real-time or debug view — Meta Events Manager’s test events tool and Google Analytics’ DebugView both show events as they arrive, which is the only reliable way to confirm a pixel actually migrated correctly rather than just appearing to.
Do this migration step before the store loses checkout.liquid, not after. A pixel ported after cutover means a gap in the data between the day checkout.liquid stopped and the day someone noticed the numbers looked wrong — and that gap is usually discovered by whoever runs the ad account, not by whoever ran the migration.
How do you apply brand styling without checkout.liquid’s CSS?
Settings > Checkout > Branding exposes colour tokens, typography choices, corner radius, logo placement, and button and form field styling through a visual editor — no CSS required for the common cases. For a brand that manages checkout styling across multiple stores, or wants it version-controlled alongside a design system, the Branding API exposes the same settings programmatically, so branding can be applied via a script or CI step rather than reproduced by hand in each store’s admin.
What Branding does not cover is layout restructuring — moving a section, adding a custom block in a new position, or building a visual element that isn’t one of Branding’s defined properties. That work belongs to a checkout UI extension, not to Branding settings pushed further than they’re built for.
How do you verify the migration worked?
Before cutover, place a test order that exercises every path the audit surfaced: each payment method, at least one discount code, a shipping zone with custom rates if any exist, and any custom field. Confirm:
- Every UI extension renders in the right position with the right content.
- Every discount and eligibility Function produces the correct outcome for that cart.
- Every Web Pixel fires, checked in each platform’s own real-time debugging tool, not just assumed from the extension being “active”.
- Branding renders correctly across the payment methods your customers actually use, since some payment method UI (like certain wallet buttons) is partly controlled by the payment provider rather than fully by Branding settings.
After go-live, check the first batch of real orders against the admin’s order detail view to confirm custom field values are landing where fulfilment and customer service expect them, and check each analytics platform’s reporting a day or two later — real-time views catch a pixel that never fired, but a pixel firing with the wrong event parameters sometimes only shows up once aggregate reporting runs.
Checkout extensibility is an ops automation problem, not just a checkout problem
Everything above — the audit, the four extension points, the pixel migration — is the same discipline as any other Shopify Plus automation project: map what the current system does field by field, rebuild each piece in the tool built for it, and verify before cutover rather than after. Treating checkout extensibility as “a Shopify update that happens automatically” is how tracking gaps and dropped custom fields make it to production. Our ops automation work on Shopify Plus stores runs this kind of migration as a project with its own audit, build and verification stages — the same shape as a payment recovery flow or an inventory sync, just applied to checkout.
If checkout extensibility is one piece of a broader Shopify Plus platform decision — what the plan costs, and what else comes with it — the Shopify Plus pricing breakdown covers the platform side of that question.
Sources
No external figures are quoted; this article is written from how Shopify checkout extensibility — UI extensions, Functions, Web Pixels and the Branding API — is structured and configured. Store-specific deprecation dates and plan limits should be checked directly in the Shopify admin’s upgrade guide and at shopify.dev, as noted in the body.