How to Implement Customer Profiles
In this document, you’ll learn how to implement customer account functionalities in a storefront.
Overview
Medusa provides the necessary functionalities and endpoints to allow integrating essential customer features. Customers can create accounts to manage their information and keep track of their orders.
Scenario
You want to implement the following features in a storefront:
- Customer registration
- Customer login and logout
- Allow customers to reset their password
- Allow customers to manage their basic information and shipping addresses
- Show customers their orders
You can use Medusa’s Store APIs to achieve more functionalities as well. Check out the API reference to learn more.
Prerequisites
Medusa Components
It's assumed that you already have a Medusa server installed and set up. If not, you can follow the quickstart guide to get started.
It's also assumed you already have a storefront set up. It can be a custom storefront or one of Medusa’s storefronts. If you don’t have a storefront set up, you can install either the Next.js or Gatsby storefronts.
JS Client
This guide includes code snippets to send requests to your Medusa server using Medusa’s JS Client, among other methods.
If you follow the JS Client code blocks, it’s assumed you already have Medusa’s JS Client installed and have created an instance of the client.
Medusa React
This guide also includes code snippets to send requests to your Medusa server using Medusa React, among other methods.
If you follow the Medusa React code blocks, it's assumed you already have Medusa React installed and have used MedusaProvider higher in your component tree.
Register a Customer
A customer can register with an email and a password to store and manage their data.
You can register a new customer by sending a request to the Create a Customer endpoint:
- Medusa JS Client
- Medusa React
- Fetch API
medusa.customers.create({
email,
password,
first_name,
last_name,
})
.then(({ customer }) => {
console.log(customer.id)
})
import { useCreateCustomer } from "medusa-react"
const RegisterCustomer = () => {
const createCustomer = useCreateCustomer()
// ...
const handleCreate = () => {
// ...
createCustomer.mutate({
first_name,
last_name,
email,
password,
})
}
// ...
return (
<form>
{/* Render form */}
</form>
)
}
export default RegisterCustomer
fetch(`<SERVER_URL>/store/customers`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
first_name,
last_name,
}),
})
.then((response) => response.json())
.then(({ customer }) => {
console.log(customer.id)
})
This request requires the following body parameters:
email
: An email used to log in after registration. This email must be unique. You can check if an email is unique using the “Check if email exists” endpoint.password
: A password used to log in after registration.first_name
: The customer’s first name.last_name
: The customer’s last name.
This request also accepts optional body parameters, which you can check out in the API reference.
It returns the created customer object in the response.
Log in a Customer
A customer can log in to your store to manage their data and make purchases using their account.
You can log in a customer into your store by sending a request to the Customer Login endpoint:
- Medusa JS Client
- Fetch API
medusa.auth.authenticate({
email,
password,
})
.then(({ customer }) => {
console.log(customer.id)
})
fetch(`<SERVER_URL>/store/auth`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
}),
})
.then((response) => response.json())
.then(({ customer }) => {
console.log(customer.id)
})
This request requires the body parameters email
and password
. It returns the customer object in the response.
If you’re using the Medusa JS Client, the customer’s session will already be set and used in all future requests.
However, if you’re using the Fetch API, you must include the option credentials
with the value include
to make sure all future requests are authenticated.
Log out a Customer
You can log out a customer by sending a request to the Customer Logout endpoint:
- Medusa JS Client
- Fetch API
medusa.auth.deleteSession()
.then(() => {
// success
})
fetch(`<SERVER_URL>/store/auth`, {
method: "DELETE",
credentials: "include",
})
.then(() => {
// success
})
If this request is successful, the customer’s session will be deleted and they’ll be logged out.
Reset Password
Customers might need to reset their password in case they forget it. To reset a customer’s password, you need to implement two steps.
Step 1: Request Password Reset
The customer must first enter their account’s email. Then, if an account with that email address exists, an email will be sent to that email address with a link that points the customer to step 2.
You can request to reset a customer’s password by sending a request to the Request Password Reset endpoint:
- Medusa JS Client
- Fetch API
medusa.customers.generatePasswordToken({
email,
})
.then(() => {
// successful
})
.catch(() => {
// failed
})
fetch(`<SERVER_URL>/store/customers/password-token`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
}),
})
.then(() => {
// successful
})
.catch(() => {
// failed
})
This request requires the body parameter email
. Its value must be the email associated with the customer’s account.
If the request has been processed successfully, it returns a 204
status code in the response. In case it fails, an error will be thrown.
If the customer doesn’t receive an email after this request, make sure that you’ve set up a Notification provider like SendGrid successfully. You also need to add a subscriber that handles the customer.password_reset event and sends the email.
Step 2: Verify and Reset Password
After the first step, the customer should receive an email with a link to a page in the storefront. This page should accept a token
query parameter. Then, the customer should be prompted to enter their email and password.
You can then reset the customer’s password to the new password they enter by sending a request to the Reset Password endpoint:
- Medusa JS Client
- Fetch API
medusa.customers.resetPassword({
email,
password,
token,
})
.then(({ customer }) => {
console.log(customer.id)
})
fetch(`<SERVER_URL>/store/customers/password-reset`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
token,
}),
})
.then((response) => response.json())
.then(({ customer }) => {
console.log(customer.id)
})
This request requires the following body parameters:
email
: The email of the customer. This must be the email associated with the account.password
: The new password the customer wants to use for their account.token
: The token passed as a query into the page.
If successful, this request returns the customer object in the response.
Edit a Customer’s Info
A logged-in customer can edit their info, such as their first name or email address.
You can edit a customer’s info using the Update Customer endpoint:
- Medusa JS Client
- Medusa React
- Fetch API
medusa.customers.update({
first_name,
})
.then(({ customer }) => {
console.log(customer.id)
})
import { useUpdateMe } from "medusa-react"
const UpdateCustomer = () => {
const updateCustomer = useUpdateMe()
// ...
const handleUpdate = () => {
// ...
updateCustomer.mutate({
id: customer_id,
first_name,
})
}
// ...
return (
<form>
{/* Render form */}
</form>
)
}
export default UpdateCustomer
fetch(`<SERVER_URL>/store/customers/me`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
first_name,
}),
})
.then((response) => response.json())
.then(({ customer }) => {
console.log(customer.id)
})
This request accepts any of the customer’s details that should be updated as body parameters. In the example above, the first_name
of the customer is updated. You can check out the API reference for a full list of accepted body parameters.
It returns in the response the updated customer object.
Manage Shipping Addresses
A logged-in customer uses their shipping addresses during the checkout process. They can have more than one shipping address, and they can choose one of them when placing an order.
The customer object returned in the requests mentioned in this document include a shipping_addresses
property. It’s an array of the customer’s shipping addresses. You can access it to display the customer’s shipping addresses.
Add a Shipping Address
You can add a shipping address to a customer’s account by sending a request to the Add a Shipping Address endpoint:
- Medusa JS Client
- Fetch API
medusa.customers.addresses.addAddress({
address: {
first_name,
last_name,
address_1,
city,
country_code,
postal_code,
phone,
company,
address_2,
province,
metadata,
},
})
.then(({ customer }) => {
console.log(customer.id)
})
fetch(`<SERVER_URL>/store/customers/me/addresses`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
address: {
first_name,
last_name,
address_1,
city,
country_code,
postal_code,
phone,
company,
address_2,
province,
metadata,
},
}),
})
.then((response) => response.json())
.then(({ customer }) => {
console.log(customer.id)
})
This request requires an address
object as a body parameter. The address
object must have the following properties:
first_name
: The first name associated with the shipping addresslast_name
: The last name associated with the shipping addressaddress_1
: The first address line of the shipping address.city
: The city of the shipping address.country_code
: The 2 character ISO code of the country in lower case.postal_code
: The postal code of the shipping address
It also accepts other optional body parameters, which you can learn more about in the API reference.
This request returns the updated customer object in the response.
Edit a Shipping Address
You can edit a customer’s shipping address using the Update a Shipping Address endpoint:
- Medusa JS Client
- Fetch API
medusa.customers.addresses.updateAddress(addressId, {
first_name,
})
.then(({ customer }) => {
console.log(customer.id)
})
fetch(`<SERVER_URL>/store/customers/me/addresses/${addressId}`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
first_name,
}),
})
.then((response) => response.json())
.then(({ customer }) => {
console.log(customer.id)
})
This request requires the address’s ID as a path parameter. It accepts as a body parameter any of the address’s properties. In the example above, the first_name
of the shipping address is updated. You can check the API reference for all the available body parameters.
This request returns the updated customer object in the response.
Delete a Shipping Address
You can delete a shipping address by sending a request to the Delete an Address endpoint:
- Medusa JS Client
- Fetch API
medusa.customers.addresses.deleteAddress(addressId)
.then(({ customer }) => {
console.log(customer.id)
})
fetch(`<SERVER_URL>/store/customers/me/addresses/${addressId}`, {
method: "DELETE",
credentials: "include",
})
.then((response) => response.json())
.then(({ customer }) => {
console.log(customer.id)
})
This request requires the address’s ID as a path parameter. It returns in the response the updated customer object.
Retrieve a Customer’s Orders
Logged-in customers can see their orders along with the orders’ details.
You can retrieve a customer’s orders by sending a request to the List Orders endpoint:
- Medusa JS Client
- Medusa React
- Fetch API
medusa.customers.listOrders()
.then(({ orders, limit, offset, count }) => {
console.log(orders)
})
import { useCustomerOrders } from "medusa-react"
import { Order } from "@medusajs/medusa"
const Orders = () => {
// refetch a function that can be used to
// re-retrieve orders after the customer logs in
const { orders, isLoading, refetch } = useCustomerOrders()
return (
<div>
{isLoading && <span>Loading orders...</span>}
{orders?.length && (
<ul>
{orders.map((order: Order) => (
<li key={order.id}>{order.display_id}</li>
))}
</ul>
)}
</div>
)
}
export default Orders
fetch(`<SERVER_URL>/store/customers/me/orders`, {
credentials: "include",
})
.then((response) => response.json())
.then(({ orders, limit, offset, count }) => {
console.log(orders)
})
This request doesn’t require any path or query parameters. You can, however, send optional query parameters used for filters, pagination, and sorting. You can learn more in the API reference.
It returns the following data in the response:
orders
: An array of orders.limit
: The maximum number of orders that can be returned in the request.offset
: The number of orders skipped in the result.count
: The total number of orders available.
You can learn more about pagination in the API reference.