Skip to main content
* tootsnoop - You Mastodon message statistics tool

# #+BEGIN_SRC sh :results output :wrap src
# uv run ./tootsnoop/__init__.py --help
# #+END_SRC

: usage: tootsnoop [-h] --days DAYNUMBER --count COUNTNUMBER [--flop FLOPNUMBER]
: [--flop-threshold SUMNUMBER] [--flop-min-age HOURS]
: [--hashtags [MIN_MESSAGES]] [--inactive] [--verbose]
:
: This tool prints a brief statistics about your Mastodon messages of the latest DAYNUMBER days.
:
: The output constist of:
: - timestamp (now)
: - number of toots retrieved
: - your current number of followers
: - the totals of boosts, favorites and replies of that period
: - top COUNTNUMBER most boosted messages (or less if no more found)
: - top COUNTNUMBER most favored messages (or less if no more found)
: - top COUNTNUMBER most replied messages (or less if no more found)
: - optionally: FLOPNUMBER least successful messages (see --flop)
: - optionally: a ranking of your hashtags (see --hashtags)
:
: Only your own messages are analyzed. Not taken into account are:
: - your boosts of other people's messages: those reactions belong to the original author
: - your direct messages: they are private and can not even be boosted
: Those messages are missing from all sections, including the number of retrieved toots.
:
: The list of least successful messages is restricted to messages that can be compared
: with each other fairly. It holds public messages only and no replies to other
: people (but the messages of your own threads). Other visibilities can not be boosted by
: everybody and a reply to somebody else was never meant to be spread, so both would end
: up in that list no matter how good they were. The hashtag ranking uses the same
: restriction.
:
: Example usages:
: uv run tootsnoop --days 7 --count 10
: … prints the topmost 10 entries for the last 7 days
: uv run tootsnoop --days 7 --count 10 --flop 5
: … additionally lists the 5 least successful messages
: uv run tootsnoop --days 7 --count 10 --flop 5 --flop-threshold 2
: … same, but only messages with at most 2 boosts+favorites+replies in total
: uv run tootsnoop --days 7 --count 10 --flop 5 --flop-min-age 24
: … same, but ignores messages younger than 24 hours for the flop list
: uv run tootsnoop --days 90 --count 10 --hashtags
: … additionally ranks your hashtags of the last 90 days (needs a long period)
:
: One-time setup:
:
: 1. Configure you access token:
: - Login to your Mastodon instance in your web browser.
: - Go to Preference → Development and click on "New Application".
: - Enter "tootsnoop" as the name of the new application and modify the scopes:
: - You will need only read permissions, no write permissions.
: - Submit and click on "tootsnoop".
: - Copy your new Access Token.
: - Paste this Access Token into a "access_token.txt" file in the main directory of this tool.
: 2. Configure your mastodon instance:
: - Paste the main URL of your Mastodon instance into a "instance_url.txt" file in the main
: directory of this tool.
: - It looks like: "https://graz.social"
:
: options:
: -h, --help show this help message and exit
: --days DAYNUMBER Number of days to look back
: --count COUNTNUMBER Number of topmost entries to show
: --flop FLOPNUMBER Number of least successful public entries to show (omit to skip
: this section)
: --flop-threshold SUMNUMBER
: Only list messages whose sum of boosts, favorites and replies is
: less or equal than SUMNUMBER (requires --flop)
: --flop-min-age HOURS Ignore messages younger than HOURS for the flop list because
: they had little time to gather reactions (requires --flop;
: default: all messages of the period are taken into account)
: --hashtags [MIN_MESSAGES]
: List the hashtags of your public messages, ranked by the median
: reactions of the messages carrying them (omit to skip this
: section). Only hashtags of at least MIN_MESSAGES messages are
: listed, because a single successful message carries a whole set
: of hashtags which say nothing about them (default: 5). Needs a
: long period to be meaningful.
: --inactive Generate inactive time-stamps instead of active (using square
: brackets instead of angle brackets)
: --verbose Enable verbose mode
:
: :copyright: (c) by Karl Voit <tools@Karl-Voit.at>
: :license: GPL v3 or any later version
: :URL: https://gitlab.com/publicvoit/tootsnoop
: :bugreports: via https://gitlab.com/publicvoit/tootsnoop/-/issues
: :version: 2026-07-16
: ·

Setup with [[https://docs.astral.sh/uv/][uv]]:

1. Install uv itself
2. Use =uv --project /path/to/tootsnoop run path/to/tootsnoop/__init__.py= command from above to run =tootsnoop=

Or:

Install via pip:

: pip install tootsnoop

... and start =tootsnoop -h=

* Example Output

: uv run tootsnoop --days 7 --count 3

<2026-07-16 Thu 16:41> Summary of Mastodon Activity over the last 7 days:

- Toots retrieved: 45
- Current number of followers: 3450
- 60 boosts, 91 favorites, 36 replies → Period totals over all 45 analyzed messages (public, unlisted and followers-only)
- 1.3 boosts/message, 2.0 favorites/message, 0.8 replies/message
- 1.0 reactions → Typical (median) message: half of them reached more, half less
- 60 boosts, 79 favorites, 19 replies → Period totals over the 22 public messages
- 2.7 boosts/message, 3.6 favorites/message, 0.9 replies/message
- 4.5 reactions → Typical (median) message: half of them reached more, half less

*Top 3 Boosted Messages*

- 13 Boosts: [[https://graz.social/users/publicvoit/statuses/116916868164249149][<2026-07-14 Tue 06:17>]] «Reproduce it yourself: show that [[https://graz.social/tags/xAI][#xAI]]'s [[https://graz.social/tags/Grok][#Grok]] Build CLI uploads your entire repository --- every tracked file plus full git history --- to xAI's cloud (POST /v1/storage, routed to the GCS bucket grok-code-session-traces), independent of what the agent reads, and that turning off "Improve the model" does not stop it.» • GitHub - cereblab/grok-build-exfil-repro\\ [[https://github.com/cereblab/grok-build-exfil-repro][https://github.com/cereblab/grok-build-exfil-repro]] • [[https://graz.social/tags/security][#security]] [[https://graz.social/tags/privacy][#privacy]] [[https://graz.social/tags/ai][#ai]]
- 11 Boosts: [[https://graz.social/users/publicvoit/statuses/116906833376882076][<2026-07-12 Sun 11:45>]] [[https://graz.social/tags/DistroFighter][#DistroFighter]] --- find your Linux distro & desktop\\ [[https://distrofighter.com/][https://distrofighter.com/]] • This is a hilarious [[https://graz.social/tags/Linux][#Linux]] distribution + [[https://graz.social/tags/DesktopEnvironment][#DesktopEnvironment]] chooser [[https://graz.social/tags/game][#game]] 🤓 • For my preferences, Debian/KDE won. Just the environment I'm currently working with. 👍 • Finalists were Kubuntu (I've been using it for 15-20 years!) and Hyprland (which never crossed my path so far).
- 9 Boosts: [[https://graz.social/users/publicvoit/statuses/116917827094906240][<2026-07-14 Tue 10:21>]] Happy Birthday [[https://graz.social/tags/LinuxCaf%C3%A9][#LinuxCafé]] [[https://graz.social/tags/Graz][#Graz]] im Juli! Wir sehen uns in einer Woche am 21. Juli ab 17:00 Uhr!\\ [[https://events.graz.social/p/Das-Linux-Cafe-wird-im-Juli-ein-Jahr-alt-CTA62T7Y3pwDvaKPm68PUN][https://events.graz.social/p/Das-Linux-Cafe-wird-im-Juli-ein-Jahr-alt-CTA62T7Y3pwDvaKPm68PUN]] • Wenn du Fragen zu freier Software hast, dein altes/langsames Windows-Notebook mit Linux ausprobieren möchtest, oder dich einfach mit netten Techniker:innen unterhalten möchtest: einfach im Café Kork vorbeischauen! 👋 • [[https://graz.social/tags/diday][#diday]] [[https://graz.social/tags/Linux][#Linux]] [[https://graz.social/tags/FOSS][#FOSS]] [[https://graz.social/tags/digitalesouveranitat][#digitalesouveranitat]] [[https://graz.social/tags/LinuxCafe][#LinuxCafe]]

*Top 3 Most Favored Messages*

- 11 Favorites: [[https://graz.social/users/publicvoit/statuses/116916868164249149][<2026-07-14 Tue 06:17>]] «Reproduce it yourself: show that [[https://graz.social/tags/xAI][#xAI]]'s [[https://graz.social/tags/Grok][#Grok]] Build CLI uploads your entire repository --- every tracked file plus full git history --- to xAI's cloud (POST /v1/storage, routed to the GCS bucket grok-code-session-traces), independent of what the agent reads, and that turning off "Improve the model" does not stop it.» • GitHub - cereblab/grok-build-exfil-repro\\ [[https://github.com/cereblab/grok-build-exfil-repro][https://github.com/cereblab/grok-build-exfil-repro]] • [[https://graz.social/tags/security][#security]] [[https://graz.social/tags/privacy][#privacy]] [[https://graz.social/tags/ai][#ai]]
- 11 Favorites: [[https://graz.social/users/publicvoit/statuses/116908992628482759][<2026-07-12 Sun 20:54>]] Kleine Wagen, große Freiheit: [[https://graz.social/tags/Fahrradwohnwagen][#Fahrradwohnwagen]]-Treffen Waakhausen 2026\\ [[https://reisemobil-international.de/wohnwagen/kleine-wagen-grosse-freiheit-fahrradwohnwagen-treffen-waakhausen-2026/][https://reisemobil-international.de/wohnwagen/kleine-wagen-grosse-freiheit-fahrradwohnwagen-treffen-waakhausen-2026/]] • Coole Fotos aus einer sehr lässigen Community von Menschen, die sich einen [[https://graz.social/tags/DIY][#DIY]] [[https://graz.social/tags/Wohnwagen][#Wohnwagen]] fürs [[https://graz.social/tags/Fahrrad][#Fahrrad]] gebaut haben. • [[https://graz.social/tags/Camper][#Camper]]
- 8 Favorites: [[https://graz.social/users/publicvoit/statuses/116900129296644466][<2026-07-11 Sat 07:20>]] "Dieser Hersteller stellt sich gegen den DÜMMSTEN TREND der Fahrradbranche" - [[https://graz.social/tags/SuperBicycles][#SuperBicycles]]\\ [[https://www.youtube.com/watch?v=6sOkfpULh_Q][https://www.youtube.com/watch?v=6sOkfpULh_Q]] • Interessanter [[https://graz.social/tags/Lastenrad][#Lastenrad]]-Hersteller aus Berlin: günstig, maximal gut wartbar, [[https://graz.social/tags/DIY][#DIY]]-affin mit viel Zubehör als 3D-Druck-Komponenten zum Selbermachen, Pläne im Netz, ... • [[https://graz.social/tags/SUPERmighty][#SUPERmighty]] als der [[https://graz.social/tags/Longjohn][#Longjohn]]-Klassiker aber immer noch kompakt.\\ [[https://graz.social/tags/SUPERmini][#SUPERmini]] als wendiges, kleines Lastenrad.\\ [[https://graz.social/tags/SUPERmightyjr][#SUPERmightyjr]] als Lastenrad für Kinder! 👍 • [[https://super-bicycles.com/][https://super-bicycles.com/]] • Händlernetz schaut ebenfalls bereits gut ausgebaut aus.

*Top 3 Most Replied Messages*

- 4 Replies: [[https://graz.social/users/publicvoit/statuses/116900534104605803][<2026-07-11 Sat 09:03>]] Ich habe mich spaßhalber (ohne aktuellen Bedarf) über [[https://graz.social/tags/Tim][#Tim]] [[https://graz.social/tags/Graz][#Graz]] informiert: [[https://www.tim-oesterreich.at/graz/][https://www.tim-oesterreich.at/graz/]] (#Carsharing) • Registrierung 15€ + monatlich 9,50€ (bei [[https://graz.social/tags/Klimaticket][#Klimaticket]] entfallen beide)\\ Kleinwagen ab 5,90€/Stunde und 50km max (danach pro km 0,25€)\\ Mindestlaufzeit 1 Jahr. • Ohne vorhandenem Klimaticket möchte man das vermutlich nicht mal so nebenbei ausprobieren. • Leider hat die Android App recht schlechte Bewertungen im Play Store. Hat hier jemand Erfahrung mit dem Service (und der App) und möchte kurz berichten? • [[https://graz.social/tags/TimGraz][#TimGraz]]
- 4 Replies: [[https://graz.social/users/publicvoit/statuses/116896392039254693][<2026-07-10 Fri 15:29>]] Wie lange noch werden wir diese coolen 6er-Abteile bei der [[https://graz.social/tags/%C3%96BB][#ÖBB]] vorfinden? • Obwohl: das war in einem [[https://graz.social/tags/NightJet][#NightJet]] - welche modernen Garnituren gibt's denn, wo man die Sitze zu drei Liegeflächen zusammenschieben kann? 🤔
- 2 Replies: [[https://graz.social/users/publicvoit/statuses/116906833376882076][<2026-07-12 Sun 11:45>]] [[https://graz.social/tags/DistroFighter][#DistroFighter]] --- find your Linux distro & desktop\\ [[https://distrofighter.com/][https://distrofighter.com/]] • This is a hilarious [[https://graz.social/tags/Linux][#Linux]] distribution + [[https://graz.social/tags/DesktopEnvironment][#DesktopEnvironment]] chooser [[https://graz.social/tags/game][#game]] 🤓 • For my preferences, Debian/KDE won. Just the environment I'm currently working with. 👍 • Finalists were Kubuntu (I've been using it for 15-20 years!) and Hyprland (which never crossed my path so far).

* Optional: Listing Least Popular Messages
:PROPERTIES:
:CREATED: [2026-07-16 Thu 18:27]
:END:

Besides your most popular messages, you may be interested in the other end of the scale: the messages that did *not* work out. Add =--flop FLOPNUMBER= to get an additional section listing your least successful messages:

: uv run tootsnoop --days 7 --count 3 --flop 3

The messages are sorted by the *sum of their boosts, favorites and replies*, lowest first. Messages with the same sum are listed oldest first: they had the most time to gather reactions and therefore are the more meaningful flops.

Each entry shows that sum followed by a breakdown of =B=oosts, =F=avorites and =R=eplies:

*3 Least Successful Public Messages*

- 0 (B:0 F:0 R:0): [[https://graz.social/users/publicvoit/statuses/116917931559185927][<2026-07-14 Tue 10:47>]] [[https://graz.social/tags/Graz][#Graz]]|er Glacis ist wochenlang Großbaustelle und wird gesperrt\\ [[https://steiermark.orf.at/stories/3362427/][https://steiermark.orf.at/stories/3362427/]] • Radweg bleibt offen.
- 1 (B:0 F:0 R:1): [[https://graz.social/users/publicvoit/statuses/116896043154784469][<2026-07-10 Fri 14:01>]] [[https://en.osm.town/@opencage][@opencage]] At least in my Mastodon clients, your geoweirdness-threads appear in random order. • Are you aware of that issue?
- 1 (B:1 F:0 R:0): [[https://graz.social/users/publicvoit/statuses/116905795049999631][<2026-07-12 Sun 07:21>]] Hackerangriff gegen argentinischen Fußballverband: Spuren nach [[https://graz.social/tags/%C3%84gypten][#Ägypten]]\\ [[https://www.derstandard.at/story/3000000331103/hackerangriff-gegen-argentinischen-fussballverband-spuren-nach-aegypten?ref=rss][https://www.derstandard.at/story/3000000331103/hackerangriff-gegen-argentinischen-fussballverband-spuren-nach-aegypten?ref=rss]] • Ich bin zwar kein Fußballfan aber wenn ich mal was davon sehe, habe ich ein Herz für die Underdogs. 🫶 • Allerdings ist man ein so schlechter Verlierer, hatte man den Sieg nie verdient. Go home [[https://graz.social/tags/Egypt][#Egypt]], you're drunk. 😞 • [[https://graz.social/tags/ArgEgy][#ArgEgy]] [[https://graz.social/tags/Sicherheit][#Sicherheit]] [[https://graz.social/tags/security][#security]] [[https://graz.social/tags/WM2026][#WM2026]] [[https://graz.social/tags/Phishing][#Phishing]]

The breakdown tells you *which* kind of reaction was missing. A message with favorites but zero boosts was appreciated but not worth spreading - which is a different kind of failure than a message that nobody reacted to at all.

** What Is Not Listed

This list is restricted to messages that can be compared with each other fairly:

- *Public messages only*: only they can be found and boosted by everybody. A followers-only message can not be boosted by anyone, so its boost count is always zero and it would end up in this list no matter how good it was. Direct messages are not part of any statistics at all.
- *No replies to other people*: a reply is a contribution to somebody else's conversation and was never meant to be spread. Nobody boosts a "Yes, I agree" - so those replies would fill up this list although they did just fine as replies.

The messages of your *own threads* are listed: although they are replies as well, they are replies to yourself and therefore part of a message of your own.

Note that those restrictions apply to this list only. The other sections and the number of retrieved toots are not affected by them.

The two "Period totals" lines of the summary use the same public/non-public distinction, so you can compare the reactions of all your messages with those of your public ones.

Each of them is followed by two sub-items: the averages per message, and the median message. The median tells you what a *typical* message of yours achieved: half of them reached more reactions, half less. Whenever it is clearly below the averages, a few successful messages generate most of your reactions - the average then describes your output as a whole and not the message you are about to write.

** Optional: Limiting the List to a Threshold

If you are only interested in messages below a certain amount of reactions, add =--flop-threshold SUMNUMBER=. It lists only messages whose sum of boosts, favorites and replies is less or equal than that number:

: uv run tootsnoop --days 7 --count 10 --flop 5 --flop-threshold 2

This may result in fewer entries than =FLOPNUMBER= - or in none at all, which is good news: nothing did that badly.

** Optional: Ignoring the Most Recent Messages

A message published a few hours ago had little time to gather reactions and therefore shows up as a flop although it might do fine tomorrow. If that bothers you, add =--flop-min-age HOURS= to ignore messages younger than the given number of hours:

: uv run tootsnoop --days 7 --count 10 --flop 5 --flop-min-age 24

By default, *all* messages of the period are taken into account. This is perfectly fine if you generate your statistics at a time when your recent messages already had their chance.

* Optional: Ranking Your Hashtags

Adding =--hashtags= lists the hashtags of your public messages, ranked by the median reactions of the messages carrying them:

: uv run tootsnoop --days 90 --count 10 --hashtags

: *Hashtags of at Least 5 Public Messages*
:
: - 5.0 reactions → Typical (median) message of the 182 messages this ranking is based on
:
: - 16.0 median of 6 messages (6-27 reactions): [[https://graz.social/tags/linux][#linux]]
: - 14.0 median of 9 messages (10-27 reactions): [[https://graz.social/tags/microsoft][#microsoft]]
: - 12.0 median of 5 messages (3-16 reactions): [[https://graz.social/tags/fediverse][#fediverse]]
: - 10.0 median of 11 messages (1-25 reactions): [[https://graz.social/tags/security][#security]]

Compare each hashtag with the typical message printed above the ranking: in this example, the messages tagged =#microsoft= reached about three times the reactions of a typical message - and the range tells you that not a single one of those nine fell below ten reactions.

*This section needs a long period.* Over a week, hardly any hashtag of yours collects enough messages to say anything. Use =--days 90= or more.

** Why the Median and a Minimum Number of Messages

Both exist to prevent the same effect: a single successful message usually carries a whole *set* of hashtags. One message with 60 reactions and nine hashtags would push all nine of them to the top of a ranking based on averages, which would then report that one message nine times and present it as nine findings about your hashtags.

- The *median* only rises if the majority of the messages of a hashtag did well. A hashtag riding a single lucky message has an unremarkable median and stays where it belongs.
- The *minimum number of messages* drops hashtags used too rarely to be told apart from the messages carrying them. It defaults to 5 and can be set via =--hashtags MIN_MESSAGES=, e.g. =--hashtags 3=. Lower it and you get more entries of less meaning.

Hashtags used on exactly the same messages (like =#win11= and =#windows11=) can not be told apart by any of those figures and therefore share one entry.

When the data does not carry the ranking, the output says so instead of pretending otherwise: it warns you when no hashtag reaches the minimum, and when the period holds too few messages to judge.

** What You Can and Can Not Derive From It

A hashtag is a *label* of your content and not a lever. A hashtag well above your typical message tells you that your audience likes the *topic* behind it. It does *not* tell you that adding that hashtag to an unrelated message would do anything for it.

Keep in mind as well:

- Hashtags far apart in the ranking may still differ by chance only - the more so the fewer messages they have. Trust an entry of many messages with a narrow range far more than a close call between two entries at the minimum.
- The ranking only knows the topics you already write about. It can confirm what your audience likes about your current messages, but it can not point you to a topic you never posted about.

* Optional: Convert Result to a Different Syntax
:PROPERTIES:
:CREATED: [2025-02-04 Tue 16:42]
:END:

If you don't like [[https://gitlab.com/publicvoit/orgdown/][orgdown syntax]] as output, you might convert the script output on-the-fly via [[https://pandoc.org/][pandoc]].

Here is an example for [[https://karl-voit.at/2017/09/23/orgmode-as-markup-only/][the inferior Markdown syntax]] (in one flavour of many):

: uv --project /path/to/tootsnoop run /path/to/tootsnoop/__init__.py --days 1 --count 3 | pandoc --from org --to markdown --wrap=none

* Optional: Integration into Emacs Org-mode
:PROPERTIES:
:CREATED: [2025-02-04 Tue 16:50]
:END:

In case you want to invoke tootsnoop from within [[https://karl-voit.at/orgmode/][Emacs Org-mode]], you can use a source block like that:

: #+BEGIN_SRC sh :results output raw
: cd /path/to/tootsnoop/
: uv --project /path/to/tootsnoop run /path/to/tootsnoop/tootsnoop/__init__.py --days 7 --count 10 --inactive
: #+END_SRC

If you've installed tootsnoop via =pip= this might probably work (not tested):

: #+BEGIN_SRC sh :results output raw
: tootsnoop --days 7 --count 10 --inactive
: #+END_SRC

* Optional: A Reccuring Job That Generates a Weekly Statistics
:PROPERTIES:
:CREATED: [2025-02-06 Thu 19:45]
:END:

This is particularily interesting to people using [[https://karl-voit.at/orgmode/][Emacs Org-mode]]: I
want a weekly statisics generated each Sunday at 23:59.

For that, I created a shell script that contains the command to generate that statistics:

#+BEGIN_SRC bash
#!/usr/bin/env bash

TEMPFILE=$(mktemp) ## used to storing the tootsnoop output
NOW_IN_ORG_TIMESTAMP="<`date '+%Y-%m-%d %a %H:%M'`>" ## time-stamp for Org heading
TARGET_REFILE_ORG_FILE="notes.org"
TARGET_REFILE_HEADING="Weekly Mastodon statistics"

## adding a custom refile code snippet that
## moves the heading to the desired heading
## after inspecting and on invoking C-c C-c:
echo -e "\n#+BEGIN_SRC emacs-lisp\n(my-org-refile \"${TARGET_REFILE_ORG_FILE}\" \"${TARGET_REFILE_HEADING}\")\n#+END_SRC\n\n" > ${TEMPFILE}

## generate the statistics:
cd /path/to/tootsnoop/
uv --project /path/to/tootsnoop run /path/to/tootsnoop/__init__.py --days 7 --count 10 --inactive 2>&1 >>${TEMPFILE}
if [ "$?" != 0 ]; then
echo "tootsnoop execution had an issue."
appendorgheading --output ~/org/inbox.org \
--level 1 \
--title "${NOW_IN_ORG_TIMESTAMP} Weekly Mastodon Statistics: ERROR" \
--filecontent ${TEMPFILE} \
--daily --quiet
exit 1
fi

## appends a new Orgdown heading to the output file with the statistics as body:
appendorgheading --output ~/org/inbox.org \
--level 1 \
--title "${NOW_IN_ORG_TIMESTAMP} Weekly Mastodon Statistics" \
--filecontent ${TEMPFILE} \
--blocktype NONE --nosanitize \
--nodaily --quiet

rm "${TEMPFILE}" ## remove temporary file
#end
#+END_SRC

This script requires:

- my other script: https://github.com/novoid/appendorgheading
- e.g., via =pip install appendorgheading=
- an Orgdown file where the results gets appended
- an Orgdown heading title within that Orgdown file where this should get manually refiled to
- proper script paths (please adapt accordingly)

What it does:

- it generates a weekly statistics (7 days, top 10 each) with inactive time-stamps
- a handy babel snippet which refiles the heading to its final destination (after I took a brief look at it in my inbox file)

If you understand, what's going on, this is really a nice way of running tootsnoop. ;-)

* Related Projects
:PROPERTIES:
:CREATED: [2025-02-10 Mon 11:25]
:END:

This is a far-from-complete list of projects with similar goals:

- <2024-09-18 Wed> Sacha Chua did [[https://sachachua.com/blog/2024/09/archiving-public-toots-on-my-blog/][an Elisp implementation of archiving
her toots]]. I might have used her code as an starting point if I had
read it earlier.

- https://mastometrics.com/ is a cool service with analytical
features. I was using the service for many months, even spent a few
Euros for it until it stopped working for me (constantly re-indexing
without showing the most current results). Maybe it's working for
you?

* How to Thank Me
# --- BEGIN SHARED: how_to_thank_me --- see https://github.com/novoid/screencasts/

I'm glad if you like my tool. I've got way more projects on:

- [[https://github.com/novoid/][GitHub]] (oldest projects),
- [[https://gitlab.com/publicvoit/][GitLab.com]] (older projects), and
- [[https://codeberg.org/publicvoit/][Codeberg]] (newest projects).

If you want to support me:

- [[https://karl-voit.at/2018/06/07/cardware/][Send old-fashioned *postcard* per snailmail]] - I love personal feedback!
- see [[http://tinyurl.com/j6w8hyo][my address]]
- Send feature wishes or improvements as an issue
- Create issues for bugs
- Contribute merge requests for bug fixes
- Check out my other cool projects on the platforms above

If you want to contribute to this cool project, please fork and
contribute!

I am using [[http://www.python.org/dev/peps/pep-0008/][Python PEP8]] and occasionally some ideas from [[http://en.wikipedia.org/wiki/Test-driven_development][Test Driven
Development (TDD)]]. I fancy Python3 with [[https://typing.python.org/en/latest/spec/annotations.html][type annotations]], although I'm
not using them everywhere at the moment. Starting with 2025, I began
to use help from Claude.ai which is a huge improvement, given my lack
of programming practice and knowledge.

After all, each of my tools was developed because I needed its
functionality and could not get it elsewhere - at least to my
knowledge or taste.

# --- END SHARED: how_to_thank_me --- see https://github.com/novoid/screencasts/

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tootsnoop-2026.7.16.3.tar.gz (27.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tootsnoop-2026.7.16.3-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file tootsnoop-2026.7.16.3.tar.gz.

File metadata

  • Download URL: tootsnoop-2026.7.16.3.tar.gz
  • Upload date:
  • Size: 27.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for tootsnoop-2026.7.16.3.tar.gz
Algorithm Hash digest
SHA256 e6248490fd19771aa7e6daf7af6534708ec9b793e8f14219d0a1046a081bcbe4
MD5 51b3a8c0108c1530d4f06db0c71f7b67
BLAKE2b-256 22e88f3106f356ab52c6cdad237b75eddca4f6829e0f6c51b14e03bde477ba2f

See more details on using hashes here.

File details

Details for the file tootsnoop-2026.7.16.3-py3-none-any.whl.

File metadata

  • Download URL: tootsnoop-2026.7.16.3-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for tootsnoop-2026.7.16.3-py3-none-any.whl
Algorithm Hash digest
SHA256 5486d13c405fc451f131f1c0c9a0dd1c6651c8e81a42e20dfbdcec09189a90df
MD5 3a20342f5f3100d5862145d56cc800cd
BLAKE2b-256 c9ddb138f97608474df8b000fc1ef7b6722bd9a9531d0a19c67e5d97271356c9

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2026.7.16.3 This release

2 files

2026.7.16

2 files

2026.3.1.2

2 files

2026.3.1.1

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page