Rename and reorder payment methods at checkout
A Shopify payment customization Function that renames payment methods and changes their order at checkout from a JSON metafield. Tested JavaScript.
- Function API
- Payment Customization
- Target
- cart.payment-methods.transform.run
- Plan
- Any plan in a public app; Shopify Plus in a custom app
- App scope
- write_payment_customizations
- API version
- 2026-10
- Last checked
In short
This payment customization Function renames payment methods and puts them in the order you choose at checkout, for example a clearer name for bank transfer and cards first. Both come from a JSON metafield, so nothing is hardcoded. It uses the cart.payment-methods.transform.run target of the Payment Customization API, version 2026-10, with the paymentMethodRename and paymentMethodMove operations.
How to use it
- Create an app with the Shopify CLI, then add the extension: shopify app generate extension --template payment_customization, with JavaScript.
- Replace the generated shopify.extension.toml and the two files in src/ with the files below.
- Run the fixtures with shopify app function run --input tests/rename-and-reorder.input.json.
- Deploy with shopify app deploy and create the customization with paymentCustomizationCreate.
- Set the $app:function-configuration metafield, for example {"renames": {"Bank Deposit": "Bank transfer"}, "order": ["Credit card", "Bank Deposit"]}.
Code
shopify.extension.tomlapi_version = "2026-10"
[[extensions]]
name = "Rename and reorder payment methods"
handle = "rename-reorder-payment-methods"
type = "function"
[[extensions.targeting]]
target = "cart.payment-methods.transform.run"
input_query = "src/cart_payment_methods_transform_run.graphql"
export = "cart-payment-methods-transform-run"
[extensions.build]
command = ""
path = "dist/function.wasm"
src/cart_payment_methods_transform_run.graphqlquery CartPaymentMethodsTransformRunInput {
paymentMethods {
id
name
}
paymentCustomization {
metafield(namespace: "$app", key: "function-configuration") {
jsonValue
}
}
}
src/cart_payment_methods_transform_run.js// @ts-check
/**
* @typedef {import("../generated/api").CartPaymentMethodsTransformRunInput} CartPaymentMethodsTransformRunInput
* @typedef {import("../generated/api").CartPaymentMethodsTransformRunResult} CartPaymentMethodsTransformRunResult
*/
/**
* Settings stored as JSON in the customization's metafield. Both are empty by
* default, so checkout stays unchanged until the merchant configures them.
*/
const DEFAULT_CONFIG = {
// Current name → name shown at checkout, matched case-insensitively.
renames: /** @type {Record<string, string>} */ ({}),
// Names in the order they should appear; unlisted methods keep their place after them.
order: /** @type {string[]} */ ([]),
};
/**
* @param {CartPaymentMethodsTransformRunInput} input
* @returns {CartPaymentMethodsTransformRunResult}
*/
export function cartPaymentMethodsTransformRun(input) {
const config = { ...DEFAULT_CONFIG, ...input.paymentCustomization?.metafield?.jsonValue };
const renames = new Map(Object.entries(config.renames).map(([from, to]) => [from.toLowerCase(), to]));
/** @param {string} name */
const findMethod = (name) =>
input.paymentMethods.find((method) => method.name.toLowerCase() === name.toLowerCase());
// Rename operations refer to the method's ID, so they're independent of the order below.
const renameOperations = input.paymentMethods
.filter((method) => renames.has(method.name.toLowerCase()))
.map((method) => ({
paymentMethodRename: { paymentMethodId: method.id, name: renames.get(method.name.toLowerCase()) ?? method.name },
}));
// Index counts only methods present in this checkout, so a configured method
// that isn't offered (another market, an inactive gateway) leaves no gap.
const moveOperations = config.order
.map(findMethod)
.filter((method) => method != null)
.map((method, index) => ({ paymentMethodMove: { paymentMethodId: method.id, index } }));
return { operations: [...renameOperations, ...moveOperations] };
}
Test input and expected output
tests/missing-method-skipped.input.json{
"paymentMethods": [
{ "id": "gid://shopify/PaymentCustomizationPaymentMethod/1", "name": "Credit card" },
{ "id": "gid://shopify/PaymentCustomizationPaymentMethod/2", "name": "PayPal" },
{ "id": "gid://shopify/PaymentCustomizationPaymentMethod/3", "name": "Bank Deposit" }
],
"paymentCustomization": {
"metafield": { "jsonValue": { "order": ["Cash on Delivery (COD)", "PayPal"] } }
}
}
tests/missing-method-skipped.output.json{
"operations": [
{ "paymentMethodMove": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/2", "index": 0 } }
]
}
tests/not-configured.input.json{
"paymentMethods": [
{ "id": "gid://shopify/PaymentCustomizationPaymentMethod/1", "name": "Credit card" },
{ "id": "gid://shopify/PaymentCustomizationPaymentMethod/2", "name": "PayPal" },
{ "id": "gid://shopify/PaymentCustomizationPaymentMethod/3", "name": "Bank Deposit" }
],
"paymentCustomization": { "metafield": null }
}
tests/not-configured.output.json{ "operations": [] }
tests/rename-and-reorder.input.json{
"paymentMethods": [
{ "id": "gid://shopify/PaymentCustomizationPaymentMethod/1", "name": "Credit card" },
{ "id": "gid://shopify/PaymentCustomizationPaymentMethod/2", "name": "PayPal" },
{ "id": "gid://shopify/PaymentCustomizationPaymentMethod/3", "name": "Bank Deposit" }
],
"paymentCustomization": {
"metafield": {
"jsonValue": {
"renames": { "bank deposit": "Bank transfer (2% off, ships after payment)" },
"order": ["Bank Deposit", "Credit card"]
}
}
}
}
tests/rename-and-reorder.output.json{
"operations": [
{
"paymentMethodRename": {
"paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/3",
"name": "Bank transfer (2% off, ships after payment)"
}
},
{ "paymentMethodMove": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/3", "index": 0 } },
{ "paymentMethodMove": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/1", "index": 1 } }
]
}
Written by Lintel. MIT license: free to use in your own store and in client work.
Limits and edge cases
- Methods whose name is a logo can’t be renamed: Shop Pay, Apple Pay, Google Pay, other wallets and the gift card field.
- Wallets can be hidden but not reordered; move operations for them have no effect.
- Names are matched as the customer sees them at checkout, ignoring case. A method listed in the configuration but not offered in this checkout is skipped.
- Inside Shop Pay, payment customizations only affect the gift card field.
Questions
- How do I change the order of payment methods in Shopify checkout?
- The payment settings don’t let you sort methods. A payment customization Function returns paymentMethodMove operations with the position for each method, which is what this example does.
- Can I rename Cash on Delivery or bank transfer?
- Yes. Manual methods such as Cash on Delivery and bank deposit can be renamed with paymentMethodRename. Wallets and logo-only methods like Shop Pay can’t.
- Can the new name change by language?
- This example uses one name. Add localization { language { isoCode } } to the input query and keep one renames map per language in the metafield if you sell in several languages.
Shopify documentation
- Written for Function API version 2026-10 and checked against Shopify’s reference on the date shown. Shopify releases a new version every quarter.
- Custom apps that contain Functions only run on Shopify Plus stores; a public app with the same Function runs on any plan unless the page says otherwise.
- Every example ships with test fixtures, and we run them before publishing. Run them again after you change the code: shopify app function run.
- MIT license. Use the code in your own store or in client work.
Need this built, tested and maintained for your store? See Shopify Functions development.
