diff --git a/README.md b/README.md
index 46cbe21..850c1d8 100644
--- a/README.md
+++ b/README.md
@@ -19,35 +19,32 @@ pip install .
 
 ## Example use
 
-Return values are the JSON responses documented in the API: 
+Return values are from the JSON responses documented in the API: 
 https://pypistats.org/api/
 
 ```python
 import pypistats
 from pprint import pprint
 
-# Initialise the API
-api = pypistats.PyPiStats()
-
 # Call the API
-print(api.recent("pillow"))
-print(api.recent("pillow", "day", output="table"))
-pprint(api.recent("pillow", "week", output="json"))
-print(api.recent("pillow", "month"))
-
-print(api.overall("pillow"))
-print(api.overall("pillow", mirrors=True, output="table"))
-pprint(api.overall("pillow", mirrors=False, output="json"))
-
-print(api.python_major("pillow"))
-print(api.python_major("pillow", version=2, output="table"))
-pprint(api.python_major("pillow", version="3", output="json"))
-
-print(api.python_minor("pillow"))
-print(api.python_minor("pillow", version=2.7, output="table"))
-pprint(api.python_minor("pillow", version="3.7", output="json"))
-
-print(api.system("pillow"))
-print(api.system("pillow", os="darwin", output="table"))
-pprint(api.system("pillow", os="linux", output="json"))
+print(pypistats.recent("pillow"))
+print(pypistats.recent("pillow", "day", output="table"))
+pprint(pypistats.recent("pillow", "week", output="json"))
+print(pypistats.recent("pillow", "month"))
+
+print(pypistats.overall("pillow"))
+print(pypistats.overall("pillow", mirrors=True, output="table"))
+pprint(pypistats.overall("pillow", mirrors=False, output="json"))
+
+print(pypistats.python_major("pillow"))
+print(pypistats.python_major("pillow", version=2, output="table"))
+pprint(pypistats.python_major("pillow", version="3", output="json"))
+
+print(pypistats.python_minor("pillow"))
+print(pypistats.python_minor("pillow", version=2.7, output="table"))
+pprint(pypistats.python_minor("pillow", version="3.7", output="json"))
+
+print(pypistats.system("pillow"))
+print(pypistats.system("pillow", os="darwin", output="table"))
+pprint(pypistats.system("pillow", os="linux", output="json"))
 ```
diff --git a/pypistats/__init__.py b/pypistats/__init__.py
index 719f31a..9ebc7e6 100644
--- a/pypistats/__init__.py
+++ b/pypistats/__init__.py
@@ -46,10 +46,12 @@ def pypi_stats_api(
     if output == "json":
         return res
 
-    # Only sort for table
+    # These only for table
     if sort:
         res["data"] = _sort(res["data"])
 
+    res["data"] = _grand_total(res["data"])
+
     data = res["data"]
     return _tabulate(data)
 
@@ -76,7 +78,7 @@ def _filter(data, start_date=None, end_date=None):
 def _sort(data):
     """Sort by downloads"""
 
-    # Only sum lists of dicts, not a single dict
+    # Only for lists of dicts, not a single dict
     if isinstance(data, dict):
         return data
 
@@ -87,7 +89,7 @@ def _sort(data):
 def _total(data):
     """Sum all downloads per category, regardless of date"""
 
-    # Only sum lists of dicts, not a single dict
+    # Only for lists of dicts, not a single dict
     if isinstance(data, dict):
         return data
 
@@ -105,6 +107,20 @@ def _total(data):
     return data
 
 
+def _grand_total(data):
+    """Add a grand total row"""
+
+    # Only for lists of dicts, not a single dict
+    if isinstance(data, dict):
+        return data
+
+    grand_total = sum(row["downloads"] for row in data)
+    new_row = {"category": "Total", "downloads": grand_total}
+    data.append(new_row)
+
+    return data
+
+
 def _tabulate(data):
     """Return data in table"""
 

Add total row to tables
| category |  downloads  |
|----------|------------:|
|      2.7 |   1,594,594 |
|      2.6 |       1,968 |
|      3.3 |       1,824 |
|      3.2 |         244 |
|      3.1 |           3 |
| Total    |   1,598,633 |
diff --git a/tests/test_pypistats.py b/tests/test_pypistats.py
index cad9a90..1e3f8fe 100644
--- a/tests/test_pypistats.py
+++ b/tests/test_pypistats.py
@@ -3,9 +3,11 @@
 """
 Unit tests for pypistats
 """
+import copy
 import unittest
 
 import pypistats
+from data.python_minor import data as PYTHON_MINOR_DATA
 
 SAMPLE_DATA = [
     {"category": "2.6", "date": "2018-08-15", "downloads": 51},
@@ -24,7 +26,7 @@ SAMPLE_DATA = [
 class TestPypiStats(unittest.TestCase):
     def test__filter_no_filters_no_change(self):
         # Arrange
-        from data.python_minor import data
+        data = copy.deepcopy(PYTHON_MINOR_DATA)
 
         # Act
         output = pypistats._filter(data)
@@ -34,8 +36,7 @@ class TestPypiStats(unittest.TestCase):
 
     def test__filter_start_date(self):
         # Arrange
-        from data.python_minor import data
-
+        data = copy.deepcopy(PYTHON_MINOR_DATA)
         start_date = "2018-09-22"
 
         # Act
@@ -48,8 +49,7 @@ class TestPypiStats(unittest.TestCase):
 
     def test__filter_end_date(self):
         # Arrange
-        from data.python_minor import data
-
+        data = copy.deepcopy(PYTHON_MINOR_DATA)
         end_date = "2018-04-22"
 
         # Act
@@ -62,8 +62,7 @@ class TestPypiStats(unittest.TestCase):
 
     def test__filter_start_and_end_date(self):
         # Arrange
-        from data.python_minor import data
-
+        data = copy.deepcopy(PYTHON_MINOR_DATA)
         start_date = "2018-09-01"
         end_date = "2018-09-11"
 
@@ -184,7 +183,7 @@ class TestPypiStats(unittest.TestCase):
 
     def test__total(self):
         # Arrange
-        from data.python_minor import data
+        data = copy.deepcopy(PYTHON_MINOR_DATA)
 
         # Act
         output = pypistats._total(data)
@@ -203,3 +202,26 @@ class TestPypiStats(unittest.TestCase):
 
         # Assert
         self.assertEqual(output, data)
+
+    def test__grand_total(self):
+        # Arrange
+        data = copy.deepcopy(PYTHON_MINOR_DATA)
+        original_len = len(data)
+
+        # Act
+        output = pypistats._grand_total(data)
+
+        # Assert
+        self.assertEqual(len(output), original_len + 1)
+        self.assertEqual(output[-1]["category"], "Total")
+        self.assertEqual(output[-1]["downloads"], 9355317)
+
+    def test__grand_total_recent(self):
+        # Arrange
+        data = {"last_day": 123002, "last_month": 3254221, "last_week": 761649}
+
+        # Act
+        output = pypistats._grand_total(data)
+
+        # Assert
+        self.assertEqual(output, data)

pip install -e .
parse_log_pytest
pytest
flake8 freezegun pytest
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi==2025.1.31
chardet==5.2.0
charset-normalizer==3.4.1
DataProperty==1.1.0
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
flake8==7.2.0
freezegun==1.5.1
idna==3.10
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
mbstrdecoder==1.1.4
mccabe==0.7.0
packaging @ file:///croot/packaging_1734472117206/work
pathvalidate==3.2.3
pluggy @ file:///croot/pluggy_1733169602837/work
pycodestyle==2.13.0
pyflakes==3.3.2
-e git+https://github.com/hugovk/pypistats.git@785472f89297591317126f5ce95420c6d0b12205#egg=pypistats
pytablewriter==1.2.1
pytest @ file:///croot/pytest_1738938843180/work
python-dateutil==2.9.0.post0
pytz==2025.2
requests==2.32.3
six==1.17.0
tabledata==1.3.4
tcolorpy==0.1.7
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
typepy==1.3.4
urllib3==2.3.0

name: pypistats
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - certifi==2025.1.31
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - dataproperty==1.1.0
      - flake8==7.2.0
      - freezegun==1.5.1
      - idna==3.10
      - mbstrdecoder==1.1.4
      - mccabe==0.7.0
      - pathvalidate==3.2.3
      - pycodestyle==2.13.0
      - pyflakes==3.3.2
      - pytablewriter==1.2.1
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - requests==2.32.3
      - six==1.17.0
      - tabledata==1.3.4
      - tcolorpy==0.1.7
      - typepy==1.3.4
      - urllib3==2.3.0
prefix: /opt/conda/envs/pypistats

tests/test_pypistats.py::TestPypiStats::test__grand_total tests/test_pypistats.py::TestPypiStats::test__grand_total_recent
tests/test_pypistats.py::TestPypiStats::test__tabulate
tests/test_pypistats.py::TestPypiStats::test__filter_end_date tests/test_pypistats.py::TestPypiStats::test__filter_no_filters_no_change tests/test_pypistats.py::TestPypiStats::test__filter_start_and_end_date tests/test_pypistats.py::TestPypiStats::test__filter_start_date tests/test_pypistats.py::TestPypiStats::test__paramify_bool tests/test_pypistats.py::TestPypiStats::test__paramify_float tests/test_pypistats.py::TestPypiStats::test__paramify_int tests/test_pypistats.py::TestPypiStats::test__paramify_none tests/test_pypistats.py::TestPypiStats::test__paramify_string tests/test_pypistats.py::TestPypiStats::test__sort tests/test_pypistats.py::TestPypiStats::test__sort_recent tests/test_pypistats.py::TestPypiStats::test__total tests/test_pypistats.py::TestPypiStats::test__total_recent
pypistats/__init__.py README.md
pypistats/__init__.py README.md