Implementing a Custom Checkout Step

Implementing a Custom Checkout Step

This tutorial will show you how to add a custom checkout step by implementing the CommerceCheckoutStep interface.

A checkout step represents one screen of the checkout process for a customer. Liferay Commerce provides several checkout steps out-of-the-box, including essential steps like the payment method step and the order confirmation step.

Out-of-the-box checkout steps


  1. Deploy an Example
  2. Walk Through the Example
  3. Additional Information

Deploy an Example

In this section, we will get an example checkout step up and running on your instance of Liferay Commerce.

Start a new Liferay instance by running

docker run -it -m 8g -p 8080:8080 liferay/portal:

Sign in to Liferay at http://localhost:8080. Use the email address [email protected] and the password test. When prompted, change the password to learn.

Then, follow these steps:

  1. Download and unzip the Acme Commerce Checkout Step.

    curl -O
  2. Build and deploy the example.

    ./gradlew deploy$(docker ps -lq)

    This command is the same as copying the deployed jars to /opt/liferay/osgi/modules on the Docker container.

  3. Confirm the deployment in the Docker container console.

    STARTED com.acme.n8n6.web_1.0.0
  4. Verify that the example checkout step was added. Open your browser to https://localhost:8080 and navigate to a catalog on any Liferay Commerce site. Add an item to the cart, view the cart, and then click “Checkout”. The new “N8N6 Commerce Checkout Step” will be present in the list of checkout steps.

New checkout step

Congratulations, you’ve successfully built and deployed a new checkout step that implements CommerceCheckoutStep.

Next, let’s dive deeper to learn more.

Walk Through the Example

In this section, we will review the example we deployed. First, we will annotate the class for OSGi registration. Second, we will review the CommerceCheckoutStep interface. And third, we will complete our implementation of CommerceCheckoutStep.


To simplify implementing CommerceCheckoutStep, we extend BaseCommerceCheckoutStep for its base functionality.

Annotate the Class for OSGi Registration

    property = {
    service = CommerceCheckoutStep.class
public class N8N6CommerceCheckoutStep extends BaseCommerceCheckoutStep {

The checkout step name must be a unique value so that Liferay Commerce can distinguish our checkout step from existing checkout steps.

The commerce.checkout.step.order value indicates how far into the checkout process the checkout step will appear. For example, the shipping method checkout step has a value of 20. Giving our checkout step a value of 21 ensures that it will appear immediately after the shipping method step.

Review the CommerceCheckoutStep Interface

Implement the following methods in addition to extending the base class:

public String getName();

This method returns the name of our checkout step. This name may be a language key that corresponds to the name that will appear in the UI.

public void processAction(
        ActionRequest actionRequest, ActionResponse actionResponse)
    throws Exception;

The processAction method may be used to implement business logic with the information passed through the ActionRequest if backend processing is required.

public void render(
        HttpServletRequest httpServletRequest,
        HttpServletResponse httpServletResponse)
    throws Exception;

This will be where we add the code to render a customized screen for our checkout step.

Complete the Checkout Step

The checkout step is comprised of a custom screen and backend logic to process any input. Do the following:

Configure the ServletContext for the Module

Define the ServletContext using the symbolic name of our bundle so that it can find the JSP in our module:

@Reference(target = "(osgi.web.symbolicname=com.acme.n8n6.web)")
private ServletContext _servletContext;

The value we set for osgi.web.symbolicname matches the value for Bundle-SymbolicName in our bnd.bnd file. These values must match for the ServletContext to locate the JSP.

We also need to declare a unique value for Web-ContextPath in our bnd.bnd file so the ServletContext is correctly generated. In our example, Web-ContextPath is set to /n8n6-web. See bnd.bnd for a reference on these values.

Implement the render Method

public void render(
        HttpServletRequest httpServletRequest,
        HttpServletResponse httpServletResponse)
    throws Exception {

        _servletContext, httpServletRequest, httpServletResponse,

private JSPRenderer _jspRenderer;

@Reference(target = "(osgi.web.symbolicname=com.acme.n8n6.web)")
private ServletContext _servletContext;

Use a JSPRenderer to render the JSP for our checkout step (in this case, terms_and_conditions.jsp). Provide the ServletContext as a parameter to find the JSP we have created.

Add Business Logic to processAction

Our example will display text on a custom screen and does not require backend processing in the processAction implementation.

Add a JSP to Render the Custom Screen

In our example, we are adding placeholder text. You can see the implementation at terms_and_conditions.jsp.

Add the Language Key to

Add the language key and its value to a file within our module:

n8n6-commerce-checkout-step=N8N6 Commerce Checkout Step

See Localizing Your Application for more information.


Congratulations! You now know the basics for implementing the CommerceCheckoutStep interface, and have added a new checkout step to Liferay Commerce.

Additional Information