Guest Checkout
This guide explains how to implement guest checkout using a customer object.
Prerequisites
- An Elastic Path Commerce store
- API client credentials with appropriate permissions
- A cart with items
@epcc-sdk/sdks-shopper
package installed
Implementation Steps
-
Install and Configure the Shopper SDK
npm install @epcc-sdk/sdks-shopper
-
Create a Checkout Form
- Build a form to collect essential customer information (name, email, billing and shipping addresses)
- Include any necessary validation to ensure data quality
-
Format the Customer Data Object
- Structure the collected form data as a customer object
- Include customer details, billing address, and shipping address
// Basic structure of a guest checkout object
const checkoutData = {
data: {
// Optional fields
order_number: 1234,
external_ref: "order-ref-123",
// Customer information (required)
customer: {
email: "john@example.com",
name: "John Doe",
},
// Billing address
billing_address: {
first_name: "John",
last_name: "Doe",
company_name: "Company Inc",
line_1: "123 Billing St",
line_2: "Suite 101",
city: "Billing City",
county: "Billing County",
region: "State",
postcode: "12345",
country: "US",
},
// Shipping address
shipping_address: {
first_name: "John",
last_name: "Doe",
phone_number: "(555) 555-1234",
company_name: "Company Inc",
line_1: "123 Shipping St",
line_2: "Apt 202",
city: "Shipping City",
county: "Shipping County",
region: "State",
postcode: "12345",
country: "US",
instructions: "Leave package at front door",
},
},
}; -
Convert Cart to Order
- Use the
checkoutApi
function to convert the cart to an order - Pass the customer data object as part of the request
- Use the
-
Process Payment
- Implement a payment processing solution
- For simple testing, you can use the manual gateway
-
Display Order Confirmation
- Show order details to the customer
- Clear the cart data after successful checkout
Sample Implementation
Here's a simple React component implementing guest checkout:
import React, { useState } from "react";
import { getCartId, checkoutApi, paymentSetup } from "@epcc-sdk/sdks-shopper";
function GuestCheckout() {
// State for form data
const [formData, setFormData] = useState({
email: "",
firstName: "",
lastName: "",
billingLine1: "",
billingCity: "",
billingPostcode: "",
billingCountry: "",
shippingLine1: "",
shippingCity: "",
shippingPostcode: "",
shippingCountry: "",
sameAsShipping: true,
});
// State for tracking process
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [orderConfirmation, setOrderConfirmation] = useState(null);
// Handle form input changes
const handleInputChange = (e) => {
const { name, value, type, checked } = e.target;
setFormData((prev) => ({
...prev,
[name]: type === "checkbox" ? checked : value,
}));
};
// Handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
try {
// Create customer data object for checkout
const customerData = {
customer: {
email: formData.email,
name: `${formData.firstName} ${formData.lastName}`,
},
billing_address: {
first_name: formData.firstName,
last_name: formData.lastName,
line_1: formData.billingLine1,
city: formData.billingCity,
postcode: formData.billingPostcode,
country: formData.billingCountry,
},
shipping_address: {
first_name: formData.firstName,
last_name: formData.lastName,
line_1: formData.sameAsShipping
? formData.billingLine1
: formData.shippingLine1,
city: formData.sameAsShipping
? formData.billingCity
: formData.shippingCity,
postcode: formData.sameAsShipping
? formData.billingPostcode
: formData.shippingPostcode,
country: formData.sameAsShipping
? formData.billingCountry
: formData.shippingCountry,
},
};
// Get cart ID
const cartId = getCartId();
if (!cartId) {
throw new Error("No cart found. Please add items to your cart first.");
}
// Checkout the cart
const checkoutResponse = await checkoutApi({
path: {
cartID: cartId,
},
body: {
data: customerData,
},
});
const orderId = checkoutResponse.data?.data?.id;
if (!orderId) {
throw new Error("Failed to create order");
}
// Process payment using manual gateway
const paymentResponse = await paymentSetup({
path: {
orderID: orderId,
},
body: {
data: {
gateway: "manual",
method: "purchase",
},
},
});
// Set order confirmation details
setOrderConfirmation({
orderId: paymentResponse.data?.data?.order?.id,
orderReference: paymentResponse.data?.data?.order?.reference,
orderStatus: paymentResponse.data?.data?.order?.status,
orderTotal:
paymentResponse.data?.data?.order?.meta?.display_price?.with_tax
?.formatted,
});
} catch (err) {
setError(err.message || "Checkout failed. Please try again.");
console.error("Checkout error:", err);
} finally {
setLoading(false);
}
};
// Show order confirmation if checkout was successful
if (orderConfirmation) {
return (
<div className="order-confirmation">
<h2>Thank you for your order!</h2>
<p>Order ID: {orderConfirmation.orderId}</p>
<p>Reference: {orderConfirmation.orderReference}</p>
<p>Status: {orderConfirmation.orderStatus}</p>
<p>Total: {orderConfirmation.orderTotal}</p>
</div>
);
}
// Render checkout form
return (
<form onSubmit={handleSubmit} className="checkout-form">
<h2>Guest Checkout</h2>
{error && <div className="error-message">{error}</div>}
<div className="form-section">
<h3>Contact Information</h3>
<div className="form-group">
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleInputChange}
required
/>
</div>
<div className="form-row">
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<input
type="text"
id="firstName"
name="firstName"
value={formData.firstName}
onChange={handleInputChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<input
type="text"
id="lastName"
name="lastName"
value={formData.lastName}
onChange={handleInputChange}
required
/>
</div>
</div>
</div>
<div className="form-section">
<h3>Billing Address</h3>
<div className="form-group">
<label htmlFor="billingLine1">Address</label>
<input
type="text"
id="billingLine1"
name="billingLine1"
value={formData.billingLine1}
onChange={handleInputChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="billingCity">City</label>
<input
type="text"
id="billingCity"
name="billingCity"
value={formData.billingCity}
onChange={handleInputChange}
required
/>
</div>
<div className="form-row">
<div className="form-group">
<label htmlFor="billingPostcode">Postal Code</label>
<input
type="text"
id="billingPostcode"
name="billingPostcode"
value={formData.billingPostcode}
onChange={handleInputChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="billingCountry">Country</label>
<input
type="text"
id="billingCountry"
name="billingCountry"
value={formData.billingCountry}
onChange={handleInputChange}
required
/>
</div>
</div>
</div>
<div className="form-group checkbox">
<input
type="checkbox"
id="sameAsShipping"
name="sameAsShipping"
checked={formData.sameAsShipping}
onChange={handleInputChange}
/>
<label htmlFor="sameAsShipping">Shipping address same as billing</label>
</div>
{!formData.sameAsShipping && (
<div className="form-section">
<h3>Shipping Address</h3>
<div className="form-group">
<label htmlFor="shippingLine1">Address</label>
<input
type="text"
id="shippingLine1"
name="shippingLine1"
value={formData.shippingLine1}
onChange={handleInputChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="shippingCity">City</label>
<input
type="text"
id="shippingCity"
name="shippingCity"
value={formData.shippingCity}
onChange={handleInputChange}
required
/>
</div>
<div className="form-row">
<div className="form-group">
<label htmlFor="shippingPostcode">Postal Code</label>
<input
type="text"
id="shippingPostcode"
name="shippingPostcode"
value={formData.shippingPostcode}
onChange={handleInputChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="shippingCountry">Country</label>
<input
type="text"
id="shippingCountry"
name="shippingCountry"
value={formData.shippingCountry}
onChange={handleInputChange}
required
/>
</div>
</div>
</div>
)}
<button type="submit" disabled={loading} className="checkout-button">
{loading ? "Processing..." : "Complete Checkout"}
</button>
</form>
);
}
export default GuestCheckout;