diff --git a/resources/scripts/api/account/activity.ts b/resources/scripts/api/account/activity.ts
index 7746c8a4..7d56061e 100644
--- a/resources/scripts/api/account/activity.ts
+++ b/resources/scripts/api/account/activity.ts
@@ -4,11 +4,12 @@ import { ActivityLog, Transformers } from '@definitions/user';
 import { AxiosError } from 'axios';
 import http, { PaginatedResult, QueryBuilderParams, withQueryBuilderParams } from '@/api/http';
 import { toPaginatedSet } from '@definitions/helpers';
+import useFilteredObject from '@/plugins/useFilteredObject';
 
 export type ActivityLogFilters = QueryBuilderParams<'ip' | 'event', 'timestamp'>;
 
 const useActivityLogs = (filters?: ActivityLogFilters, config?: ConfigInterface<PaginatedResult<ActivityLog>, AxiosError>): responseInterface<PaginatedResult<ActivityLog>, AxiosError> => {
-    const key = useUserSWRContentKey([ 'account', 'activity', JSON.stringify(filters) ]);
+    const key = useUserSWRContentKey([ 'account', 'activity', JSON.stringify(useFilteredObject(filters || {})) ]);
 
     return useSWR<PaginatedResult<ActivityLog>>(key, async () => {
         const { data } = await http.get('/api/client/account/activity', {
diff --git a/resources/scripts/api/http.ts b/resources/scripts/api/http.ts
index 2dc54a60..119f074a 100644
--- a/resources/scripts/api/http.ts
+++ b/resources/scripts/api/http.ts
@@ -88,7 +88,7 @@ export interface FractalPaginatedResponse extends FractalResponseList {
             total_pages: number;
             /* eslint-enable camelcase */
         };
-    }
+    };
 }
 
 export interface PaginatedResult<T> {
diff --git a/resources/scripts/helpers.ts b/resources/scripts/helpers.ts
index 67d07942..fe6cc4f5 100644
--- a/resources/scripts/helpers.ts
+++ b/resources/scripts/helpers.ts
@@ -65,3 +65,13 @@ export function hashToPath (hash: string): string {
 export function formatIp (ip: string): string {
     return /([a-f0-9:]+:+)+[a-f0-9]+/.test(ip) ? `[${ip}]` : ip;
 }
+
+// eslint-disable-next-line @typescript-eslint/ban-types
+export const isObject = (o: unknown): o is {} => typeof o === 'object' && o !== null;
+
+// eslint-disable-next-line @typescript-eslint/ban-types
+export const isEmptyObject = (o: {}): boolean =>
+    Object.keys(o).length === 0 && Object.getPrototypeOf(o) === Object.prototype;
+
+// eslint-disable-next-line @typescript-eslint/ban-types
+export const getObjectKeys = <T extends {}> (o: T): Array<keyof T> => Object.keys(o) as Array<keyof T>;
diff --git a/resources/scripts/plugins/useFilteredObject.ts b/resources/scripts/plugins/useFilteredObject.ts
new file mode 100644
index 00000000..440e422f
--- /dev/null
+++ b/resources/scripts/plugins/useFilteredObject.ts
@@ -0,0 +1,22 @@
+/**
+ * Similar to "withQueryBuilderParams" except this function filters out any null,
+ * undefined, or empty string key values. This allows the parameters to be used for
+ * caching without having to account for all of the different data combinations.
+ */
+import { isEmptyObject, isObject } from '@/helpers';
+
+// eslint-disable-next-line @typescript-eslint/ban-types
+export default <T extends {}>(data: T): T => {
+    const empty = [ undefined, null, '' ] as unknown[];
+
+    const removeEmptyValues = (input: T): T =>
+        Object.entries(input)
+            .filter(([ _, value ]) => !empty.includes(value))
+            .reduce((obj, [ k, v ]) => {
+                const parsed = isObject(v) ? removeEmptyValues(v as any) : v;
+
+                return isObject(parsed) && isEmptyObject(parsed) ? obj : { ...obj, [k]: parsed };
+            }, {} as T);
+
+    return removeEmptyValues(data);
+};