


Building a Custom Shipping Calculator with Stripe and Netlify Functions for Multi-Currency (€/$), Quantity, and Location Support
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)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Book Pre-Order</title> <!-- Include any CSS or Meta tags here --> </head> <body> <!-- 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>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>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> </body> </html>
? 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!

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

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.
