


Commit 3c90066
Before you read any further, just as an FYI, I learn and code on my own to build what we need to run our business. So, please take the following information as is. It's a real world example we used for our own ? yellow book about coworking. At the time we couldn't find a better solution, so I build the following for our eCommerce website.
Selling a single product online, like a book, can be straightforward until you encounter the complexities of international shipping rates, multiple currencies, and varying quantities—especially since Stripe Checkout allows for only one shipping rate by default. In this article, let's walk through how we built a custom shipping calculator using Netlify Functions and Stripe to handle these challenges. By the end, you'll have a working solution tailored for selling up to three copies of a book, with dynamic shipping costs based on the customer's currency (EUR/USD), quantity, and location.
While this example is very specific to our needs, you can tweak it to suit your own requirements. Please feel free to share your solutions, upgrades, or any improvements you make.
? Prerequisites
Before we dive in, make sure you have the following:
- A Netlify account with a deployed site.
- A Stripe account with test and live API keys.
- Basic understanding of HTML, JavaScript, and serverless functions.
- Familiarity with environment variables.
? Overview
Let's create a seamless checkout experience that:
- Determines shipping costs based on the customer's currency, number of items, and location.
- Supports both EUR and USD currencies.
- Handles different shipping rates for European and worldwide destinations.
- Integrates seamlessly with Stripe Checkout.
Bellow I will cover both the frontend (HTML and JavaScript) and the backend (Netlify Function) components.
? Project Structure
Project should include the following folders and files:
/functions - create-checkout-session.js /index.html .env netlify.toml package.json
- /functions: Directory for Netlify Functions.
- create-checkout-session.js: The custom serverless function.
- index.html: The frontend HTML file.
- .env: File to store environment variables
- netlify.toml: The configuration file for Netlify.
- package.json: Lists dependencies like stripe.
?️ Setting Up the Backend (Netlify Function)
Create a new file in your /functions directory named create-checkout-session.js.
/functions - create-checkout-session.js /index.html .env netlify.toml package.json
? Code Breakdown
Importing Stripe
// functions/create-checkout-session.js // Add Stripe secret key const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); exports.handler = async (event) => { // Parse the order data sent from the frontend const order = JSON.parse(event.body); // Define country groups const euCountries = ['AL', 'AM', 'AT', ...]; // Add the EU countries you ship to const worldCountries = ['AE', 'AR', 'AU', ...]; // Add worldwide countries you ship to let allowedCountries = []; // Payment methods based on currency let paymentMethods = []; // Determine shipping rates and allowed countries if (order.currency === 'EUR') { paymentMethods = ['card', 'sepa_debit', 'ideal', 'bancontact', 'p24', 'eps', 'giropay', 'sofort']; if (order.shippingOption === 'europe-eur') { allowedCountries = euCountries; // Set shipping rate IDs for Europe in EUR order.shippingRate = process.env[`SHIPPING_RATE_EUR_EU_${order.items}`]; } else if (order.shippingOption === 'world-eur') { allowedCountries = worldCountries; // Set shipping rate IDs for World in EUR order.shippingRate = process.env[`SHIPPING_RATE_EUR_W_${order.items}`]; } } else if (order.currency === 'USD') { paymentMethods = ['card']; if (order.shippingOption === 'europe-usd') { allowedCountries = euCountries; // Set shipping rate IDs for Europe in USD order.shippingRate = process.env[`SHIPPING_RATE_USD_EU_${order.items}`]; } else if (order.shippingOption === 'world-usd') { allowedCountries = worldCountries; // Set shipping rate IDs for World in USD order.shippingRate = process.env[`SHIPPING_RATE_USD_W_${order.items}`]; } } // Create the Stripe Checkout session const session = await stripe.checkout.sessions.create({ payment_method_types: paymentMethods, line_items: [ { price: order.priceId, // The price ID of your product quantity: order.items, }, ], mode: 'payment', billing_address_collection: 'auto', shipping_rates: [order.shippingRate], shipping_address_collection: { allowed_countries: allowedCountries, }, success_url: `${process.env.URL}/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${process.env.URL}/cancel`, }); return { statusCode: 200, body: JSON.stringify({ sessionId: session.id, publishableKey: process.env.STRIPE_PUBLISHABLE_KEY, }), }; };
Initializes the Stripe SDK with your secret key.
Handling the Event
Pars the incoming order data from the frontend.
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
Defining Country Groups
exports.handler = async (event) => { const order = JSON.parse(event.body); // Rest of the code... };
- Lists of countries for EU and worldwide shipping.
- allowedCountries will be set based on the shipping option.
Setting Payment Methods
Determine the available payment methods based on the currency.
const euCountries = [/* ... */]; const worldCountries = [/* ... */]; let allowedCountries = [];
Determining Shipping Rates
let paymentMethods = [];
- Uses environment variables to set the correct shipping rate ID based on currency, region, and quantity.
- Example environment variable: SHIPPING_RATE_EUR_EU_1 for 1 item in Europe with EUR currency.
Creating the Checkout Session
if (order.currency === 'EUR') { paymentMethods = [/* ... */]; if (order.shippingOption === 'europe-eur') { allowedCountries = euCountries; order.shippingRate = process.env[`SHIPPING_RATE_EUR_EU_${order.items}`]; } else if (order.shippingOption === 'world-eur') { allowedCountries = worldCountries; order.shippingRate = process.env[`SHIPPING_RATE_EUR_W_${order.items}`]; } } else if (order.currency === 'USD') { // Similar logic for USD }
- Creates a new Stripe Checkout session with dynamic configurations.
?️ Setting Up the Frontend
Below is a shortened example of the HTML and JavaScript code that interacts with our Netlify Function.
? HTML Structure (index.html)
const session = await stripe.checkout.sessions.create({ payment_method_types: paymentMethods, line_items: [/* ... */], mode: 'payment', billing_address_collection: 'auto', shipping_rates: [order.shippingRate], shipping_address_collection: { allowed_countries: allowedCountries, }, success_url: `${process.env.URL}/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${process.env.URL}/cancel`, });
? HTML Breakdown
- Currency Tabs: Allows users to select between EUR and USD pricing.
- Number of Books: Users can select up to three books.
- Shipping Destination: Dropdowns populated with countries, grouped by shipping rates.
- Checkout Buttons: Initiates the checkout process when clicked.
? JavaScript Logic (script.js)
<meta charset="UTF-8"> <title>Book Pre-Order</title> <!-- Include any CSS or Meta tags here --> <!-- Book Purchase Section --> <section id="pricing"> <div class="pricing-content"> <!-- Currency Tabs --> <ul class="tabs-menu"> <li id="active_currency_eur" class="current"><a href="#tab-1">Buy in ?? EUR</a></li> <li id="active_currency"><a href="#tab-2">Buy in ?? USD</a></li> </ul> <!-- EUR Tab Content --> <div id="tab-1" class="tab-content"> <h3 id="Print-Book">1 Print Book</h3> <p>A beautiful, 350 pages book.</p> <p>Price: <span id="book-price-eur">€95</span></p> <!-- Number of Books --> <label for="num-books">Number of Books (Max 3)</label> <select name="num-books" id="num-books" required> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <!-- Shipping Destination --> <label for="shipping-amount-eur">Select Shipping Destination</label> <select name="shipping-amount" id="shipping-amount-eur" required> <optgroup label="Europe €14"> <option value="europe-eur">Austria</option> <option value="europe-eur">Belgium</option> <!-- Add other European countries --> </optgroup> <optgroup label="Worldwide €22"> <option value="world-eur">United States</option> <option value="world-eur">Canada</option> <!-- Add other worldwide countries --> </optgroup> </select> <!-- Checkout Button --> <button id="checkout-button-eur" type="button">PRE-ORDER</button> </div> <!-- USD Tab Content --> <div id="tab-2" class="tab-content"> <h3 id="Print-Book">1 Print Book</h3> <p>A beautiful, 350 pages book.</p> <p>Price: <span id="book-price-usd"></span></p> <!-- Number of Books --> <label for="num-books-usd">Number of Books (Max 3)</label> <select name="num-books-usd" id="num-books-usd" required> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <!-- Shipping Destination --> <label for="shipping-amount-usd">Select Shipping Destination</label> <select name="shipping-amount" id="shipping-amount-usd" required> <optgroup label="Europe "> <option value="europe-usd">Austria</option> <option value="europe-usd">Belgium</option> <!-- Add other European countries --> </optgroup> <optgroup label="Worldwide "> <option value="world-usd">United States</option> <option value="world-usd">Canada</option> <!-- Add other worldwide countries --> </optgroup> </select> <!-- Checkout Button --> <button id="checkout-button-usd" type="button">PRE-ORDER</button> </div> </div> </section> <!-- Include Stripe.js --> <script src="https://js.stripe.com/v3/"></script> <!-- Include your JavaScript file --> <script src="script.js"></script>
? JavaScript Breakdown
- Event Listeners: Attach click events to the checkout buttons.
- Determining Order Details: Based on the clicked button, extract the currency, shipping option, number of books, and price ID.
- Preparing Order Data: Create an object containing all necessary order information.
- Fetching the Checkout Session: Send a POST request to the Netlify Function with the order data.
- Redirecting to Stripe Checkout: Use the session ID returned from the backend to redirect the user to Stripe Checkout.
? Setting Environment Variables
Make sure to add your product and shipping prices on Stirpe Dashboard.
On Stripe:
On Netlify:
Create a .env file in the root of your project and add your environment variables(or do it on the Netlify UI as shown above Site configuration > Environment variables):
/functions - create-checkout-session.js /index.html .env netlify.toml package.json
- Replace the values with your actual Stripe keys and shipping rate IDs.
- Make sure to create these shipping rates in your Stripe dashboard.
? Updating netlify.toml
Configure Netlify to use environment variables in your functions:
// functions/create-checkout-session.js // Add Stripe secret key const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); exports.handler = async (event) => { // Parse the order data sent from the frontend const order = JSON.parse(event.body); // Define country groups const euCountries = ['AL', 'AM', 'AT', ...]; // Add the EU countries you ship to const worldCountries = ['AE', 'AR', 'AU', ...]; // Add worldwide countries you ship to let allowedCountries = []; // Payment methods based on currency let paymentMethods = []; // Determine shipping rates and allowed countries if (order.currency === 'EUR') { paymentMethods = ['card', 'sepa_debit', 'ideal', 'bancontact', 'p24', 'eps', 'giropay', 'sofort']; if (order.shippingOption === 'europe-eur') { allowedCountries = euCountries; // Set shipping rate IDs for Europe in EUR order.shippingRate = process.env[`SHIPPING_RATE_EUR_EU_${order.items}`]; } else if (order.shippingOption === 'world-eur') { allowedCountries = worldCountries; // Set shipping rate IDs for World in EUR order.shippingRate = process.env[`SHIPPING_RATE_EUR_W_${order.items}`]; } } else if (order.currency === 'USD') { paymentMethods = ['card']; if (order.shippingOption === 'europe-usd') { allowedCountries = euCountries; // Set shipping rate IDs for Europe in USD order.shippingRate = process.env[`SHIPPING_RATE_USD_EU_${order.items}`]; } else if (order.shippingOption === 'world-usd') { allowedCountries = worldCountries; // Set shipping rate IDs for World in USD order.shippingRate = process.env[`SHIPPING_RATE_USD_W_${order.items}`]; } } // Create the Stripe Checkout session const session = await stripe.checkout.sessions.create({ payment_method_types: paymentMethods, line_items: [ { price: order.priceId, // The price ID of your product quantity: order.items, }, ], mode: 'payment', billing_address_collection: 'auto', shipping_rates: [order.shippingRate], shipping_address_collection: { allowed_countries: allowedCountries, }, success_url: `${process.env.URL}/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${process.env.URL}/cancel`, }); return { statusCode: 200, body: JSON.stringify({ sessionId: session.id, publishableKey: process.env.STRIPE_PUBLISHABLE_KEY, }), }; };
? Installing Dependencies
Run the following command to install the Stripe SDK:
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
? Testing the Function
- Start Netlify Dev Server
exports.handler = async (event) => { const order = JSON.parse(event.body); // Rest of the code... };
- Place an Order
- Open your index.html file in the browser.
- Select your options and click the "PRE-ORDER" button.
- Ensure that the correct shipping rates and payment methods appear in the Stripe Checkout.
- Test Different Scenarios
- Switch between EUR and USD currencies.
- Change the shipping options and item quantities.
- Confirm that the allowed countries match your configurations.
? Conclusion
Et voilà! You've set up a custom shipping calculator function that dynamically adjusts shipping rates based on currency, quantity, and location.
Feel free to adapt and expand upon this setup to suit your own products and shipping policies.
? Additional Resources
- Stripe Checkout Documentation
- Netlify Functions Documentation
- Creating Shipping Rates in Stripe
- Stripe.js Reference
Note: This article is based on a real-world scenario for pre-ordering/selling a single book with up to three copies and demonstrates one way to handle shipping calculations involving currency, quantity, and location variables. There might be more efficient methods depending on your specific needs.
The above is the detailed content of Building a Custom Shipping Calculator with Stripe and Netlify Functions for Multi-Currency (€/$), Quantity, and Location Support. For more information, please follow other related articles on the PHP Chinese website!

The main difference between Python and JavaScript is the type system and application scenarios. 1. Python uses dynamic types, suitable for scientific computing and data analysis. 2. JavaScript adopts weak types and is widely used in front-end and full-stack development. The two have their own advantages in asynchronous programming and performance optimization, and should be decided according to project requirements when choosing.

Whether to choose Python or JavaScript depends on the project type: 1) Choose Python for data science and automation tasks; 2) Choose JavaScript for front-end and full-stack development. Python is favored for its powerful library in data processing and automation, while JavaScript is indispensable for its advantages in web interaction and full-stack development.

Python and JavaScript each have their own advantages, and the choice depends on project needs and personal preferences. 1. Python is easy to learn, with concise syntax, suitable for data science and back-end development, but has a slow execution speed. 2. JavaScript is everywhere in front-end development and has strong asynchronous programming capabilities. Node.js makes it suitable for full-stack development, but the syntax may be complex and error-prone.

JavaScriptisnotbuiltonCorC ;it'saninterpretedlanguagethatrunsonenginesoftenwritteninC .1)JavaScriptwasdesignedasalightweight,interpretedlanguageforwebbrowsers.2)EnginesevolvedfromsimpleinterpreterstoJITcompilers,typicallyinC ,improvingperformance.

JavaScript can be used for front-end and back-end development. The front-end enhances the user experience through DOM operations, and the back-end handles server tasks through Node.js. 1. Front-end example: Change the content of the web page text. 2. Backend example: Create a Node.js server.

Choosing Python or JavaScript should be based on career development, learning curve and ecosystem: 1) Career development: Python is suitable for data science and back-end development, while JavaScript is suitable for front-end and full-stack development. 2) Learning curve: Python syntax is concise and suitable for beginners; JavaScript syntax is flexible. 3) Ecosystem: Python has rich scientific computing libraries, and JavaScript has a powerful front-end framework.

The power of the JavaScript framework lies in simplifying development, improving user experience and application performance. When choosing a framework, consider: 1. Project size and complexity, 2. Team experience, 3. Ecosystem and community support.

Introduction I know you may find it strange, what exactly does JavaScript, C and browser have to do? They seem to be unrelated, but in fact, they play a very important role in modern web development. Today we will discuss the close connection between these three. Through this article, you will learn how JavaScript runs in the browser, the role of C in the browser engine, and how they work together to drive rendering and interaction of web pages. We all know the relationship between JavaScript and browser. JavaScript is the core language of front-end development. It runs directly in the browser, making web pages vivid and interesting. Have you ever wondered why JavaScr


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

VSCode Windows 64-bit Download
A free and powerful IDE editor launched by Microsoft

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

SublimeText3 Chinese version
Chinese version, very easy to use

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.
