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와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 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
    });
})();