Updates to Lessons, Reviews, and Extra Study

100% that is the plan. It is a little while off as I still have other pages to update first to bring everything in line, but I wanted to mention that the process has started. Here is an example of it in use:

.wk-button--modal-primary {
    border: 2px solid var(--color-button-modal-primary-border);
    background-color: var(--color-button-modal-primary-background);
    color: var(--color-button-modal-primary-text);

I will be sure to let the community know once the process is complete (it is very much in flux at the moment).

We already use SASS variables so the maintenance isn’t that much of a motivation. However I may sprinkle in some web components in the future, and CSS variables provide an nicer way to cross Shadow DOM boundaries which is the main motivation.


If only I could like a reply more than once!


Oh my, I’m going to have to update a lot of scripts. I’ll be busy this weekend. Good change, though.


@tofugu-scott Did the session timeout go away, too? Is that a side-effect of discontinuing jStorage?[1]

I stepped away from my review session for several hours and it’s still sitting there waiting for me on the same subject without the familiar “timed out” icon and overlay.

Any comments you can make about how session state is handled? “Wrap-up” is still there, so I assume the no-more-than-10-incomplete-subjects behavior is still present.

More a curiousity question than anything, but if session state is maintained purely server-side that would be of interest to me and other script writers – especially if “review session” info might start appearing in future versions of the API.

I’ve been doing some fancy statistics based on review timestamps to determine “sessions”, which works quite well in practice, but if the official definition of what comprises a “session” might change, I’d like to know about it.

Thanks for all the continuing updates! Great stuff.

  1. I managed to sleep through the whole jquery era, so I’m unfamiliar with jStorage. ↩︎


Yes the session timeouts went away as did the notion of a session (review, lesson, or otherwise). A session timestamp was used to determine what to show on the summary pages, but as the summary pages have gone away, so has the need for a session.

The session timestamp was also used to determine which items to show in last items section (shown below). However I changed this to show the items completed in the past hour (up to a maximum of 10 subjects).

So as you can see it wasn’t a side-effect from removing jStorage.

The queue logic largely remains the same and is managed client side. We have a backlog queue of subjects and an active queue of 10 subjects[1]. When you complete a subject it is removed from the active queue. We then fill the active queue with subjects from the backlog so long as wrap-up is not active. The count you see on the wrap-up button when it is active represents the number of remaining items in the active queue. If you reload the page you will lose any state, such as partially completed subjects (e.g. reading answered but not meaning) as I no longer use browser session storage (and cache expiration is a hard problem to solve)

I am not sure if this answers all your session questions. If you have any additional questions or if I have not been clear enough, please let me know.

  1. please don’t bank on this number of subjects in the active queue not changing (i.e. don’t hard code 10 in your scripts) ↩︎


Thank you for the thorough response. Very helpful!


Is there any way for userscripts to access or even modify the queue? It seems to me that the queue is now stored in javascript variables that are unreachable(?) from the page context. The only related thing I found is this queue (limited to 100 entries):

JSON.parse(document.querySelector(`#quiz-queue [data-quiz-queue-target="subjects"]`).textContent)

and this complete queue which contains just the ids and the srs stages:

JSON.parse(document.querySelector(`#quiz-queue [data-quiz-queue-target="subjectIdsWithSRS"]`).textContent)

Sadly, they don’t seem to update when the user proceeds through the reviews, and changes to these elements are also ignored.

If any other script author has already found a way to modify the queue, I would be interested in knowing how to do it.

EDIT: While looking through the code, I noticed that you are emitting some events that are also useful for script authors:

  • audioWillPlay
  • willShowNextQuestion
  • didChangeSRS
  • didUpdateUserSynonyms
  • registerWrapUpObserver
  • didAnswerQuestion
  • didCompleteSubject
  • updateQuizProgress
  • connectionTimeout

Let me try and help by providing some more context and guidance.

I want to start with the caveat that this by no means constitutes documentation or provides any guarantee about how the code may or may not work in the future.

Firstly as I am sure you are aware we use Turbo and Stimulus (aka Hotwire) to power most of the pages in Wanikani. Not all pages have migrated to this architecture (namely the dashboard) but they will. In particular you probably want to pay attention to the Turbo events (e.g. turbo:load or turbo:before-render would probably be useful). These events will let you know when the page has / is going to change in the instance where it is not a full page reload.

As you have discovered there are number of events that I use to control different aspects of the app. Rather than have you guess what they do and when they fire, I will just tell you in the list below:

  • audioWillPlay - Sent when the audio for a subject will play. I use this to stop any other playing audio. You should consider this for internal use only.
  • willShowNextQuestion - This event fires right before the question changes. It is used by multiple components to change display states, and also by the main quiz input to set the current question and subject.
  • didChangeSRS - This is fired after a subject is completed to allow the SRS indicator that pops up in reviews to show up. You should consider this for internal use only.
  • didUpdateUserSynonyms - I keep a dictionary of synonyms for each of the subjects that is in the current review queue. Historically the synonyms were mixed in with subjects but this impacts cache-ability so I now keep the dictionary separate. If you open up the item info for a subject and add or remove a synonym the dictionary is updated so that the next time you answer the question your new synoynm is used (or not if you deleted it). You should consider this for internal use only.
  • registerWrapUpObserver - This event is fired when you click on the wrap up button. You should consider this for internal use only.
  • didAnswerQuestion - This event is fired after the answer checking is done and is used to power things like the autoplaying of audio, or enabling the item info button.
  • didCompleteSubject - This is fired when the subject is completed so the statistics at the top of the page can update.
  • updateQuizProgress - This event is used to power the progress bar at the top of the page. You should consider this for internal use only.
  • connectionTimeout - this is fired when the client can’t send the subject results to the server (after a number of retires) and allows the timeout modal to show up. You should consider this for internal use only.

The 2 events that I think will be most useful to you are willShowNextQuestion and didAnswerQuestion.

Next it seems that the queue ordering (and reordering) is a popular topic. In order (no pun intended) to make this easier to understand it is probably helpful for you know a bit more about how it works (and how I would approach such a task)

The whole queue is managed by the HTML element with the id quiz-queue. This queue element is picked up by a stimulus controller which interprets the internal data and data attributes as follows:

  • The script tag with data-quiz-queue-target="subjects" contains a json string for the first (up to) 100 subjects preloaded onto the page.
  • The script tag with data-quiz-queue-target="subjectIds" contains a json string for the entire list of subject ids for the current quiz. This is used for extra study and for lesson quizzes (not for reviews)
  • The script tag with data-quiz-queue-target="subjectIdsWithSRS" contains a json string for the entire list of subject ids and current SRS (Spaced Repetition System) levels represented as an array of tuple [[id, srs], [id, srs], ...]. This is used for reviews.
  • The data attribute data-quiz-queue-items-url-value is the URL where additional subjects are fetched from when the backlog queue is running low
  • The data attribute data-quiz-queue-completion-url-value is the URL where the subject results are sent
  • The data attribute data-quiz-queue-done-url-value is the URL that will be visited once the review is complete.
  • The data attribute data-quiz-queue-complete-subjects-in-order-value is a boolean set to "true" when you want to complete each subject in the order of the given queue (both reading and meaning are answered before moving on). This is used in extra study.
  • The data attribute data-quiz-queue-question-order-value can be set to either readingFirst or meaningFirst and will override the random question selection with the given preference.
  • there is also an HTML template for the done modal that shows up on lesson pages.

Currently there is no way to set the question order (e.g. reading first or meaning first), however I don’t feel that you can properly control the queue without this so I will add this in tomorrow and report back with more info on how you can set the value.

So with all this above information, I would take the following approach to reordering the queue.

  • get the queue DOM node - queueEl = document.getElementById('quiz-queue')
  • grab a reference to the queues parent - parentEl = queueEl.parentElement
  • remove the queueEl from the DOM - queueEl.remove()
  • clone the queueEl - cloneEl = queueEl.cloneNode(true)
  • manipulate the queues however you need on the cloned node
  • reattach the clone node (after reordering is done) - parentEl.appendChild(cloneEl)

The rationale for this approach has to do with the order that the stimulus lifecycle callbacks fire. I have to do most of the work in setting up the queue in the initialise callback of the stimulus controller as the queue needs to be setup before the quiz input detects it as an outlet. Because of the way lifecycle callbacks work with stimulus I can’t put the queue setup logic in the connect callback which necessitates the need to clone the DOM node that I mentioned above. When you attach the clone back to the DOM, my code will pick this up and create the new queue based on your reorder logic and fire the willShowNextQuestion event which should update the UI. Note that if you changed the order where the first subject is no longer the first subject, the user will see the subject change on there screen which may be a little jarring, so you might want to consider adding something to indicate loading/reordering that makes it a little more user friendly (or not, it is up to you).

Sorry this is a bit of a long one, but hopefully it is helpful and you find it useful. I will update you tomorrow once I have made the question ordering configurable.


I have now implemented the ability to specify the question order and updated the attributes list for the quiz-queue above. I have also made it so that the question order can be set via a URL parameter question_order=reading_first or question_order=meaning_first which is there to help with setting the preferred question type for the first preloaded subject. Note the use of snake-case for the url parameter and the use camelcase for the javascript parameter used in the data attribute.


Dunno if I’ll ever do anything with this info (mucking with the queue has never been of much interest to me) but the transparency is sincerely appreciated!

One of the many things WK does right is to maintain a well-documented API and support the userscript ecosystem. For a learning site like this, it’s particularly valuable, but it’s also extremely refreshing.

Thank you!


Thank you for the kind words I really appreciate it.
I would just like to be clear on the use of the word support in the context of the userscript eco system. I would like to be as helpful to script authors as and where I can, but issues that arise from user scripts can not be supported by us. I am pretty sure this is known, but I just want to make is abundantly clear, that user scripts are the responsibly of the script authors and the users that install them.

I hope you don’t mind me clarifying that, I just want to make sure we all have the same expectations.


Thank you for going above and beyond with this extremely helpful answer! :crabigator:


@tofugu-scott now that the dashboard code is getting looked at, there was this conversation a bit ago mainly between me and @Rrwrex about the kana keyboard:

Main point would be that it has は and な mixed up when compared to gojuuon order


One difference I noticed between this new version and the current version, is that the audio from the previous card used to play over the next one if you pressed enter after getting a reading review right, while now it interrupts the audio.

Is this change on purpose or is this an oversight? I personally liked the current system, because it allowed me to still hear the reading without having to wait for it to finish.

In terms of design, might be because it’s new and fresh, but it’s looking great. It feels crisper than it does in the current version.


I would also have to agree with this - I get a lot of reviews to do and don’t have much time, and so press enter to continue immediately on getting a review correct - meaning that the 80% of the time I get a review correct, 90% of the audio plays over the next item.

With the new version making it cut off, it either means I have to significantly slow down my reviews, or I have to stop hearing the words - obviously not good. Especially as they usually takes a few hundred milliseconds to load (do they not cache until after you get an answer correct?), meaning in some cases I’m not even hearing the start of the audios!

Would be great if you could clarify if this was intentional @tofugu-scott, and if so maybe reconsider it a bit? :sweat_smile:

Thanks for being so open about the changes!


Now I have to scroll in order to see the buttons and tooltips under the input field.
This is how it looks for me:

This is how it was:

Why so much wasted space now?

Ouch, the “you lost connection to Wanakani” screen blinked once, and now I can’t scroll to buttons at all. There’s no scrollbar.

Item info doesn’t fit into my screen now.
That’s how it was, a table-like layout that have exactly a one-screen height:

And now it’s just one-column layout:

Bigger fonts, a lot of empty space to the right, and having to scroll. Seems kinda inconvenient to me.


Thank you for pointing this out. I have fixed this.


I have updated the audio to finish playing before being removed when you move on to the next question. Hopefully that will help, however if you answer the next question before the previous questions audio is finished playing, it will still get cut off, or not played at all if your internet connection is latent.

As for the question on caching, I can’t load the pronunciation audio until after you have answered the question as I have to work out which audio to play. There may be more than one audio pronunciation, or your accepted answer might not have an associated audio pronunciation. We only autoplay the audio that matches your answer, as it would seem weird if you typed one thing and heard something different. I don’t want to unnecessarily preload all the audio as that isn’t very friendly on the network, especially if you are on a mobile device. However, if this does prove to be an issue for you after using it for a while, could you please let customer support know by sending them an email to hello@wanikani.com and we can continue to look at this.


I just want to point out (in case you missed it above), I have deployed the change to allow the question order to be set and updated / edit the associated post.


That’s great, thank you! Like you say, answering the next question before the first finishes playing also cuts off the audio, but that does make sense and is probably the most reasonable behaviour! The main issue was just the cutting off immediately on going to the next question which you’ve now fixed :slight_smile:

One other quite noticeable downgrade imo is that now when expanding an item’s details it doesn’t automatically scroll down to them, meaning I have to take the moments to reach for the mouse and scroll down manually - seemingly not too important but the extra time it takes adds up. Any chance you could take a look at this? I feel like the original behaviour of just auto scrolling down to the expanded content was definitely better.

Thanks for listening to all our feedback!


We have different font sizes for the kanji and radicals vs the vocabulary. In order to prevent the character header from jumping about (which can be quite disorienting) when moving between subjects, we fix the height. The header height use to be bigger in lessons and smaller in reviews but I wanted to make this consistent across the board, which is the difference you are seeing. I do plan to make more use of css variables as I mentioned here, so if the styling isn’t to your liking you will be able to change it easily in future. You can also change it now with your own user script which is more what this thread is about. Also, if after we deploy this to production and you have used it for a while you still feel the same way, please do put in a request to customer support by emailing them at hello@wanikani.com. We will obviously continue to improve this as time goes by so your feedback is helpful.

Out of curiosity what device and screen resolution are you using? I did check on a bunch of standard sized devices tablets, phones, and desktops, and a screen resolution of 1920x892 seems a little weird to me, but knowing what you have will help my future testing.

We had a version like this on lesson quizzes, and the reviews hadn’t been updated. I have now consolidated the lessons and reviews so the reviews got the updated design. The item info now more closely retables the subject pages, and has a lot of the new features that were added there but not to the old review style.