Skip to main content

Calculate taxes on your frontend

This guide focuses on integrating Quaderno.js to calculate taxes on your frontend.

Including Quaderno.js

However you’re using Quaderno.js, you always begin by including the library and setting your public API key.

  <script src=""></script>

To get started, include this script on your pages — it should always be loaded directly from


Please note that we provide a differentiated publishable API key for Quaderno.js for security reasons. This public API key is different from your account's private API key, which should never be exposed on your frontend.

You can tell the difference by their naming:

  • private key starts with sk_, which stands for "secret key"
  • public key starts with pk_, which stands for "public key"

While the private API key is meant for being used server-side, secured in your backend, the public API key is only used by Quaderno.js, and only allow access to our tax calculations engine. No data can be leaked from your account with the public API key.

Calculating taxes

Next up we're showing an example of using Quaderno.js directly from your frontend. In the highlighted lines, we can see:

  • Use of the custom init method.
  • The most common use case of Quaderno.js: to calculate taxes, invoking the method Quaderno.calculateTaxes.
  • We'll also validate Tax IDs (e.g. VAT numbers) when given one, with Quaderno.validateBusinessNumber.

The rest of the code is handling UI updates on the relevant fields to force tax calculations and show it in a <span>.

<label for="country">
<select id="country">
<option value="US" selected>United States</option>
<option value="GB">United Kingdom</option>
<option value="DE">Germany</option>
<option value="FR">France</option>
<option value="IT">Italy</option>
<option value="ES">Spain</option>
<option value="CA">Canada</option>
<option value="AU">Australia</option>

<label for="postal-code">
Postal code
<input id="postal-code">

<label for="business-number">
Business number:
<input id="business-number">

<label for="tax-class">
Tax Code:
<select id="tax-class">
<option value="standard">standard</option>
<option value="eservice">eservice</option>
<option value="ebook">ebook</option>
<option value="saas">saas</option>

Taxes: <span id="tax-rate"></span>


// never expose your private API key on your frontend, use the public API key instead
let publishableKey = "pk_test_xxxxxxxxxxxxxxxxxxxx";
// we're not attaching Quaderno.js to our form, so we need to use init:
Quaderno.init(publishableKey).then(function() {
console.log('Quaderno.js successfully initialized');
}).catch(function(error) {
console.log(error.description, error.messages);

// this is a custom function to be called each time the user introduces new data
function reloadTaxes(options){
console.log("Calling calculateTaxes with params", options)
Quaderno.calculateTaxes(options).then(function(taxObject) {
// Remember, you need to be registered on the tax jurisdiction to get the tax rate
console.log("Taxes calculated:", taxObject)
document.querySelector('#tax-rate').innerHTML = + " " + taxObject.rate + "%"; // ie.: VAT 20%

// handle change events on the relevant user-inputs so that the Tax Rate it's automatically updated
document.querySelector('#country').addEventListener('change', function () {
country = this.value
postalCode = document.querySelector('#postal-code').value
businessNumber = document.querySelector('#business-number').value

reloadTaxes({ country: country, postalCode: postalCode, businessNumber: businessNumber})

document.querySelector('#postal-code').addEventListener('change', function () {
postalCode = this.value
country = document.querySelector('#country').value
businessNumber = document.querySelector('#business-number').value

reloadTaxes({ country: country, postalCode: postalCode, businessNumber: businessNumber })

document.querySelector('#business-number').addEventListener('change', function () {
businessNumber = this.value
country = document.querySelector('#country').value
postalCode = document.querySelector('#postal-code').value

// validates a Tax ID (e.g. VAT number) when given one
Quaderno.validateBusinessNumber(businessNumber, country).then(function(){
reloadTaxes({ businessNumber: businessNumber, country: country, postalCode: postalCode })

// collects the data that will be used as `options` for calculateTaxes
document.querySelector('#tax-class').addEventListener('change', function () {
taxClass = this.value
country = document.querySelector('#country').value
postalCode = document.querySelector('#postal-code').value
businessNumber = document.querySelector('#business-number').value

reloadTaxes({ taxClass: taxClass, country: country, postalCode: postalCode, businessNumber: businessNumber })

So, we're showing a form with different countries and tax codes (called taxClass in Quaderno.js).

Instead of using the super-simple approach of binding to your form by specifying a quaderno-payment-form id and a valid data-publishable-key, we're first initializing Quaderno.js with our public API key by using the custom init method.

Finally (line 88 onwards), we're collecting the data that will be used as options for calculateTaxes(options). This is done with document.querySelector('#value-id'), anytime these receive a change event from the DOM.

The result from calculateTaxes(options) is then updated on the UI. We're also validating the Tax ID (e.g. VAT number) with validateBusinessNumber when given one.


Note that we're not calling the performant getLastTax() method because in this case the data changes everytime. If you already got your tax rate and need that data again later in your checkout process, you may want to call calculateTaxes(options) once and after that rely on getLastTax().

Executing the example by selecting "United States" and introducing "7501" as postal code, the console prints:

Taxes calculated:
country: "US"
extraName: null
extraRate: null
name: "Sales tax"
rate: 6.25
region: "TX"