La extensibilidad del checkout son en realidad dos productos
Las UI extensions renderizan y las Functions deciden. Casi todo proyecto de checkout que decepciona nace de pedirle a una el trabajo de la otra.
Análisis8 de julio de 20267 min de lectura
"Extensibilidad del checkout" es una sola frase que cubre dos tecnologías que casi no comparten nada. Una dibuja cosas que el comprador ve. La otra toma decisiones que el comprador nunca ve. Corren en lugares distintos, bajo reglas distintas, con modos de fallo distintos, y el plan las limita de forma distinta.
Casi todo proyecto de checkout que termina en decepción termina ahí porque alguien le pidió a una mitad el trabajo de la otra. El comerciante pidió un cargo y recibió un mensaje. El comerciante pidió una explicación y recibió un cambio de precio silencioso. Ninguna de las dos partes se equivocó sobre lo que quería; usaban una palabra para dos cosas.
Vale la pena separarlas bien, porque en cuanto puedes distinguirlas también puedes decir, a partir de una sola frase de una petición, cuál de las dos te están pidiendo en realidad.
Un nombre, dos productos
Una checkout UI extension es una aplicación pequeña que Shopify dibuja dentro de una ranura con nombre en el checkout. Es tu código, corriendo en un sandbox, dentro de la sesión del comprador, dibujando una interfaz. Puede mostrar un campo de mensaje de regalo, un selector de fecha de entrega, un sello de confianza, una línea de texto que explica una restricción.
Una Function es un módulo de WebAssembly que Shopify ejecuta en sus propios servidores mientras cotiza el carrito y valida el pedido. No tiene interfaz y no puede producir una. Devuelve una lista de operaciones y desaparece.
Desliza la figura para verla completa
Dicho a lo bruto: la mitad de UI es un inquilino en la interfaz de Shopify, y la mitad de lógica es una subrutina en el motor de precios de Shopify. La primera es una invitada y se comporta como tal. La segunda es código que la plataforma ejecuta por cuenta propia.
La mitad de UI es consultiva, y la API lo dice en voz alta
Esta es la parte que sorprende, y Shopify es admirablemente directo al respecto. Una checkout UI extension no cambia el checkout sin más. Pregunta, y el checkout puede decir que no.
Antes de agregar una línea al carrito, se espera que la extension revise instructions.lines.canAddCartLine. Antes de escribir un metafield de carrito, instructions.metafields.canSetCartMetafields. Antes de editar la dirección de envío, instructions.delivery.canSelectCustomAddress. Esas instrucciones no son decoración; se ponen en falso en situaciones reales — un checkout de draft order, una sesión de Shop Pay, una suscripción — y una extension que las ignora falla en el peor momento.
El rate limiting es todavía más revelador. Shopify limita a las extensions que aplican demasiados cambios, y lo que la documentación dice que ocurre después es que la extensión ya no puede hacer cambios durante esa sesión del comprador. Léelo al revés: la plataforma está construida para esquivar una extensión que se porta mal, no para que pueda detener una venta. Es el compromiso correcto para un checkout, y es letal para cualquier plan que trate a una UI extension como mecanismo de cumplimiento.
Súmale la última restricción, la que define el alcance más seguido que ninguna otra: las checkout UI extensions que se dibujan en los pasos de información, envío y pago están disponibles solo en Shopify Plus. Las extensions en otros puntos del flujo son de disponibilidad más amplia. Una cotización escrita sin saber de qué lado de esa línea cae la petición es una adivinanza.
La mitad de lógica es autoritativa, y muda
Una Function tiene el perfil opuesto. No se puede saltar, ni limitar hasta volverla irrelevante, ni esquivar por un comprador que le pega directo a la API del carrito: corre dentro de la pasada de precio, en la infraestructura de Shopify, siempre. Si necesitas que una regla sea cierta, este es el único lugar donde puede vivir.
Y no puede decir ni una palabra. Devuelve operaciones. Una Function de validación puede devolver un mensaje de error atado a un campo, y una Function de descuento adjunta un mensaje al descuento que creó, pero ninguno de los dos es una interfaz que tú controles. Una Function no puede dibujar un tooltip explicando que la tarifa de importación se saltó la tarjeta de regalo. No puede poner un distintivo junto a una línea. Cambia el número y sigue.
El intercambio es deliberado. La mitad en la que se puede confiar es la mitad que no se ve, y la mitad que se ve es la mitad en la que no se puede confiar.
Desliza la figura para verla completa
Cuatro frases, y qué está pidiendo cada una en realidad
Aquí es donde la distinción se paga sola. Toma cuatro peticiones que llegan redactadas casi igual y ordénalas.
"Agrega un cargo de cinco dólares por envoltura de regalo." Esto es una Function — Cart Transform, expandiendo la línea. Una extension podría agregar un producto de envoltura como línea de carrito, pero estaría agregando un producto a su propio precio, no un cargo, y lo haría desde una superficie que puede quedar limitada. Si el dinero tiene que estar bien, el dinero es una Function.
"Deja que el cliente escriba un mensaje de regalo." Esto es una UI extension, entera. No hay decisión que tomar. Hay que dibujar algo, recogerlo y adjuntarlo al pedido como atributo o metafield de carrito. Una Function no tiene nada que aportar.
"Muéstrale al cliente por qué no aplicó su descuento." Esto son las dos, y es la petición que más seguido se construye como una sola. La regla vive en una Function. La explicación vive en una extension. No comparten memoria, así que alguien tiene que diseñar el traspaso — normalmente un atributo o un metafield de carrito que la Function pueda leer y la extension pueda mostrar, escrito por el lado que de verdad sabe.
"Que nadie de esa región pueda completar un pedido." Esto es una Function de validación y nada más. Construirlo como extension produce un checkout que bloquea a los compradores educados y deja pasar a cualquiera con conexión lenta o bloqueador de anuncios, que es peor que no construirlo.
El patrón de fondo: si la respuesta equivocada cuesta dinero o rompe un compromiso, es una Function. Si la respuesta equivocada cuesta un momento de confusión, es una extension. Casi todo brief real contiene las dos, y el plan de proyecto útil las nombra por separado con criterios de aceptación separados. Así estructuramos nuestro trabajo de checkout extensions, y por eso una app de motor de reglas mantiene la configuración de cara al comerciante en el admin y no dentro del checkout.
Por qué la división es correcta, aunque moleste
Sería más cómodo que una extension pudiera fijar un precio. También significaría que el precio del checkout se puede cambiar desde código que corre en un navegador, que es una categoría de problema que ninguna plataforma de ecommerce sobrevive a escala. La separación no es un descuido que haya que rodear; es la razón por la que Shopify puede correr un solo checkout para todos y aun así dejar que desconocidos lo extiendan.
La consecuencia útil para quien cotiza este trabajo es que la frontera es una costura real del proyecto, no un detalle de implementación. Cambia el requisito de plan, la estrategia de pruebas (una Function se prueba aislada, una extension necesita un checkout real), la historia de despliegue, y quién responde cuando algo se ve raro en producción. Tratarlo como una sola cosa llamada "personalización del checkout" esconde las cuatro.
Cómo formular la petición
Antes de pedirle a alguien que construya trabajo de checkout, parte tu propia frase en dos. Escribe qué tiene que ser cierto — el precio, la regla, la negativa — y aparte qué tiene que ser visible — el campo, el mensaje, el distintivo. Después pregunta qué pasa si la mitad visible nunca se dibuja.
Si la respuesta es "el comprador se confunde", tienes un diseño sano. Si la respuesta es "perdemos dinero", la regla está en la mitad equivocada y hay que moverla antes de que alguien escriba código. Nuestras páginas de extensibilidad del checkout y desarrollo de Shopify Functions cubren las dos mitades por separado por la misma razón, y la decisión entre una Function, una app y un cambio de tema es lo siguiente que conviene leer una vez que la división está clara.