diff --git a/daemon/openrazer_daemon/hardware/mouse.py b/daemon/openrazer_daemon/hardware/mouse.py
index d6514e9c776f490fd0a2d841ae7e8a0054c91836..fdc64d69f1e5860c53c4158909bcdf9548ff89ae 100644
--- a/daemon/openrazer_daemon/hardware/mouse.py
+++ b/daemon/openrazer_daemon/hardware/mouse.py
@@ -23,10 +23,14 @@ class RazerViperMini(__RazerDeviceSpecialBrightnessSuspend):
 
     USB_VID = 0x1532
     USB_PID = 0x008A
+    HAS_MATRIX = True
+    MATRIX_DIMS = [1, 1]
     METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness',
                # Underglow/Logo use LOGO_LED
                'set_logo_static_naga_hex_v2', 'set_logo_spectrum_naga_hex_v2', 'set_logo_none_naga_hex_v2', 'set_logo_reactive_naga_hex_v2',
-               'set_logo_breath_random_naga_hex_v2', 'set_logo_breath_single_naga_hex_v2', 'set_logo_breath_dual_naga_hex_v2']
+               'set_logo_breath_random_naga_hex_v2', 'set_logo_breath_single_naga_hex_v2', 'set_logo_breath_dual_naga_hex_v2',
+               # Custom frame
+               'set_custom_effect', 'set_key_row']
 
     DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1634/vipermini.png"
 
@@ -1682,13 +1686,16 @@ class RazerViperUltimateWired(__RazerDeviceSpecialBrightnessSuspend):
 
     USB_VID = 0x1532
     USB_PID = 0x007A
-    HAS_MATRIX = False  # TODO device probably has matrix support
+    HAS_MATRIX = True
+    MATRIX_DIMS = [1, 1]
     METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness',
                # Battery
                'get_battery', 'is_charging', 'set_idle_time', 'set_low_battery_threshold',
                # Logo
                'set_logo_static_naga_hex_v2', 'set_logo_spectrum_naga_hex_v2', 'set_logo_none_naga_hex_v2', 'set_logo_reactive_naga_hex_v2',
-               'set_logo_breath_random_naga_hex_v2', 'set_logo_breath_single_naga_hex_v2', 'set_logo_breath_dual_naga_hex_v2']
+               'set_logo_breath_random_naga_hex_v2', 'set_logo_breath_single_naga_hex_v2', 'set_logo_breath_dual_naga_hex_v2',
+               # Custom frame
+               'set_custom_effect', 'set_key_row']
 
     DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1577/ee_photo.png"
 
@@ -1726,7 +1733,6 @@ class RazerViperUltimateWireless(RazerViperUltimateWired):
     """
     EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Viper_Ultimate_Dongle-if0(1|2)-event-kbd')
 
-    USB_VID = 0x1532
     USB_PID = 0x007B
     METHODS = RazerViperUltimateWired.METHODS + ['set_charge_effect', 'set_charge_colour']
 
@@ -1753,12 +1759,14 @@ class RazerViper(__RazerDeviceSpecialBrightnessSuspend):
 
     USB_VID = 0x1532
     USB_PID = 0x0078
-    HAS_MATRIX = False  # TODO Device should have matrix support
+    HAS_MATRIX = True
     MATRIX_DIMS = [1, 1]
     METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness',
                # Logo
                'set_logo_static_naga_hex_v2', 'set_logo_spectrum_naga_hex_v2', 'set_logo_none_naga_hex_v2', 'set_logo_reactive_naga_hex_v2',
-               'set_logo_breath_random_naga_hex_v2', 'set_logo_breath_single_naga_hex_v2', 'set_logo_breath_dual_naga_hex_v2']
+               'set_logo_breath_random_naga_hex_v2', 'set_logo_breath_single_naga_hex_v2', 'set_logo_breath_dual_naga_hex_v2',
+               # Custom frame
+               'set_custom_effect', 'set_key_row']
 
     DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1539/1539_viper.png"
 
diff --git a/driver/razermouse_driver.c b/driver/razermouse_driver.c
index fd073d66550dae7592354efb29effb43058d9241..d999584204fbba03ce0e4a8325685b33ea57e02f 100644
--- a/driver/razermouse_driver.c
+++ b/driver/razermouse_driver.c
@@ -533,6 +533,10 @@ static ssize_t razer_attr_write_mode_custom(struct device *dev, struct device_at
     case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED:
     case USB_DEVICE_ID_RAZER_BASILISK:
     case USB_DEVICE_ID_RAZER_DEATHADDER_V2:
+    case USB_DEVICE_ID_RAZER_VIPER:
+    case USB_DEVICE_ID_RAZER_VIPER_MINI:
+    case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED:
+    case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS:
         report = razer_chroma_extended_matrix_effect_custom_frame();
         break;
 
@@ -1461,6 +1465,10 @@ static ssize_t razer_attr_write_set_key_row(struct device *dev, struct device_at
         case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED:
         case USB_DEVICE_ID_RAZER_BASILISK:
         case USB_DEVICE_ID_RAZER_DEATHADDER_V2:
+        case USB_DEVICE_ID_RAZER_VIPER:
+        case USB_DEVICE_ID_RAZER_VIPER_MINI:
+        case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED:
+        case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS:
             report = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]);
             break;
 
@@ -3725,6 +3733,8 @@ static int razer_mouse_probe(struct hid_device *hdev, const struct hid_device_id
             CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath);
             CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static);
             CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none);
+            CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom);
+            CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame);
             break;
 
         case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER:
@@ -4167,6 +4177,8 @@ static void razer_mouse_disconnect(struct hid_device *hdev)
             device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath);
             device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static);
             device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none);
+            device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom);
+            device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame);
             break;
 
         case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER:
diff --git a/pylib/openrazer/_fake_driver/razerviper.cfg b/pylib/openrazer/_fake_driver/razerviper.cfg
index 14b9087370611d043133a2073cf57308fb09166f..66e4da83dc41b5e6673a81421c064051bcfc31d4 100644
--- a/pylib/openrazer/_fake_driver/razerviper.cfg
+++ b/pylib/openrazer/_fake_driver/razerviper.cfg
@@ -12,5 +12,7 @@ files = rw,device_idle_time,600
         w,logo_matrix_effect_reactive
         w,logo_matrix_effect_spectrum
         w,logo_matrix_effect_static
+        w,matrix_custom_frame
+        w,matrix_effect_custom
         rw,poll_rate,500
         r,version,1.0.0
diff --git a/pylib/openrazer/_fake_driver/razervipermini.cfg b/pylib/openrazer/_fake_driver/razervipermini.cfg
index 5d3b0305876006c32ce63407274ce20a1056a69f..ea01b3262e0d5172881f2fbf3f5c10ab86d05730 100644
--- a/pylib/openrazer/_fake_driver/razervipermini.cfg
+++ b/pylib/openrazer/_fake_driver/razervipermini.cfg
@@ -12,5 +12,7 @@ files = rw,device_idle_time,600
         w,logo_matrix_effect_reactive
         w,logo_matrix_effect_spectrum
         w,logo_matrix_effect_static
+        w,matrix_custom_frame
+        w,matrix_effect_custom
         rw,poll_rate,500
         r,version,1.0.0
diff --git a/pylib/openrazer/_fake_driver/razerviperultimatewired.cfg b/pylib/openrazer/_fake_driver/razerviperultimatewired.cfg
index e97887ae202e001489f4410c1f32a5c24a047273..38c722feea533745b9062d4c1fc655bbcfb662eb 100644
--- a/pylib/openrazer/_fake_driver/razerviperultimatewired.cfg
+++ b/pylib/openrazer/_fake_driver/razerviperultimatewired.cfg
@@ -15,5 +15,7 @@ files = r,charge_level,255
         w,logo_matrix_effect_reactive
         w,logo_matrix_effect_spectrum
         w,logo_matrix_effect_static
+        w,matrix_custom_frame
+        w,matrix_effect_custom
         rw,poll_rate,500
         r,version,1.0.0
diff --git a/pylib/openrazer/_fake_driver/razerviperultimatewireless.cfg b/pylib/openrazer/_fake_driver/razerviperultimatewireless.cfg
index 516513f9309764a2ef7c37fc1db4d87a059812b2..228a8d6f5033296c15e7a2226d585659b58e296d 100644
--- a/pylib/openrazer/_fake_driver/razerviperultimatewireless.cfg
+++ b/pylib/openrazer/_fake_driver/razerviperultimatewireless.cfg
@@ -17,5 +17,7 @@ files = w,charge_colour
         w,logo_matrix_effect_reactive
         w,logo_matrix_effect_spectrum
         w,logo_matrix_effect_static
+        w,matrix_custom_frame
+        w,matrix_effect_custom
         rw,poll_rate,500
         r,version,1.0.0