Wanikani Open Framework [developer thread]

I think you can use window.onfocus and window.onblur to detect when the tab gets and loses focus. However, that doesn’t account for someone leaving the tab focused while not visible on screen.


Makes sense. I briefly looked into it years ago while making a “Time Spent” script, which measures how much time you spend on reviews, lessons, forums, forum categories, etc. I’m not sure if I ended up discovering “window.onfocus” / “window.onblur”

1 Like

I looked into it a couple of months ago, although I don’t remember what I was working on sweat_smile

1 Like

It appears the Page Visibility API is the modern, approved method to check whether a page is active or not. Amazingly, it appears to be well-supported across every browser (even IE!).


Oh, that’s cool. I didn’t find that one when I looked into it

How on earth are you liking my posts within milliseconds of posting! <laugh>

1 Like


1 Like

Man this really feels weird to ask, but I’m struggling with the recent reviewQueue change that stores only ids. I’m trying to update this reorder button userscript to use the wkof fetch functions to get the review queue items’ srs levels, but I’m really not sure how to go about this.

According to this thread there’s some review/queue and review/items endpoint I should be able to hit, though I’ve no clue how to actually hit that endpoint. I’m not really sure where to even find its documentation, and trying to see how it’s used by the client scripts running the review page hasn’t yielded much.

I’m honestly not a JS nor web dev whatsoever, so I’m really out of tools to keep flailing on this. Has anyone else figured out how to fetch all review data with the new setup? Even reference code links would be greatly appreciated :pray:

1 Like

The /review/queue and /review/items URLs aren’t part of the Wanikani API, they are part of the review interface. The latter might have the current SRS level, but I haven’t looked, and it may be limited on the number of items it can return in one query.

If you want to use Open Framework, you can do something like this:


function fetch_items() {
   return wkof.get_items('assignments');

var items_by_id;
function process_items(items)
   items_by_id = wkof.get_index(items, 'subject_id');
   // Usage:
   //  var srs_stage = items_by_id[2345].assignments.srs_stage;

Like @rfindley mentioned, the review endpoint isn’t officially part of the API. You can however still use it if you want an easy method of obtaining data in the format the activeQueue expects. review/queue is used to populate the review queue, which is now just an array of subject ids.

review/items is the more interesting one, which can be used to convert the given subject ids into the JSON objects the activeQueue now expects. Since it’s not part of the official API, you need to manually fetch it instead of using WKOF, although the code to do so is relatively simple since this endpoint doesn’t return any paginated results. You can just use a normal fetch, passing the subject ids in the query parameter ids and use the result as JSON to obtain the result. There is probably a limit on the number of items you can query at once though, although querying 10 at once to fill the activeQueue seems to work.

An example of how to fetch data from the review/items endpoint:

// Assuming an array of subject ids as argument
async function fetch_review_items(subject_ids) {
    let subject_ids_str = subject_ids.join(',');
    let request = await fetch(`/review/items?ids=${subject_ids_str}`);
    return await request.json();

Yep. Wanikani itself fetches up to 100 at a time when you start a review session.


tyvm for the support y’all :pray:

That set up works really well, and I love how the code for it is laid out, though after setting it all up, I realized I’m actually back where I started wrt the review IDs. Before I was stuck getting the SRS level for a review item by review ID, but now I’m trying to get the subject ID of a review item by review ID. It ended up being a lateral move :confused:

Apologies if I’m missing some obvious prerequisite setup for this to work, but I’m still not really able to access those endpoints. Trying to do it manually in the console results in the following:

I feel that if I could figure out how to get review information in-bulk (whether through that /review/items endpoint or through the /v2/reviews endpoint), I’d be pretty much done right now :disappointed:


Oh, interesting. I assumed the Review ID was the Subject ID. Hmm…

1 Like

I just did an experiment on my test account, and the ‘review IDs’ from jStorage’s “reviewQueue” and “activeQueue” both matched the API’s subject ID.

1 Like

Man, I am seriously so sorry.
I’m thinking that some mess-up on my part in handling a promise resulted in me misunderstanding why I was seeing an undefined printout message.

I can actually pull the review items from the /review/items endpoint. I’ll double check if there was some other issue when I tried using the reviewQueue items as subject IDs – I presume it was just an issue of tired-eyes :sweat_smile:

1 Like

No problem… gotta learn somehow :slight_smile:

FYI, each time you complete an item (i.e both reading and meaning), one new item is popped from the end of “reviewQueue”, and placed at the end of “activeQueue”. So, in my experiment, I went to the review page, looked at the last item ID in “reviewQueue”. Then I answered reviews until I completed the Reading and Meaning for one item, which triggered the last item from reviewQueue to move to activeQueue and load its details. Then I looked at the end of “activeQueue” and saw which item it was (夕) and its ID (461). I then loaded the item data from the API via wkof, and they matched.


Whew, lad! I finally got it sorted… can you guess what my issue was based off the state of this chunk I’m debugging? :man_facepalming:

So the activeQueue and reviewQueue was full of ints, so in trying to access them through the index built by wkof I was getting a bunch of misses. If I convert the keys to strings before checking the queue, it works just fine! :grinning_face_with_smiling_eyes:

I’ll try to finish this work leveraging wkof instead of relying on the undocumented /review/items endpoint despite getting both working so far. Thank y’all a ton for helping with this! :heart:

Sidenote: there’s a section of my plugin that’s dedicated to displaying the amount of items remaining for each SRS level. I figure with all this work, I can split that off into its own separate userscript for leveraging by other userscripts. I figure I can have it subscribe to updates to the activeQueue and reviewQueue and refresh counts on events.

The actual question regarding that: if the other plugin pulls all in-review assignments with the exact same request through wkof as this plugin, will the results stay cached and shared by both plugins?


The arrays and indices returned by get_items() and get_index() are built per-call, but the contents (the item structures inside the array or index) are shared between all scripts. I figured scripts might modify an array without thinking about it affecting other scripts, but it was unlikely that people would modify the item data in ways that would interfere.

edit: On each call, wkof may also query the server to ask for changed item data. But it won’t check more often than once a minute unless you reload the page.


That would be nice. I already have this script, but I don’t have time to update it right now

1 Like