[Userscript] Item Filter

I’m not sure how well this works if there are multiple scripts trying to do the same. My guess: not very well.


Here’s a version that will probably work with multiple scripts though:

const original = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, "responseText");

Object.defineProperty(XMLHttpRequest.prototype, "responseText", {
  get: function patchedResponse() {
    if (this.responseURL === "https://www.wanikani.com/review/queue?minimal=true") {
      return "[1115]";
    return this.response;

And then you would use the returned value from original.get.apply as your basis


Another method to achieve similar things (and more) are Proxies, which I’ve recently learned about. I’m not sure if they are of any use in this case, but in general they seem pretty cool, so I thought I would mention them just in case you don’t know about them.


If you can set the prototype itself to this proxy (and I don’t think anything’s stopping you), then sure enough, it should do the same thing.


@Gorbit99 @Sinyaven Do you think that this method is reliable enough that I should use it in Omega? I know you were talking about it being a race condition

I’m not sure… the advantage of it is that the WK cache works as long as the user starts the session with the desired preset active, and that the script can be used to filter NSFW items or something like that. But on the other hand, you would most likely have to change @run-at to document-start, and then maintain three different approaches for the same functionality: the fetch interception, the XMLHttpRequest interception, and the jStorage manipulation. And for the XMLHttpRequest interception, you would probably first have to extend the code snippet by @Gorbit99 to allow for async manipulation of the queue (I assume your queue manipulation first has to wait for wkof to be ready).

By the way, if you actually decide to switch to @run-at document-start, you might have to wait for the document body to be available, because wkof.include() tries to use it and might fail otherwise.

EDIT: And regarding the race condition: if the script loses the race condition and misses the interception then you would just have to fall back to the jStorage method.

1 Like

Ok, I think I will hold off for now, then. It would be a lot of effort for little gain, especially as I already set it to run at document-idle to easily resolve another issue

1 Like

Yes, it’s probably not worth the effort.

I still don’t understand what causes this other issue (I assume you are talking about the jStorage listener error). When this was happening to me, I thought that the problem is that jStorage can’t handle removing a listener callback from within this callback, because once I delayed the jStorage.stopListening() call until after the listener callback had finished, the error was gone. But then I did a bit more testing, and usually jStorage handles this just fine – it seems like just this one practiceQueue change at the start of the extra study session does not allow removing the listener :thinking:

Some code I used for analyzing this jStorage error
// ==UserScript==
// @name         jStorage Error Test
// @namespace    jStorageErrorTest
// @version      0.1
// @description  jStorage error test
// @author       Sinyaven
// @license      MIT-0
// @match        https://www.wanikani.com/extra_study/session?title=Recent+Lessons
// @require      https://greasyfork.org/scripts/441518-wanikani-queue-manipulator/code/WaniKani%20Queue%20Manipulator.js?version=1032684
// @grant        none
// @run-at       document-start
// ==/UserScript==

(async function() {
	"use strict";
	/* global $, wkQueueManipulator */
	/* eslint no-multi-spaces: off */

	function changeHandler() {
		$.jStorage.stopListening("practiceQueue", changeHandler);
		console.log("stopped listening");

	async function changeHandlerAsync() {
		await true; // delay any further execution of this function until later
		$.jStorage.stopListening("practiceQueue", changeHandlerAsync);
		console.log("stopped listening");

	await wkQueueManipulator.jQueryReady();
//	await sleep(1000);
	$.jStorage.listenKeyChange("practiceQueue", changeHandler);       // this version causes an error
//	$.jStorage.listenKeyChange("practiceQueue", changeHandlerAsync);  // this version works fine
//	$.jStorage.set("practiceQueue", $.jStorage.get("practiceQueue"));

	function sleep(ms) {
		return new Promise(resolve => setTimeout(resolve, ms));

Hello, I hope it’s ok to ask this. I read the thread but didn’t see if this was answered before. Is there any way of seeing which items have been filtered?

No, there is not (except if you filter the items, finish the entire review session, and then start the session again without filtering anything – then you get questioned on the previously filtered items).

Is there a use case for which you need to see the filtered items?

Yes, since I have set some of them to be answered correctly automatically (usually because they are leeches, but not always), I’d like to go back a see which items are marked as “burned” without me actually having burned them.

Instead of implementing an item list feature into this script, I remembered a suggestion by @Kumirei [1] and decided to create a companion script that registers your filtered items in an Open Framework filter:

This allows you to view the item list in an already established and feature-rich tool like Item Inspector. With Open Framework Item Filter and Item Inspector installed, you just have to locate the Item Inspector on your dashboard, click the settings gear button, go to the “Tables” tab, add a “New” table list, give it a name, find the “Item Filter” checkbox (probably at the bottom), and activate it. After saving, you should see a list of all your filtered items.

  1. ↩︎

This is great! Thank you so much for creating this!


does not work.

correction, seems to only work when I turn off all other scripts including open framework.
Seems like open framework prevents it from working properly.
Kind of a shame since most other scripts require it. Just reset back 10 levels which was probably pretty stupid on my end. I just wanna learn kanji, I’ve seen all the vocabulary 1000 times so I have hundreds of vocab reviews that I have to get through so I can progress on my kanji. thanks for this. Hope it gets updated so I can use it with everything else on.

correction, still doesn’t work.
I give up.

It still works for me. Are you using Tampermonkey and Google Chrome? It seems that there are currently problems with Tampermonkey sometimes not injecting scripts with that setup. In that case, it might help to switch to Violentmonkey. Other than that, could you look through the suggested steps in this guide to see if any of them give more hints to why it does not work for you?

1 Like

Hey, I’m using this script to filter out radicals completely since I’m going through WK from lvl 1 for the 3rd time now. I like to do my reviews on several computers but noticed that this script only uses localStorage for the list of filtered items.
Is there any chance of a sync feature or companion script coming in the future?

I’ll have to try that. Thanks. All other scripts seemed to work just fine so that’s why I thought it was the script but I am using chrome so it could be a tampermonkey issue.

I was expecting that Tampermonkey would have a storage sync feature and tried to use the Tampermonkey storage instead of localStorage, but sadly Tampermonkey only syncs the list of scripts but not their settings. At the moment I cannot think of a good solution for syncing the settings, but if anyone has suggestions, let me know.


Maybe this is what you are looking for?