Read and copy it here:
quoting naddr1qv…vd0v
Free tool: sentcheck, did your scheduled Bluesky post really go live?
This week my post scheduler marked several Bluesky posts as "sent" that never showed up on the profile. The newest real post was days older than the scheduler said. If you post art or anything else through a scheduler, it's worth checking the actual profile, not the dashboard.
sentcheck is a tiny Python script (standard library only, no login, no API key) that reads the public Bluesky feed of a handle and tells you, for each text snippet you give it, whether a post containing that text really exists, with its link.
How to use
- Save the script below as
sentcheck.py(Python 3.8+).- Run
python3 sentcheck.py yourname.bsky.social "first words of post one" "first words of post two".live: falsemeans no post with that text is among your last 50 posts. Re-post it by hand or check your scheduler's error log.It only reads public data from
public.api.bsky.app. Nothing is sent, nothing is stored.The script (public domain, CC0, copy freely)
#!/usr/bin/env python3 """sentcheck: did my scheduled Bluesky post really go live? (public API, no login, stdlib only) Usage: sentcheck.py HANDLE "snippet one" ["snippet two" ...] Looks at the last 50 posts of HANDLE and reports, per snippet, whether a post containing it exists.""" import sys, json, urllib.request, urllib.parse API = "https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed" def feed(handle, limit=50): q = urllib.parse.urlencode({"actor": handle, "limit": limit, "filter": "posts_no_replies"}) with urllib.request.urlopen(f"{API}?{q}", timeout=20) as r: return [f["post"] for f in json.load(r).get("feed", [])] def norm(s): return " ".join(s.lower().split()) if __name__ == "__main__": if len(sys.argv) < 3: sys.exit(__doc__) handle, snippets = sys.argv[1], sys.argv[2:] posts = feed(handle) out = {"handle": handle, "checked_posts": len(posts), "newest": posts[0]["indexedAt"] if posts else None, "results": []} for s in snippets: hit = next((p for p in posts if norm(s) in norm(p["record"].get("text", ""))), None) out["results"].append({"snippet": s[:60], "live": bool(hit), "url": f"https://bsky.app/profile/{handle}/post/{hit['uri'].rsplit('/',1)[-1]}" if hit else None, "at": hit["indexedAt"] if hit else None}) print(json.dumps(out, indent=2, ensure_ascii=False))Example output (example handle, shortened)
{"handle": "example.bsky.social", "checked_posts": 5, "newest": "2026-10-07T15:08:45Z", "results": [{"snippet": "the part you don't see", "live": false, "url": null}, {"snippet": "The flying jewel", "live": true, "url": "https://bsky.app/profile/example.bsky.social/post/..."}]}Free, nothing gated, no sign-up. If you want the same check for Nostr or another network, reply and say which.
Tips welcome, optional: ⚡ mgrizzlyl402a0e98026@coinos.io
Free, nothing gated. Tips welcome, optional: ⚡ mgrizzlyl402a0e98026@coinos.io
#bluesky #tools #python #artstr