Coins: 17,432
Exchanges: 1,291
Market Cap: $3.446T 2.2%
24h Vol: $116.468B
Gas: 0.624 GWEI
Go Ad-free
API
TABLE OF CONTENTS

How to Build a Crypto Tax Calculator (React Guide)

4.1
| by
Rollend Xavier
|
Edited by
Julia Ng
-

Calculating taxes on cryptocurrency transactions can be complex due to market volatility and various taxable events. In this article, we'll guide you through building a simple crypto tax calculator using React and the CoinGecko API. Our focus will be on basic tax structures, providing a foundation that you can adapt to your local regulations. This tutorial will cover:

  1. User Inputs: Fields for entering required details for our calculation.
  2. Calculation Logic: Functions to compute capital gains or losses and the corresponding tax.
  3. Responsive Design: A user-friendly interface built with React and styled components.
  4. Real-Time Results: Instant calculation and display of tax obligations based on user input.

By the end, you'll have a functional application to help manage your crypto taxes. Let's jump in!


Crypto Tax Calculator - CoinGecko API

Prerequisites

Before you start, make sure you have the following:

Basic Knowledge of JavaScript and React
Familiarity with JavaScript ES6+ features and basic React concepts such as components, hooks (useState, useEffect), and state management will be helpful.

CoinGecko API
We will use the CoinGecko API to fetch market data for cryptocurrencies. With a rate limit of 30 calls per minute and a monthly cap of 10,000 calls, the free Demo plan is sufficient for our needs. Check out our API documentation or create a Demo account to try it out!

Text Editor or Integrated Development Environment (IDE)
You will need a code editor to write your application – we will be using Visual Studio Code. Other popular choices include Sublime Text and Atom.

Development Environment:Node.js and npm
Ensure that Node.js and npm are installed on your machine. Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine, and npm is the package manager for Node.js, which you'll use to manage your project's dependencies.

Set Up Your Project

First, create a new directory for your Tax Calculator App. Open your terminal or command prompt and run the following command to create a new directory:

mkdir crypto-tax-calculator
cd crypto-tax-calculator 

To set up a new React project, we'll use Vite, a fast-build tool that provides a leaner and quicker development experience compared to traditional tools. Vite leverages native ES modules and modern browser features for rapid development and optimized builds. To create the project, run the following command in your terminal:

npm create vite@latest .

The above command will create a new React project in the current directory.

Install Required Libraries

Our application will use several libraries:

  • Axios: For making API requests.
  • Moment.js: For date manipulation.
  • Styled-Components: For writing CSS in JavaScript to style your React components.

To install these libraries, run the following command in your project directory:

npm install axios moment styled-components

Folder and File Structure

crypto-tax-calculator/
├── node_modules/
├── public/
│   └── vite.svg
├── src/
│   ├──api/
│   │  └──coingecko.jsx
│   ├──components/
│   │  └──Calculator/
│   │      └──Calculator.jsx/
│   ├── App.css
│   ├── App.jsx
│   └── main.jsx
├── .gitignore
├── .eslintrc.cjs
├── index.html
├── package.json
├── README.md
├── vite.config.js
└── yarn.lock (or package-lock.json)

  • src/: This is the main source code directory where all the development happens.
  • api/: This directory contains all our API calls.
  • components/: This directory typically holds React components. In this case, there's a Calculator/ directory, which might contain a Calculator.jsx file representing a React component related to calculating crypto taxes.
  • App.css, App.jsx, main.jsx: These files are part of the React application structure.
  • App.css: CSS file for styling the main App component.
  • App.jsx: Main React component file where the application structure begins.
  • main.jsx: Entry point for the React application, typically imports App.jsx and renders the root component.

How to Build a Crypto Tax Calculator (Complete Code)

Here's the complete code for the Crypto Tax Calculator component:

import React, { useState, useEffect } from "react";
import styled from "styled-components";
import { fetchCryptoCoins, fetchCryptoPriceHistory } from "../../api/coingecko";

const CalculatorContainer = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
  max-width: 500px;
  margin: auto;
  border: 1px solid #ccc;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  background-color: #f9f9f9;
`;

const Title = styled.h1`
  font-size: 2em;
  margin-bottom: 20px;
`;

const Label = styled.label`
  display: flex;
  flex-direction: column;
  margin-bottom: 10px;
  width: 100%;
`;

const Input = styled.input`
  padding: 10px;
  margin-top: 5px;
  border: 1px solid #ccc;
  border-radius: 5px;
  font-size: 1em;
`;

const Select = styled.select`
  padding: 10px;
  margin-top: 5px;
  border: 1px solid #ccc;
  border-radius: 5px;
  font-size: 1em;
`;

const Result = styled.h2`
  margin-top: 20px;
  font-size: 1.5em;
`;

const Calculator = () => {
  const [buyDate, setBuyDate] = useState("");
  const [sellDate, setSellDate] = useState("");
  const [fees, setFees] = useState(0);
  const [annualIncome, setAnnualIncome] = useState(0);
  const [totalGainOrLoss, setTotalGainOrLoss] = useState(0);
  const [taxRate, setTaxRate] = useState(0);
  const [totalCapitalGainsTax, setTotalCapitalGainsTax] = useState(0);
  const [taxOwed, setTaxOwed] = useState(0);
  const [coins, setCoins] = useState([]);
  const [selectedCoin, setSelectedCoin] = useState({});
  const [historicalPrices, setHistoricalPrices] = useState({
    buyPrice: 0,
    sellPrice: 0,
  });
  const [buyQuantity, setBuyQuantity] = useState(0);
  const [sellQuantity, setSellQuantity] = useState(0);

  useEffect(() => {
    const fetchCryptoAssets = async () => {
      try {
        const response = await fetchCryptoCoins();
        if (response) {
          setCoins(response);
          setSelectedCoin(response[0]); // Default to the first asset
        } else {
          throw new Error("Failed to fetch crypto assets");
        }
      } catch (error) {
        console.error("Error fetching crypto assets:", error);
      }
    };
    fetchCryptoAssets();
  }, []);

  useEffect(() => {
    const fetchHistoricalPrices = async () => {
      if (!selectedCoin.id || !buyDate || !sellDate) return;

      try {
        const buyPriceResponse = await fetchCryptoPriceHistory(
          selectedCoin.id,
          buyDate
        );
        const sellPriceResponse = await fetchCryptoPriceHistory(
          selectedCoin.id,
          sellDate
        );

        if (buyPriceResponse && sellPriceResponse) {
          setHistoricalPrices({
            buyPrice: buyPriceResponse.market_data.current_price.usd,
            sellPrice: sellPriceResponse.market_data.current_price.usd,
          });
        } else {
          throw new Error("Failed to fetch historical prices");
        }
      } catch (error) {
        console.error("Error fetching historical prices:", error);
      }
    };

    fetchHistoricalPrices();
  }, [selectedCoin, buyDate, sellDate]);

  useEffect(() => {
    calculateGainLoss();
  }, [historicalPrices, fees, buyQuantity, sellQuantity]);

  useEffect(() => {
    calculateTax();
  }, [totalGainOrLoss, annualIncome, taxRate]);

  const calculateGainLoss = () => {
    const { buyPrice, sellPrice } = historicalPrices;
    if (!buyPrice || !sellPrice || buyQuantity <= 0 || sellQuantity <= 0) {
      setTotalGainOrLoss(0);
      return;
    }

    const buyTotal = buyPrice * buyQuantity;
    const sellTotal = sellPrice * sellQuantity;
    const gainLoss = sellTotal - buyTotal - fees;

    setTotalGainOrLoss(parseFloat(gainLoss.toFixed(2)));
  };

  const calculateTax = () => {
    if (totalGainOrLoss <= 0) {
      setTotalCapitalGainsTax(0);
      setTaxOwed(0);
      return;
    }

    let taxPercentage = 0;
    if (annualIncome > 18200) {
      taxPercentage = 19;
      if (annualIncome > 45001) {
        taxPercentage = 32.5;
      }
      if (annualIncome > 120001) {
        taxPercentage = 37;
      }
      if (annualIncome > 180001) {
        taxPercentage = 45;
      }
    }

    setTaxRate(taxPercentage);

    let totalTax = (totalGainOrLoss * taxPercentage) / 100;
    setTotalCapitalGainsTax(parseFloat(totalTax.toFixed(2)));

    // Assume some deductions or adjustments for simplicity
    const deductions = 1000; // Example deduction
    const adjustedTax = totalTax - deductions;
    setTaxOwed(Math.max(0, adjustedTax.toFixed(2))); // Tax owed can't be negative
  };

  const handleAssetChange = (e) => {
    const selectedCoinId = e.target.value;
    const selectedCoinData = coins.find((coin) => coin.id === selectedCoinId);
    setSelectedCoin(selectedCoinData || {});
  };

  const handleBuyDateChange = (e) => {
    setBuyDate(e.target.value);
  };

  const handleSellDateChange = (e) => {
    setSellDate(e.target.value);
  };

  const handleBuyQuantityChange = (e) => {
    setBuyQuantity(e.target.value);
  };

  const handleSellQuantityChange = (e) => {
    setSellQuantity(e.target.value);
  };

  return (
    <CalculatorContainer>
      <Title>Crypto Tax Calculator</Title>
      <Label>
        Select Asset:
        <Select value={selectedCoin.id} onChange={handleAssetChange}>
          {coins.map((asset) => (
            <option key={asset.id} value={asset.id}>
              {asset.name}
            </option>
          ))}
        </Select>
      </Label>
      {selectedCoin.current_price && (
        <Result>Current Price: ${selectedCoin.current_price}</Result>
      )}
      <Label>
        Buy Date:
        <Input
          type="date"
          value={buyDate}
          onChange={handleBuyDateChange}
          placeholder="Buy Date"
        />
      </Label>
      <Label>
        Sell Date:
        <Input
          type="date"
          value={sellDate}
          onChange={handleSellDateChange}
          placeholder="Sell Date"
        />
      </Label>
      <Label>
        Buy Quantity:
        <Input
          type="number"
          min={0}
          value={buyQuantity}
          onChange={handleBuyQuantityChange}
          placeholder="Buy Quantity"
        />
      </Label>
      <Label>
        Sell Quantity:
        <Input
          type="number"
          min={0}
          value={sellQuantity}
          onChange={handleSellQuantityChange}
          placeholder="Sell Quantity"
        />
      </Label>
      <Label>
        Annual Income:
        <Input
          type="number"
          min={0}
          value={annualIncome}
          onChange={(e) => setAnnualIncome(e.target.value)}
          placeholder="Annual Income"
        />
      </Label>
      <Label>
        Fees:
        <Input
          type="number"
          min={0}
          value={fees}
          onChange={(e) => setFees(e.target.value)}
          placeholder="Fees"
        />
      </Label>
      <Result>Total Gain or Loss: ${totalGainOrLoss}</Result>
      <Result>Tax Rate: {taxRate}%</Result>
      <Result>Total Capital Gains Tax You Will Pay: ${totalCapitalGainsTax}</Result>
      <Result>Tax Owed: ${taxOwed}</Result>
    </CalculatorContainer>
  );
};

export default Calculator;

This code block contains the main logic and UI for our Crypto Tax Calculator application. Here’s a break down of how it works:

1. Importing Required Libraries

  • React and Hooks: We import React components and hooks (useState, useEffect). 
  • Styled-Components: Used for styling our components.
  • API Helpers: fetchCryptoCoins and fetchCryptoPriceHistory are functions to fetch data from the CoinGecko API.

2. Styling the Components

  • CalculatorContainer: This sets up the main layout of the calculator with flexbox, padding, and other styling properties to center the content and give it a neat appearance.
  • Title, Label, Input, Select, Result: These styled-components are used to style various parts of the UI such as the title, labels, inputs, select dropdown, and result displays.

3. Setting Up State Variables
We use useState to manage different states such as:

  • buyDate, sellDate: Dates for buying and selling.
  • fees, annualIncome: Fees and annual income inputs.
  • totalGainOrLoss, taxRate, totalCapitalGainsTax, taxOwed: Calculated results.
  • coins, selectedCoin, historicalPrices: Crypto asset data and historical prices.
  • buyQuantity, sellQuantity: Quantities for buying and selling.

4. Fetching Crypto Assets

  • useEffect: Used to fetch the list of crypto assets when the component mounts using fetchCryptoCoins.
  • The fetched assets are stored in the coins state and the first asset is set as the default selectedCoin.

5. Fetching Historical Prices

  • useEffect: This fetches the historical prices for the selected coin on the specified buy and sell dates using fetchCryptoPriceHistory.
  • The fetched prices are stored in the historicalPrices state.

6. Calculating Gain or Loss

  • calculateGainLoss: This function calculates the total gain or loss based on the historical buy and sell prices, quantities, and fees. It updates the totalGainOrLoss state.

7. Calculating Tax

  • calculateTax: This function calculates the tax rate based on the annual income and applies it to the total gain or loss to determine the total capital gains tax and the tax owed. It updates the taxRate, totalCapitalGainsTax, and taxOwed states.

8. Handling User Input

  • handleAssetChange, handleBuyDateChange, handleSellDateChange, handleBuyQuantityChange, handleSellQuantityChange: These functions update the respective states based on user input.

9. Rendering the UI

  • The return statement renders the calculator UI, including the title, input fields, and results, all styled appropriately.

This component is located in the components folder of our application and represents the main code block containing our logic and UI for this application.

API Helper Functions

The following code contains our API helper functions which are essential for fetching cryptocurrency data from the CoinGecko API. These functions are located in the api/coingecko.js file.

import axios from "axios";
import moment from "moment";

const COINGECKO_API_URL = "https://pro-api.coingecko.com/api/v3";
const API_KEY = "YOUR_API_KEY";

export const fetchCryptoPriceHistory = async (id, date) => {
  const formattedDateString = moment(date, "YYYY-MM-DD").format("DD-MM-YYYY");

  try {
    const response = await axios.get(
      `${COINGECKO_API_URL}/coins/${id}/history?date=${formattedDateString}`,
      {
        headers: {
          "x-cg-pro-api-key": API_KEY,
        },
      }
    );
    return response.data;
  } catch (error) {
    console.error("Error fetching crypto prices", error);
    throw error;
  }
};

export const fetchCryptoCoins = async () => {
  try {
    const response = await axios.get(`${COINGECKO_API_URL}/coins/markets?vs_currency=usd`, {
      headers: {
        "x-cg-pro-api-key": YOUR_API_KEY,
      },
    });
    return response.data;
  } catch (error) {
    console.error("Error fetching crypto prices", error);
    throw error;
  }
};

This file contains two main functions that interact with the CoinGecko API to retrieve necessary data for our Crypto Tax Calculator:

1. Setting Up Axios and Moment.js

  • Axios: A promise-based HTTP client used to make requests to the CoinGecko API.
  • moment: A library used to format dates, ensuring that the date format is compatible with the CoinGecko API.

2. API URL and Key

  • COINGECKO_API_URL: Base URL for the CoinGecko API.
  • API_KEY: Your API key for accessing the CoinGecko API. Make sure to replace "YOUR_API_KEY" with your actual API key.

3. fetchCryptoPriceHistory

This function fetches the historical price of a specific cryptocurrency on a given date.

Parameters:

  • id: The ID of the cryptocurrency.
  • date: The date for which to fetch the historical price, formatted as "YYYY-MM-DD".

Process:   

  • Format the date to DD-MM-YYYY using moment.
  • Makes a GET request to the /coins/{id}/history endpoint with the formatted date.
  • Returns the response data containing historical price information.
  • Catches and logs any errors that occur during the request.

4. fetchCryptoCoins

This function fetches a list of available cryptocurrencies and their current market data.

Process:

  • Makes a GET request to the /coins/markets endpoint with the query parameter vs_currency=usd to get the current market data in USD.
  • Returns the response data containing the list of cryptocurrencies.
  • Catches and logs any errors that occur during the request.

Run The Application

To run the application, follow these steps in your root directory:

Install Dependencies: Use the following command to install all dependencies:

npm install  

Run the Application: Once dependencies are installed, start the application with:

npm run dev

View the Application: Open your browser and navigate to http://localhost:5173 to see the application running.

Calculate Tax

To calculate the tax, follow these steps:

Select Crypto Asset: Select a cryptocurrency in the dropdown.

  • Enter Buy Date: Enter the date when you purchased the cryptocurrency.
  • Enter Sell Date: Enter the date when you sell the cryptocurrency.
  • Enter Buy Quantity: Enter your buy quantity.
  • Enter Sell Quantity: Enter your sell quantity.
  • Enter Fee: Input the fee for the particular transaction.
  • Enter Annual Income: Input your annual income to account for tax calculations.
     

Once you've entered these details, the application will display:

  • Total Gain or Loss: The net profit or loss from your cryptocurrency transaction, considering the buy price, sell price, and any associated fees.
  • Tax Owed: The total capital gains tax you need to pay based on your gain or loss and annual income, calculated using progressive tax rates.
     

This will provide a comprehensive overview of your financial position regarding cryptocurrency transactions and the taxes applicable.

Crypto Tax Calculator React UI

Potential Enhancements

To further enhance the utility of this application, consider the following:

Integration with Cryptocurrency Exchanges: By connecting the application with cryptocurrency exchange APIs, users can automatically import their transaction data. This would streamline the process and reduce the potential for manual input errors, providing more precise calculations.

Multi-Currency Support: Adding support for multiple cryptocurrencies and fiat currencies would make the calculator more versatile for global users, allowing them to handle transactions in various currencies seamlessly.

Adapting to Global Tax Structures: Enhancing your Crypto Tax Calculator with a tax API, such as Taxrates.io as an example, could allow it to cater to the specific tax structures of different countries. This would make the calculator more accurate and globally applicable, providing a comprehensive solution for users worldwide.

User Accounts and Data Storage: Allowing users to create accounts and store their transaction histories securely would enable ongoing tracking of their portfolio and tax calculations over multiple tax years.

These enhancements would significantly improve the application's functionality and user experience.

Coinmarketcap API alternative

Conclusion

In this article, we walked through the process of building a comprehensive cryptocurrency tax calculator. This tool helps users accurately calculate their capital gains and tax liabilities from cryptocurrency transactions. We utilized modern web development tools and frameworks, including React and Vite, to create a robust and efficient application.

The calculator allows users to input their buy price, sell price, and annual income. It then computes the net gain or loss from their transactions and applies the appropriate tax rates to determine the tax owed. By leveraging React hooks and styled-components, we created an intuitive and responsive user interface that enhances the user experience.

Overall, this cryptocurrency tax calculator serves as a valuable tool for investors, providing clear and immediate insights into their financial positions and tax obligations.


Looking for similar coding tutorials? Browse our full library of API learning resources.

CoinGecko's Content Editorial Guidelines
CoinGecko’s content aims to demystify the crypto industry. While certain posts you see may be sponsored, we strive to uphold the highest standards of editorial quality and integrity, and do not publish any content that has not been vetted by our editors.
Learn more
Want to be the first to know about upcoming airdrops?
Subscribe to the CoinGecko Daily Newsletter!
Join 600,000+ crypto enthusiasts, traders, and degens in getting the latest crypto news, articles, videos, and reports by subscribing to our FREE newsletter.
Tell us how much you like this article!
Vote count: 9
Rollend Xavier
Rollend Xavier
Rollend is a Microsoft Certified Cloud Architect with 16 years of experience. He is the author of the book “Automate Your Life: Streamline Your Daily Tasks with Python: 30 Powerful Ways to Streamline Your Daily Tasks with Python”. Follow the author on Twitter @RollendXavier

Related Articles

Select Currency
Suggested Currencies
USD
US Dollar
IDR
Indonesian Rupiah
TWD
New Taiwan Dollar
EUR
Euro
KRW
South Korean Won
JPY
Japanese Yen
RUB
Russian Ruble
CNY
Chinese Yuan
Fiat Currencies
AED
United Arab Emirates Dirham
ARS
Argentine Peso
AUD
Australian Dollar
BDT
Bangladeshi Taka
BHD
Bahraini Dinar
BMD
Bermudian Dollar
BRL
Brazil Real
CAD
Canadian Dollar
CHF
Swiss Franc
CLP
Chilean Peso
CZK
Czech Koruna
DKK
Danish Krone
GBP
British Pound Sterling
GEL
Georgian Lari
HKD
Hong Kong Dollar
HUF
Hungarian Forint
ILS
Israeli New Shekel
INR
Indian Rupee
KWD
Kuwaiti Dinar
LKR
Sri Lankan Rupee
MMK
Burmese Kyat
MXN
Mexican Peso
MYR
Malaysian Ringgit
NGN
Nigerian Naira
NOK
Norwegian Krone
NZD
New Zealand Dollar
PHP
Philippine Peso
PKR
Pakistani Rupee
PLN
Polish Zloty
SAR
Saudi Riyal
SEK
Swedish Krona
SGD
Singapore Dollar
THB
Thai Baht
TRY
Turkish Lira
UAH
Ukrainian hryvnia
VEF
Venezuelan bolívar fuerte
VND
Vietnamese đồng
ZAR
South African Rand
XDR
IMF Special Drawing Rights
Cryptocurrencies
BTC
Bitcoin
ETH
Ether
LTC
Litecoin
BCH
Bitcoin Cash
BNB
Binance Coin
EOS
EOS
XRP
XRP
XLM
Lumens
LINK
Chainlink
DOT
Polkadot
YFI
Yearn.finance
Bitcoin Units
BITS
Bits
SATS
Satoshi
Commodities
XAG
Silver - Troy Ounce
XAU
Gold - Troy Ounce
Select Language
Popular Languages
EN
English
RU
Русский
DE
Deutsch
PL
język polski
ES
Español
VI
Tiếng việt
FR
Français
PT
Português
All Languages
AR
العربية
BG
български
CS
čeština
DA
dansk
EL
Ελληνικά
FI
suomen kieli
HE
עִבְרִית
HI
हिंदी
HR
hrvatski
HU
Magyar nyelv
ID
Bahasa Indonesia
IT
Italiano
JA
日本語
KO
한국어
LT
lietuvių kalba
NL
Nederlands
NO
norsk
RO
Limba română
SK
slovenský jazyk
SL
slovenski jezik
SV
Svenska
TH
ภาษาไทย
TR
Türkçe
UK
украї́нська мо́ва
ZH
简体中文
ZH-TW
繁體中文
Welcome to CoinGecko
Welcome back!
Login or Sign up in seconds
or
Sign in with . Not you?
Forgot your password?
Didn't receive confirmation instructions?
Resend confirmation instructions
Password must contain at least 8 characters including 1 uppercase letter, 1 lowercase letter, 1 number, and 1 special character
By continuing, you acknowledge that you've read and agree fully to our Terms of Service and Privacy Policy.
Forgot your password?
You will receive an email with instructions on how to reset your password in a few minutes.
Resend confirmation instructions
You will receive an email with instructions for how to confirm your email address in a few minutes.
Get the CoinGecko app.
Scan this QR code to download the app now App QR Code Or check it out in the app stores
coingecko
Continue in app
Track prices in real-time
Open App