diff --git a/conf.php-dist b/conf.php-dist
index 9dc2457d..148c121e 100644
--- a/conf.php-dist
+++ b/conf.php-dist
@@ -94,6 +94,14 @@ $config['baseMaps'] = array(
   ),
 );
 
+// customCategory needs a database
+$db_conf = [
+  //'dsn' => 'mysql:host=localhost;dbname=openstreetbrowser',
+  'dsn' => 'sqlite:data/db.sqlite',
+  'username' => 'USERNAME',
+  'password' => 'PASSWORD',
+];
+
 // List of available user interface languages
 $languages = array(
   "en", // English
diff --git a/init.sql b/init.sql
new file mode 100644
index 00000000..5476b34f
--- /dev/null
+++ b/init.sql
@@ -0,0 +1,7 @@
+create table customCategory (
+  id            char(32)        not null,
+  content       mediumtext      not null,
+  created       datetime        not null default CURRENT_TIMESTAMP,
+  lastAccess    datetime        not null default CURRENT_TIMESTAMP,
+  primary key(id)
+);
diff --git a/modulekit.php b/modulekit.php
index 6bbce73a..59b1d8e8 100644
--- a/modulekit.php
+++ b/modulekit.php
@@ -12,6 +12,7 @@ $depend = array(
 $include = array(
   'php' => array(
     'src/defaults.php',
+    'src/database.php',
     'src/options.php',
     'src/language.php',
     'src/ip-location.php',
@@ -22,6 +23,7 @@ $include = array(
     'src/RepositoryDir.php',
     'src/RepositoryGit.php',
     'src/repositories.php',
+    'src/customCategory.php',
   ),
   'css' => array(
     'style.css',
diff --git a/src/customCategory.js b/src/customCategory.js
index a2c830ff..d20e3a2d 100644
--- a/src/customCategory.js
+++ b/src/customCategory.js
@@ -38,6 +38,7 @@ class CustomCategory {
 
     input.onclick = () => {
       this.applyContent(this.textarea.value)
+      ajax('customCategory', { content: this.textarea.value }, (result) => {})
       return true
     }
   }
diff --git a/src/customCategory.php b/src/customCategory.php
new file mode 100644
index 00000000..cb3083ca
--- /dev/null
+++ b/src/customCategory.php
@@ -0,0 +1,39 @@
+<?php
+function ajax_customCategory ($param) {
+  global $db;
+
+  if (!$db) {
+    return null;
+  }
+
+  if ($param['id']) {
+    $stmt = $db->prepare("select content from customCategory where id=:id");
+    $stmt->bindValue(':id', $param['id'], PDO::PARAM_STR);
+    if ($stmt->execute()) {
+      $row = $stmt->fetch(PDO::FETCH_ASSOC);
+      $result = $row['content'];
+      $stmt->closeCursor();
+
+      $stmt = $db->prepare("update customCategory set lastAccess=:now where id=:id");
+      $stmt->bindValue(':id', $param['id']);
+      $stmt->bindValue(':now', (new DateTime())->format('Y-m-d H:i:s'), PDO::PARAM_STR);
+      $stmt->execute();
+
+      return $result;
+    }
+
+    return false;
+  }
+
+  if ($param['content']) {
+    $id = md5($param['content']);
+
+    //$stmt = $db->prepare("insert into customCategory (id, content) values (:id, :content) on duplicate key update lastAccess=:now");
+    $stmt = $db->prepare("insert into customCategory (id, content) values (:id, :content) on conflict(id) do update set lastAccess=:now");
+    $stmt->bindValue(':id', $id, PDO::PARAM_STR);
+    $stmt->bindValue(':content', $param['content'], PDO::PARAM_STR);
+    $stmt->bindValue(':now', (new DateTime())->format('Y-m-d H:i:s'), PDO::PARAM_STR);
+    $result = $stmt->execute();
+    return $result;
+  }
+}
diff --git a/src/database.php b/src/database.php
new file mode 100644
index 00000000..c5b013b8
--- /dev/null
+++ b/src/database.php
@@ -0,0 +1,9 @@
+<?php
+register_hook('ajax_start', function () {
+  global $db;
+  global $db_conf;
+  
+  if ($db_conf) {
+    $db = new PDO($db_conf['dsn'], $db_conf['username'], $db_conf['password']);
+  }
+});