Nike is the world’s largest supplier and manufacturer of athletic shoes. Part of what makes Nike successful is its ecommerce website. Its net sales has crossed 12 billion USD in 2022. This makes up approximately 65% of Nike’s global direct-to-customer revenue in 2022 (18.73 billion USD).
Nike’s ecommerce website is rich with features that encourage customers to make a purchase. It shows a great understanding of what customers want, and how to convert first-time visitors to loyal customers.
Nike realized early-on that they needed to implement an omnichannel experience to provide their customers with the best user experience. This led them to build their own headless commerce platforms utilizing microservices and cloud technologies.
In this article, you’ll learn how to implement 5 core features Nike offers its customers using Medusa. These are:
- Digital Gift Cards
- Free shipping for members
- Search suggestions and autocomplete
- Member-only products
- Birthday deals
What is Medusa?
Using an open source ecommerce platform gives you many of the benefits of customization that a custom platform like Nike’s has. Medusa is built for developers that wants to build bespoke commerce experiences with a composable commerce platforms in Node.js.
Medusa’s architecture allows businesses and developers to build unique and on-brand experiences. Features such as omnichannel support, scalability, and customizability are at Medusa’s core.
Medusa also provides advanced ecommerce features related to automated RMA flows, sales channels, product and order management, and much more.
Medusa’s integrations system gives businesses more flexibility. You can integrate any third-party service into Medusa for rich CMS functionalities, payment gateways, customer support, and more. You can also create custom integrations specific to your brand.
Feature 1: Digital Gift Cards
Nike allows customers to customize and purchase gift cards. They can be sent as a gift to an email or can be shipped as an actual card to a shipping address.
Medusa allows creating gift cards with custom images, unlimited amounts, description, tags, and more.
Merchants can also specify for a specific denomination or amount the price for different currencies.
Customers that purchase this gift card will have it delivered to their email and can use it during checkout.
You can also customize the experience by allowing customers to deliver the gift card to another person’s email. Gift cards in Medusa (and all entities) have a Copy to clipboardmetadata
attribute. This attribute can be used to store custom data.
You can utilize it to store a custom recipient email or shipping address, which would allow customers to send the gift card to their family or friends.
123metadata: {recipient_email: 'example@gmail.com'}
Feature 2: Free Shipping for Members
When taking a look at the features Nike provides, you’ll notice that their main focus is converting visitors and one-time customers to registered customers. This builds customer loyalty and increases the possibility of the customer making future purchases.
One way Nike encourages visitors to register and become members is offering free shipping for every order a member places. This makes registering worth the extra steps a customer have to make before placing an order, as they’ll be saving up on current and future orders.
In Medusa, this feature can be implemented with a combination of available features: Customer Groups, Discounts, and Subscribers.
Customer Groups
Customer groups can be used to group together customers that share a similar set of attributes. Then, you can apply a different set of prices, discounts, and rules for customers belonging to that group.
In this use case, you can use customer groups to create the “Members” customer group. You’ll see later how to add customers to that group automatically on registration.
Discounts
Discounts can be used to create discount codes that customers can use to save on their order. Discounts can be in the form of fixed discount amount, percentage discount amount, or free shipping.
Discounts can also have conditions. For example, you can specify which products this discount can be used on or which customer groups.
To implement the Free Shipping for Members feature, you can create a discount that gives customers belonging to the customer group “Members” free shipping on their orders.
Subscribers
The last step required is to automatically:
- Add customers to the Members customer group on registration.
- Add the free shipping discount to customers of the Members customer group.
In Medusa, important actions trigger an event. Developers can listen or subscribe to events and perform an automated task when an action occurs. They do that using subscribers.
Starting with adding customers to the Members customer group, you need to create a subscriber Copy to clipboardsrc/subscribers/members.ts
on your Medusa server that subscribes to the Copy to clipboardcustomer.created
event and adds the customer to the “Members” customer group:
123456789101112131415161718192021222324252627282930313233343536import { CustomerGroupService, CustomerService, EventBusService } from "@medusajs/medusa"type InjectedProperties = {eventBusService: EventBusServicecustomerService: CustomerServicecustomerGroupService: CustomerGroupService}class MembersSubscriber {customerService: CustomerServicecustomerGroupService: CustomerGroupServiceconstructor (container: InjectedProperties) {this.customerService = container.customerServicethis.customerGroupService = container.customerGroupServicecontainer.eventBusService.subscribe('customer.created', this.handleRegistration)}handleRegistration = async (data) => {//get Members customer groupconst membersGroup = await this.customerGroupService.list({name: 'Members'}, { take: 1 })if (!membersGroup.length) {//Members group doesn't existreturn}//add customer to customer groupawait this.customerGroupService.addCustomers(membersGroup[0].id, data.id)}}export default MembersSubscriber
Next, you need to create a subscriber that automatically adds the free shipping discount to members. The subscriber should subscribe to the events Copy to clipboardcart.created
and Copy to clipboardcart.customer_updated
. The first event is triggered when a new cart is created, and the second one is triggered whenever the customer associated with the cart is changed.
123456789101112131415161718192021222324252627282930313233import { CartService, EventBusService } from "@medusajs/medusa"type InjectedDependencies = {eventBusService: EventBusServicecartService: CartService}class MemberDiscountSubscriber {cartService: CartServicediscountCode: stringconstructor (container: InjectedDependencies) {this.cartService = container.cartServicethis.discountCode = 'MEMBERSFREESHIP'container.eventBusService.subscribe('cart.created', this.handleDiscount)container.eventBusService.subscribe('cart.customer_updated', this.handleDiscount)}handleDiscount = async (data) => {const cartId = typeof data === 'string' ? data : data.idthis.cartService.update(cartId, {discounts: [{code: this.discountCode}]})}}export default MemberDiscountSubscriber
Notice that in the code above, the discount code is hardcoded. This behavior can be changed to instead include it as an option or retrieve it in other ways using the Copy to clipboardDiscountService
.
Feature 3: Search Suggestions and Auto Complete
An essential and often overlooked feature that ecommerce websites must perfect is the search functionalities. Customers generally visit an ecommerce website either exactly knowing what they want, or with an idea of what they want.
Nike does a great job at providing results for both types of customers. The moment the customer starts entering a search query, they can see top query suggestions and the best products that match the query.
If the customer knows what they’re looking for, they’ll find the product in the immediate results. If not, they can use the help of the top suggestions.
In Medusa, advanced search functionalities can be implemented by integrating the server to third-party services like Algolia or MeiliSearch. This removes the need to implement these features from scratch, and allows utilizing best-in-brand services in your store.
Both Algolia and MeiliSearch provide advanced features such as instantaneous search results, typo tolerance, search suggestions, autocomplete and more. You can integrate one of them by installing the service’s plugin on the Medusa server. Then, you can customize the UI on the storefront as you see fit for your customers.
Feature 4: Member-only Products
Similar to the free shipping feature, Nike also provides products that are only available for members or registered customers. This further encourages visitors to register and check out exclusive products.
In Medusa, this can be implemented with a combination of features: Customer Groups, Sales Channels, and Subscribers.
Customer Groups
As explained in an earlier section, members can be represented by a Customer Group called “Members”. You would then need to implement automatically assigning the Members customer groups to registered customers, as explained earlier.
Sales Channels
Sales channels allow customizing how and what products you sell for different channels in your store. Channels can be different platforms, such as website or mobile. It can also be different types of customers, such as B2B customers or members.
To implement the Member-only products feature, you need to create a sales channel for Members. Then, you can make only specific products available in that sales channel and not available in the default channel.
Subscribers
The last step is to create two subscribers that handle the following:
- Add customers to the Members customer group on registration.
- Assign the Members sales channel to members’ carts.
The first one’s implementation was explained earlier, and you can find the code block in a previous section.
As for the second, you need to create a subscriber that subscribes to the Copy to clipboardcart.created
and the Copy to clipboardcart.customer_updated
events. If the customer associated with the cart belongs to the Members customer group, the Members sales channel is associated with the cart. Otherwise, the default channel is associated with the cart.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748import { CartService, EventBusService, SalesChannel, SalesChannelService } from "@medusajs/medusa"type InjectedDependencies = {eventBusService: EventBusServicecartService: CartServicesalesChannelService: SalesChannelService}class MemberDiscountSubscriber {cartService: CartServicesalesChannelService: SalesChannelServiceconstructor (container: InjectedDependencies) {this.cartService = container.cartServicethis.salesChannelService = container.salesChannelServicecontainer.eventBusService.subscribe('cart.created', this.handleCreate)container.eventBusService.subscribe('cart.customer_updated', this.handleCreate)}handleCreate = async (data) => {const cartId = typeof data === 'string' ? data : data.id//retrieve default sales channelconst defaultChannel = await this.salesChannelService.retrieveByName('Default Sales Channel') as SalesChannel//retrieve sales channelconst membersChannel = await this.salesChannelService.retrieveByName('Members') as SalesChannelif (!membersChannel) {//sales channel does not existreturn}//retrieve cartconst cart = await this.cartService.retrieve(cartId, {relations: ['customer', 'customer.groups']})const isMember = cart.customer?.groups.some((group) => group.name === 'Members')await this.cartService.update(cartId, {sales_channel_id: isMember ? membersChannel.id : defaultChannel.id})}}export default MemberDiscountSubscriber
Feature 5: Birthday Deals
Another member benefit that Nike offers is birthday deals. If a member registers before their birthday, they’ll receive a discount on their birthday. Nike emails them with details about the discount.
This can be implemented in Medusa using a combination of features: Customer Groups, and Scheduled Jobs. The usage of customer groups is as explained in earlier sections.
Scheduled Jobs
Medusa allows developers to schedule a task to run at a specific time using scheduled jobs. In this context, a scheduled job can be used to run every day at midnight. Then, it checks which customers’ birthday is set to today. For those customers, an email is sent with the deal details.
You can make use of the Copy to clipboardmetadata
field to store custom fields such as Copy to clipboardbirthday
. You’ll need to save it when the customer registers or allow the customer to set their birthday in their profile.
12345678910111213141516171819const checkBirthdaysJob = async (container, options) => {const jobSchedulerService = container.resolve("jobSchedulerService");jobSchedulerService.create("check-birthdays", {}, "0 0 * * *", async () => {//job to executeconst customerService = container.resolve("customerService");const customers = await this.customerService.list({metadata: {birthday: Date.now().toString()}})customers.forEach((customer) => {//create discount/gift card//and send email})})}export default checkBirthdaysJob;
The deal can be implemented either using Discounts or Custom Gift Cards. For the first option, you create a discount with a random code and send it to the customer. For the second option, you create a custom gift card with an amount, and send the gift card’s code to the customer.
To send the email to the customer, you’ll need to integrate a third-party plugin such as SendGrid.
Do More with Medusa
The features explored in this article aim to provide a better user experience for customers. This is what sets big brands like Nike apart and keep their customers loyal.
Although Nike has developed its own headless commerce platform from scratch, using a platform like Medusa can provide a similar amount of features, extensibility, and scalability.
Check out the documentation for more details on what Medusa is and how to get started.
Should you have any issues or questions related to Medusa, then feel free to reach out to the Medusa team via Discord.
Share this post