[Userscript] Wanikani Heatmap


What is Wanikani Heatmap

This script adds a chart that shows which days you have reviewed and indicates with color how many reviews you did. Does the same with lessons. Along with this it also shows you some interesting stats such as how many days you have reviewed, how many reviews you do per day on average, and what your current streak is.

It utilises and is dependent on the Wanikani Open Framework to fetch the review data, so make sure it is installed.

What is WKOF

WKOF - Wanikani Open Framework - is a script by rfindley that makes it easier and more resource efficient to develop against the WK API. You need to install it and make it run before this script, for this one to work.

More information in this thread
Installing Wanikani Open Framework

Other Info

  • The script will not show any review data since before 4 August 2017, because Wanikani did not log review data before that, but all lessons are included in your lesson heatmap.

  • The default intervals for the different colors are 0, 1-50, 51-100, 101-200, 201-400, 401+, but can be easily changed.

  • You can also choose exactly which colors you want to use, if the green scale does not fit your taste.

  • Works fine with dark themes.




Will add more here once people start posting their updated heatmaps

For more heatmaps have a look at this thread


There are quite a few settings available for this script.


  • First day of the week: Can be set to either Monday or Sunday with the default being determined by your timezone. It changes how the heatmap is layed out.
  • Reverse year order: Puts the most recent year on the bottom instead of on top.
  • Custom colors: Check this box if you want to use color gradients defined by the colors you provide in the Reviews and Lessons tabs.
  • Re-fetch: This button deletes your stored data so that you can re-fetch it through the WK API. Might be useful if something is wrong with the stored data or if you reset or anything like that.

The reviews and lessons settings are identical.

  • Start color: The starting color of the gradient for the heatmap. This is the color for the first interval.
  • ** Color 2-4:** Middle colors for the middle intervals.
  • End color: The end color of the gradient for the heatmap. This is also the color for the open-ended fifth interval.
  • Generate button: This button sets the middle colors based on your start and end colors, to create an even gradient.

This was created from the above image by just pressing the generate button.

  • End of interval 1: Days with a number of items between 0 and this number will have the related color. Not including 0.
  • End of interval 2-4: Days with a number of items between the previous number and this will have the related color.
  • Interval 5: Days with more items than what is entered in End of interval 4 will have the fifth color.

Available at

the local ice cream stand

Planned features for 2.0.0:

  • Display review/lesson summary for each day on demand
    • Hour of day heatmap
    • Item type breakdown (done for lessons)
    • Item list (done for lessons)
    • SRS breakdown for reviews
    • Pass fail breakdown and accuracy for reviews
    • Level breakdown
    • Show difference on hover for review breakdowns
  • Click and drag between two dates to show stats in interval between them
    • Color setting
  • Minimize button (show only stats when minimized)
  • Manual start date
  • Upcoming reviews (numbers per day)
    • Burn indicator
    • Current level indicator
      • Setting to ignore vocab
  • Hour to count as start of day
  • Auto ranging
  • Percentage on total lessons
  • Optional letters to the left to indicate which day of the week each row corresponds to

Known bugs:

  • Stops working in April 2019 in a specific timezone due to an unresolved bug in the heatmap library.

Heat Map Stories! (WaniKani Activity Chart)
The New And Improved List Of API and Third Party Apps
Wanikani Open Framework [developer thread]
What do you want now? (Request extensions here)
Review heatmap script?
Is there a way to get Anki like timeline for statistics in wanikani
Level 60 in more than 350 days :D
I finally broke my record!
Level 60 in less than a year (350 days)
うちはは を なめるな!- My Level 60 Post
My Journey of 368 days (+ The Ultimate Guide for WK :open_book: )
Wanikani Open Framework [developer thread]
Could we have an option for removing the 42 lesson/review limit?
Level 60 in more than 350 days :D
My Journey of 368 days (+ The Ultimate Guide for WK :open_book: )

Nice script. You should add a note that WKOF is a prerequisite (and what it is/link) and is not bundled in the heatmap script, and if possible add a notification to the heatmap script that the WKOF is missing (dialog or whatever).

It will be easier for first-time users.



Maybe follow WK colors (from apprentice, guru, master…)



I have been tricked (ಥ_ʖಥ)



I thought I did
You didn’t get an alert?

// Make sure WKOF is installed
		if (!wkof) {
				var response = confirm('WaniKani Heatmap requires WaniKani Open Framework.\n Click "OK" to be forwarded to installation instructions.');
				if (response) window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549';

I did try that, but it got rather messy. I think having a spectrum is more intuitive. Thanks for the suggestion though. I don’t really like the current colors.



Nope, no window.

I am not exactly sure how Tampermonkey works in Firefox, but the script itself is executed in the strict mode. In strict mode, they did some changes with the strict mode and undeclared variables… not really sure what (I am not a JS developer), the code itself is run in the eval() (or apply() or something).

Anyway, when I debug the code, once I reach the if (!wkof), the ReferenceError is thrown, unless I enable the WKOF in the Tapermonkey dashboard.

I guess the reason is same as why this (fix quotes, not sure why are they changed in the post):
(function() {“use strict”; eval(“if (!wk) { console.log(1);} else {console.log(2);}”); }())

throw ReferenceError: wk is not defined when I run it in the console.



Huh. I didn’t know about that. @rfindley do you know if there’s a good reason why Firefox would throw a ReferenceError? Should we maybe use a try-catch instead of if (!wkof)?

It’s wkof, not wk. Does it work with wkof?



Thanks so much for this! It’s really interesting to see.



Could change it to:

if (!window.wkof) ...

Or don’t turn on strict in your script (though I don’t know whether there’s a setting to make it default to strict, in which case some people may still have problems.).



I don’t have 'use strict' in the script, so I would assume it’s something on their end. I’ll use just put var wkof = window.wkof in my scripts from now on

1 Like


Awesome!! Looks very nice, thank you!
I love my review heatmap in Anki. I was not sooo excited about getting it for WaniKani since I could imagine what it would look like anyway (who doesn’t painfully remember when you had those few weeks where you didn’t review) but now that I see it, I love it :slight_smile:

In case you are interested in extending this further, here’s a screenshot of the info that the Anki plugin shows below the heatmap. This is also super motivating, I look at it even more than at the actual heatmap:



Sounds like good info for an update at some point ukKr5



I couldn’t wait :smiley:

Added no styling, just quickly threw something together. In case you want to reuse it. It is called in the same way as create_heatmap:

    function create_streakinfo(data) {
        var streakinfoSection = document.createElement('section');
        $(streakinfoSection).attr("class", "streakinfo");

        var daysWithReviews = 0;
        var daysWithoutReviews = 0;
        var longestStreak = 0;
        var totalReviews = 0;

        //get date without time (00:00) in order to match date in data
        let firstDate = new Date(new Date(data.first_date).getFullYear(), new Date(data.first_date).getMonth(), new Date(data.first_date).getDate());
        let lastDate = new Date(new Date(data.last_date).getFullYear(), new Date(data.last_date).getMonth(), new Date(data.last_date).getDate());

        var currentDate = firstDate;
        var currentStreak = 0;
        var previousDayHadReviews = false;

        while (currentDate <= lastDate) {
            var dateInSeconds = currentDate.getTime() / 1000;
            var count = data.counts[dateInSeconds];
            if (count) {
                if (previousDayHadReviews) {
                totalReviews += count;
                previousDayHadReviews = true;
            } else {
                if (currentStreak > longestStreak) {
                    longestStreak = currentStreak;
                currentStreak = 0;
                previousDayHadReviews = false;
            currentDate.setDate(currentDate.getDate() + 1);
        if (currentStreak > longestStreak) longestStreak = currentStreak;
        let averageReviews = Math.round(totalReviews / (daysWithReviews + daysWithoutReviews));
        let percentageWithReviews = Math.round(daysWithReviews / ((daysWithReviews + daysWithoutReviews) / 100));

        streakinfoSection.append("Average daily reviews: " + averageReviews + " Studied on " + percentageWithReviews + "% of days (" + daysWithReviews + " out of " + (daysWithReviews + daysWithoutReviews) + ") Longest streak: " + longestStreak + " Current streak: " + currentStreak );

(I also didn’t double check super duper carefully so the calculation might be a bit off; it “felt right” and I decided I was done :wink: )



It looks super cool! Small idea, it might be fun to see when you had WaniKani on vacation mode. Is it possible to add that?



I pretty much never use strict mode, and I’d still expect it to throw an error if it doesn’t have “window.” in front and the variable hasn’t been declared or assigned yet. That’s just normal JavaScript. Maybe greasemonkey/tampermonkey handles that differently somehow?

1 Like


I like it! And the colors seem fine to me.

Minor thing: it time travels.



Seems like you wouldn’t want that to throw an error if the state of being undefined was one of the conditions you were trying to test. How would you get a false? or true for if-not, ykwim



Nice script Kumi! For colors, maybe yellow to dark red? It’s is a heat map after all.

This is really one of those things that @viet and @oldbonsai should implement as a proper feature though…



Hey, you made it! Thanks Kumi! You’re awesome.

1 Like



I definitely started on July 4th, is there no data prior to August 4th?