Bluesky Post Monitor (unofficial)
Pricing
from $1.00 / 1,000 posts
Bluesky Post Monitor (unofficial)
Unofficial monitor for public Bluesky author feeds, keywords, and hashtags. Drops deleted posts and can return only new posts across runs. Not affiliated with Bluesky.
Pricing
from $1.00 / 1,000 posts
Rating
0.0
(0)
Developer
Olalekan Johnson
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Watch public Bluesky posts from an author feed, a keyword, or a hashtag, and keep only the posts that are still on the network when the run fetches them. Optional new-post tracking skips URIs this Actor already saved.
This Actor is not affiliated with, endorsed by, or maintained by Bluesky, Bluesky Social, PBC, or the AT Protocol team. It is an independent client of Bluesky's public AppView. It never posts, likes, follows, replies, or sends a notification.
What you can do with it
- Snapshot a public profile feed, starting with the default handle
bsky.app, with no Bluesky account. - Search recent posts for a phrase, or collect a hashtag.
- Run several handles or phrases in one go. Each value is requested on its own, then rows are de-duplicated by post URI.
- Schedule New posts only so the next run returns posts you have not already saved for that state namespace.
- Drop posts whose text contains an exclude keyword.
Social listening, PR checks, and research exports are the intended use. The Actor is read-only.
What works without a login
Checked against the live AppView on 23 October 2026:
GET https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeedreturns posts with no token. Author mode is the default, and it is what the Apify daily test runs.GET https://public.api.bsky.app/xrpc/app.bsky.feed.searchPostscurrently returns an HTML 403 from the edge. That response is not a JSON "please log in" error.GET https://api.bsky.app/xrpc/app.bsky.feed.searchPostsreturns search results with no token. Search requires theqparameter. Hashtags are sent asqplustag.
Search and hashtag modes call api.bsky.app directly so they do not depend on the blocked public host. If Bluesky later refuses those calls with HTTP 401 or 403, add your handle and an app password (created in the Bluesky app's settings, not your main password). The password field is secret. It is not printed in the log, not saved on the post, and not written into the seen-URI store. Leave both login fields empty for the public author feed.
The Actor follows Bluesky's developer guidelines for a read-only client: it does not generate interactions, and it does not keep a copy of a post the AppView no longer returns as a live record. Deleted, missing, and blocked post views are dropped. Past dataset rows from earlier runs stay where they are, because Apify datasets are append-only; this run simply will not write that post again.
Input
Author feed, no login:
{"mode": "author","queries": ["bsky.app"],"maxPosts": 5,"newPostsOnly": false}
Keyword watch across runs:
{"mode": "search","queries": ["apify", "web scraping"],"excludeKeywords": ["hiring"],"since": "2026-10-01T00:00:00Z","newPostsOnly": true,"stateNamespace": "brand-watch","maxPosts": 50}
Hashtag:
{"mode": "hashtag","queries": ["python"],"maxPosts": 20}
Optional login, only if search is refused:
{"mode": "search","queries": ["bluesky"],"identifier": "yourname.bsky.social","appPassword": "xxxx-xxxx-xxxx-xxxx"}
| Field | Notes |
|---|---|
| Mode | author, search, or hashtag |
| Queries | Handles, keywords, or tags. The @ and a leading # are optional |
| Exclude keywords | Case-insensitive, applied to post text |
| Posted since | ISO date or datetime. Also sent to search |
| New posts only | Skip URIs already saved. Default off, so the daily test stays non-empty |
| State namespace | Separate watches in one account |
| Maximum posts | 1 to 200, default 5 |
| Maximum charge (USD) | Extra cap, with the Apify run cap. The lower one wins |
| Handle and app password | Optional. Both or neither |
A new-posts run that finds nothing new succeeds. Any other run that saves nothing fails, including a login failure or a handle the AppView does not know.
Output
{"uri": "at://did:plc:example/app.bsky.feed.post/3abc","cid": "bafyrei...","url": "https://bsky.app/profile/bsky.app/post/3abc","authorHandle": "bsky.app","authorDid": "did:plc:example","authorDisplayName": "Bluesky","text": "Post text as returned by the AppView.","createdAt": "2026-10-22T18:00:00.000Z","indexedAt": "2026-10-22T18:00:01.000Z","langs": ["en"],"tags": ["example"],"likeCount": 12,"repostCount": 2,"replyCount": 1,"quoteCount": 0,"replyTo": null,"embedType": null,"matchedQuery": "bsky.app"}
SUMMARY in the default key-value store has the post count, the estimated charge, whether the run authenticated, and errors. It does not contain the app password or the access token.
Pricing
Pay per event. The only custom event is post. Do not price apify-default-dataset-item, or each saved post would be billed twice. Set post as the primary event.
| Event | Price | When it fires |
|---|---|---|
apify-actor-start | $0.005 | Once per run, by the platform (memory is capped at 1 GB, so once). The Actor does not call Actor.charge for it. |
post | $0.001 | One live public post was saved |
One hundred posts cost $0.005 + 100 × $0.001 = $0.105. Platform usage is not billed to you. The Actor stops when the next post would pass the run maximum charge or maxChargeUsd. Posts that were deleted, blocked, excluded by keyword, older than since, or already seen are not charged.
FAQ
Is this an official Bluesky product? No. It calls Bluesky's public HTTP API the same way any other read-only client can. The listing must not imply a partnership.
Why does the default use an author feed instead of search?
The daily test has to return data with the prefilled input and no secrets. Author feeds on public.api.bsky.app do that today. Search is available as a mode, on the host that currently allows it without a token.
Do I have to create a Bluesky account? No. Add a handle and app password only if a search or hashtag request comes back unauthorized. The password input is marked secret and is not required, so the daily test is not skipped.
What happens to deleted posts? If the AppView returns a not-found or blocked view, or a record that is no longer a post, that post is not saved. The seen store holds URIs, not text, so this Actor is not a private archive of deleted posts. Rows written by an earlier run remain in that run's dataset.
Can one run watch several keywords? Yes. Put them in queries. A post that matches two queries is saved once.
Does it respect Bluesky's developer guidelines? It is a read-only monitor: no automated follows, likes, replies, or other interactions that would notify someone. It drops posts the API says are gone. Broader duties in those guidelines (in-app reporting tools, a public contact address) apply to products that publish user-generated content of their own. This Actor does not.
Limits
- Public AppView reads only. No private profiles, no mutes, no DMs.
- Search availability can change. The 23 October 2026 check found unauthenticated search on
api.bsky.appand an edge block onpublic.api.bsky.app. The optional app password is the fallback. - At most five pages per query, and at most 200 saved posts per run.
- Seen URIs are capped at 10,000 per namespace.
- Counts (likes, reposts, replies) are whatever the AppView returned at fetch time.
- The client waits half a second between requests to the same host and retries server errors. It does not try to look like a browser.
- Platform usage is not billed to you; you pay only the events above.
Run it locally
From this directory, with monitor_core vendored beside the package:
mkdir -p storage/key_value_stores/defaultprintf '%s\n' '{"mode":"author","queries":["bsky.app"],"maxPosts":3}' > storage/key_value_stores/default/INPUT.jsonpython -m bluesky_post_monitor
Publish notes
Use limited permissions. Copy .actor/pay_per_event.json into pay-per-event monetization, with post as the primary event, and leave apify-default-dataset-item at $0 or remove it. Keep "unofficial" in the title.