DEV Community

Emma Jansen
Emma Jansen

Posted on

A tiny script to track how many words I write per day

Word count goals get a lot of criticism, and some of it is fair. A thousand bad words aren't better than two hundred good ones. But on days when I'm drafting, a simple number tells me something useful: did I actually write today, or did I just rearrange commas?

Most editors show the word count of the current file. That's not what I want. I want to know how many words I added today across everything I work on. So I wrote a small script for it. It takes a snapshot of my writing folder once a day and compares it with yesterday.

The idea

  1. Count the words in every Markdown file in a folder.
  2. Save the total, with today's date, to a small CSV file.
  3. Show the difference from the previous entry.

That's all. No database, no app, no account.

The script

I wrote it in Python because it ships with most systems and handles text well. Save this as wordlog.py:

#!/usr/bin/env python3
"""Log the total word count of a writing folder once per day."""

import csv
import re
import sys
from datetime import date
from pathlib import Path

FOLDER = Path(sys.argv[1] if len(sys.argv) > 1 else "~/writing").expanduser()
LOG = FOLDER / ".wordlog.csv"
FRONTMATTER = re.compile(r"\A---\n.*?\n---\n", re.DOTALL)
CODE_BLOCK = re.compile(r"```

.*?

```", re.DOTALL)


def count_words(text: str) -> int:
    text = FRONTMATTER.sub("", text)
    text = CODE_BLOCK.sub("", text)
    return len(re.findall(r"\b[\w'-]+\b", text))


def total_words() -> int:
    return sum(
        count_words(p.read_text(encoding="utf-8", errors="ignore"))
        for p in FOLDER.rglob("*.md")
    )


def read_log() -> list[list[str]]:
    if not LOG.exists():
        return []
    with LOG.open(newline="") as f:
        return list(csv.reader(f))


def main() -> None:
    today = date.today().isoformat()
    total = total_words()
    rows = [r for r in read_log() if r and r[0] != today]
    previous = int(rows[-1][1]) if rows else total
    rows.append([today, str(total)])
    with LOG.open("w", newline="") as f:
        csv.writer(f).writerows(rows)
    print(f"{today}: {total} words total, {total - previous:+d} since last entry")


if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

A few choices worth explaining:

  • Frontmatter and code blocks are skipped. I don't want a YAML header or a pasted config file to count as writing.
  • Running it twice on the same day is safe. The script replaces today's row instead of adding a second one.
  • The log lives inside the folder as a hidden file, so it travels with the writing.

Running it

chmod +x wordlog.py
./wordlog.py ~/writing
Enter fullscreen mode Exit fullscreen mode

Output looks like this:

2026-10-21: 48210 words total, +734 since last entry
Enter fullscreen mode Exit fullscreen mode

Making it automatic

I don't want to remember to run it. On Linux or macOS, a cron job at the end of the day takes care of that. Open your crontab with crontab -e and add:

55 23 * * * /usr/bin/python3 /home/you/bin/wordlog.py /home/you/writing
Enter fullscreen mode Exit fullscreen mode

Adjust the paths for your system. If your machine is usually off at midnight, pick a time when it's on, or just run the script by hand when you finish for the day.

Reading the log

Because it's a plain CSV, you can open it in any spreadsheet and make a chart. For a quick look in the terminal, this prints the daily difference:

awk -F, 'NR>1 {print $1, $2-prev} {prev=$2}' ~/writing/.wordlog.csv
Enter fullscreen mode Exit fullscreen mode

The catch

This counts net words. On an editing day, when I cut a weak section, the number goes negative. At first that bothered me. Now I like it. A negative day usually means the piece got better, and seeing it written down reminds me that deleting is part of the work too.

If you want gross words written instead, you'd need to track changes per file, for example with git diff --word-diff and counting the added words. That's a nice next step, but the simple version has been enough for me.

Do you track your writing output at all, or does a number like this just add pressure?

Top comments (0)