Overleaf Toolbar Word Count

Show live word count in the Overleaf PDF toolbar

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Overleaf Toolbar Word Count
// @namespace    parnavh.dev
// @version      2026-08-04
// @description  Show live word count in the Overleaf PDF toolbar
// @match        https://www.overleaf.com/project/*
// @grant        none
// @author       parnavh
// @icon         https://www.google.com/s2/favicons?sz=64&domain=overleaf.com
// @license MIT
// ==/UserScript==

(function () {
    'use strict';

    let counter;

    async function updateWordCount() {
        try {
            const res = await fetch(location.pathname + "/wordcount", {
                credentials: "same-origin",
                cache: "no-store"
            });

            if (!res.ok) return;

            const { texcount } = await res.json();

            counter.textContent = `Words: ${texcount.textWords.toLocaleString()}`;
        } catch (e) {
            console.error("Word count failed", e);
        }
    }

    function install() {
        if (document.getElementById("tm-word-count"))
            return false;

        const toolbar = document.querySelector(".toolbar-pdf-left");
        if (!toolbar)
            return false;

        counter = document.createElement("span");
        counter.id = "tm-word-count";
        counter.textContent = "Words: ...";

        counter.style.cssText = `
            font-size:14px;
        `;

        toolbar.appendChild(counter);

        updateWordCount();

        const compileBtn = document.querySelector(".compile-button");

        if (compileBtn) {
            const compileObserver = new MutationObserver(() => {
                if (compileBtn.dataset.olLoading === "false") {
                    updateWordCount();
                }
            });

            compileObserver.observe(compileBtn, {
                attributes: true,
                attributeFilter: ["data-ol-loading"]
            });
        }

        return true;
    }

    // Wait until Overleaf has rendered
    const observer = new MutationObserver(() => {
        if (install()) {
            observer.disconnect();
        }
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
})();