Bluesky Keyword & Mention Alerts — Only New Posts
Pricing
from $3.00 / 1,000 new-posts
Bluesky Keyword & Mention Alerts — Only New Posts
Monitor Bluesky for keywords, mentions & hashtags on a schedule. Charges only for new posts. No login required.
Pricing
from $3.00 / 1,000 new-posts
Rating
0.0
(0)
Developer
Telemark Digital
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
0
Monthly active users
20 hours ago
Last modified
Categories
Share
Monitor Bluesky for keywords, mentions & hashtags on a schedule — and pay only for posts you haven't already seen. SKYLARK turns an Apify Schedule into a cheap, recurring alert feed for Bluesky (the AT Protocol network): every run returns only the new matched posts it has never delivered to your task before, fires a webhook when something new appears, and needs no Bluesky login for keyword, hashtag, and mention monitoring.
Unofficial and independent. This Actor is not affiliated with, endorsed by, or sponsored by Bluesky Social PBC.
If you're polling a stateless scraper ~250×/day to catch new posts, this is your bill cut. You stop paying to re-download and re-deduplicate the same posts every hour.
What does Bluesky Keyword & Mention Alerts do?
- Watches keywords, phrases, hashtags, and handles (a handle is watched two ways — its own new posts and new posts that mention it), all in one task, one merged deduplicated feed.
- Charges only for genuinely new posts. Duplicates, excluded terms, and off-language posts are filtered before billing. Seen IDs are retained for 30 days, subject to the documented state cap.
- Runs headless on a Schedule and pushes structured JSON to a dataset (download as JSON, CSV, Excel, or HTML) + an optional webhook payload for Slack / n8n / Make / any endpoint / an AI agent.
How much does it cost to monitor Bluesky? (honest, maxItems-aware)
| Your watch | SKYLARK (only-new) | A stateless scraper, re-scraped hourly |
|---|---|---|
| Quiet-to-moderate term (~0.3–2 new posts/run), hourly | ~$2–6 / month | ~$10.70–26.80 / month (capped at 10–25 posts/run) + you dedupe it yourself |
| Hot, all-new firehose term (100s new/run) | ~$3.00 / 1,000 new posts | ~$1.49 / 1,000 — cheaper per post; use a per-result scraper for this |
We are honest about the trade: on a quiet-to-moderate recurring watch — the actual monitoring use case — SKYLARK is 3–5× cheaper per month and hands you deduped, webhook-ready alerts with no downstream plumbing. On a hot term where every post is new, a per-result scraper is cheaper per post, and you should use one. SKYLARK owns the quiet-schedule loop, not one-shot bulk scraping.
Why use it?
- No app password required for keyword/hashtag/mention monitoring (competing "monitor" actors make you create and paste a Bluesky app password just to search).
- Durable, edit-safe state. History is keyed by your Task, not by a hash of your query — so adding or changing a keyword never resets or orphans what you've already seen.
- Arrays, not one string. Watch many keywords, handles, and hashtags in a single task with a single merged feed, plus
excludeTermsand language filters. - Engineered failover. A 3-path data chain (see Reliability below) instead of a single brittle endpoint.
- Webhooks + MCP. Fire-on-new webhooks for automation, and add this eligible paid Actor to an Apify MCP server for AI agents.
How to use it (2-minute quickstart)
- Click Try for free.
- Add at least one keyword, handle, or hashtag (e.g. keyword
bluesky monitor). - Click Start. The first run looks back 24 hours; every later run returns only what's new since the last one.
- Create a Task (top-right Create task) and attach a Schedule (e.g. every hour) — this is what turns SKYLARK into an isolated recurring monitor. Ad-hoc runs share one persistent per-user state scope, so Tasks are strongly recommended.
- (Optional) Paste a Webhook URL to get pushed the new posts the moment they appear.
Worked schedule example
Create a Task with this input, then add an hourly Schedule:
{"keywords": ["british museum", "bayeux tapestry"],"handles": ["bsky.app"],"hashtags": ["photography"],"excludeTerms": ["giveaway"],"langs": ["en"],"onlyNew": true,"maxPostsPerRun": 100,"webhookUrl": "https://hooks.example.com/your-endpoint"}
- Console: open the Task → Actions ▸ Schedule Actor → Every hour → Save.
- Each run charges
$0.002to start plus$0.003per new post; a quiet hourly watch idles at roughly $1.44/month of start fees and a few cents of new-post charges.
Integration recipes
The webhook fires only when there are new posts. Generic endpoints receive { "summary": {...}, "posts": [...up to 50 newest...] }; Slack Incoming Webhooks receive formatted text.
- n8n: add a Webhook node (HTTP POST), copy its URL into
webhookUrl.{{$json.body.posts}}is your array of new posts;{{$json.body.summary.newPosts}}is the count. - Make (Integromat): create a scenario starting with Webhooks ▸ Custom webhook, paste the address into
webhookUrl, then mapposts[]. - Slack: use a Slack Incoming Webhook URL directly as
webhookUrlfor a concise message with up to 10 post links, or route the generic payload through Make/n8n for custom formatting. - Generic / any endpoint / your own code: POST body shape:
{"summary": {"newPosts": 3,"matchedPosts": 3,"dataSourcePath": "P1","saturatedP1": false,"capped": false,"droppedCount": 0,"chargeLimitReached": false,"failureCount": 0,"charged": { "actorStart": 0.002, "newPost": 0.009 },"finishedAt": "..."},"posts": [{"uri": "...","url": "...","author": { "handle": "..." },"text": "...","matchedTerms": ["..."],"source": "keyword","isNew": true}]}
You can also skip the webhook and pull results from the dataset via the Apify API after each scheduled run.
Use it from an AI agent (MCP)
Add SKYLARK to your paid Actor tools at mcp.apify.com. An agent can then call it like:
"Watch Bluesky for mentions of
acme.bsky.socialand the keywordproduct recall, English only, and return only posts I haven't seen before."
which maps to { "handles": ["acme.bsky.social"], "keywords": ["product recall"], "langs": ["en"], "onlyNew": true }. The only-new semantics are exactly what agent polling wants — no duplicate context on every poll.
Input
Provide at least one of keywords, handles, or hashtags. All other fields are optional.
| Field | Type | Default | Description |
|---|---|---|---|
keywords | string[] | – | Full-text terms/phrases to watch. |
handles | string[] | – | Handles (± @). Each watched for its own posts and mentions of it. |
hashtags | string[] | – | Hashtags (± #). |
excludeTerms | string[] | [] | Drop posts containing any of these (case-insensitive), before billing. |
langs | string[] | [] | ISO 639-1 codes; empty = all. |
onlyNew | boolean | true | Return/charge only posts new to this task. Off = plain search (still charged per post). |
maxPostsPerRun | integer | 100 | Hard billing ceiling per run (1–800). |
webhookUrl | string | – | POSTed run summary + up to 50 newest posts, only when there are new posts. |
resetState | boolean | false | Wipe this task's seen-set + cursor and start fresh. |
Output
One dataset item per new matched post. Download as JSON, CSV, Excel, or HTML.
{"uri": "at://did:plc:gxbshd27.../app.bsky.feed.post/3mqcp2p7zgk2p","cid": "bafyreibuxa3ko...","url": "https://bsky.app/profile/mikeinindiana.bsky.social/post/3mqcp2p7zgk2p","author": {"did": "did:plc:gxbshd27...","handle": "mikeinindiana.bsky.social","displayName": "Mike Eads","avatar": "https://cdn.bsky.app/img/avatar/plain/…"},"text": "The Bayeux Tapestry is being moved to the British Museum next year…","createdAt": "2026-07-10T18:42:11.000Z","indexedAt": "2026-07-10T18:42:13.512Z","langs": ["en"],"likeCount": 14,"repostCount": 3,"replyCount": 2,"quoteCount": 0,"matchedTerms": ["british museum"],"source": "keyword","isNew": true}
| Field | Meaning |
|---|---|
uri | Stable post identity used to dedupe. |
cid | Content version identifier returned by Bluesky. |
url | Human-clickable post link. |
matchedTerms | Every input term that returned this post (emitted once even if multiple matched). |
source | keyword | hashtag | handle | mention. |
isNew | Whether this post was new to the task this run. |
Pricing
Pay-per-event, billed by Apify:
| Event | Price |
|---|---|
| Actor start (per run) | $0.002 |
| New post delivered | $0.003 ($3.00 / 1,000 new) |
Dataset writes and new-post charges use Apify's coupled PPE operation after dedup and filtering. Excluded, off-language, and already-seen posts are free. maxPostsPerRun and the buyer's maximum total charge cap the worst case of any single run.
State semantics
- "Only new" means: not present in this task's active seen-set. Dedup is by post
uri. - Task-keyed: state is stored per Apify Task, so editing keywords keeps your history. Ad-hoc (un-scheduled) runs are keyed per user — create a Task for real monitoring.
- Cursor: tracked by the server-assigned
indexedAttime (clamped to now), so future-dated spam posts can't break the monitor. First run looks back 24h. resetState: truewipes the seen-set and cursor once; turn it back off afterward.- TTL/cap: seen post IDs older than 30 days are pruned automatically, and the oldest IDs are evicted above 50,000 per task. A post can be delivered again after expiry or eviction.
Reliability & failover
SKYLARK uses a 3-path data chain and reports the active path as dataSourcePath in every run summary:
- P1 — no-login public API (default). Delivers up to 100 posts per term per poll. If a poll comes back a full 100-post page that's all new (
SATURATED_P1), that watch is auto-routed to the authenticated path to page out the backlog, and the run recommends a tighter schedule cadence. Choose a schedule frequent enough that fewer than 100 new posts arrive between runs. - P2 — authenticated fallback (best-effort). Used for saturation/backlog and if P1 is unavailable. This path is served through an operator account, creates run-local sessions to avoid exposing derived credentials in caller storage, and is subject to Bluesky's service and rate-limit policies. There is no capacity guarantee above the P1 ceiling.
- P3 — degraded replay mode. If both search paths are unavailable, SKYLARK falls back to Jetstream with an up-to-five-minute replay cursor (keyword/hashtag only). Gaps longer than five minutes are not backfilled. In this degraded path, the DID is used as the author handle fallback and a CID may be unavailable.
If a run is capped (capped: true), droppedCount reports how many new posts exceeded maxPostsPerRun — raise the ceiling or tighten the schedule to catch them.
How it compares
| SKYLARK | Enterprise scraper (stateless) | Other "monitor" clones | |
|---|---|---|---|
| Charges only for new posts | ✅ | ❌ (re-charges duplicates) | ✅ |
| No app password for keyword/hashtag/mention | ✅ | ✅ | ❌ (require one) |
| State survives query edits | ✅ (Task-keyed) | – | ❌ (keyed per query) |
| Keywords + handles + hashtags in one task | ✅ | partial | ❌ (single query string) |
excludeTerms + language filter | ✅ | partial | ❌ |
| 3-path failover | ✅ | ❌ | ❌ |
| Webhook on new + MCP-ready | ✅ | ❌ | partial |
| Best per-post price on hot all-new terms | ❌ (~$3/1k) | ✅ (~$1.49/1k) | ~$1/1k |
We don't fight enterprise scrapers on one-shot bulk scraping — we own the recurring alert loop.
FAQ
- Do I need a Bluesky account or app password? No, not for keyword, hashtag, or mention monitoring.
- What happens on the first run? It looks back 24 hours and delivers matches, then tracks forward from there.
- What if more than 100 posts match in one poll? P1 delivers the newest 100; the run flags
SATURATED_P1and auto-pages via the authenticated path. Use a more frequent schedule for very active terms. - Is this legal? It reads only public Bluesky posts via the public AT Protocol API and stores no private data. Respect Bluesky's Terms and applicable law for your use case.
- Why is there a per-run start fee? It's cost-recovery on runs with zero new posts (an hourly schedule idles at ~$1.44/month) and it prevents empty-schedule spam.
- Found a bug / want a feature? Open an issue on the Actor's Issues tab.