Bluesky Posts Search Scraper
Pricing
$0.90 / 1,000 post returneds
Bluesky Posts Search Scraper
Search public Bluesky posts by keyword, author, or post URL, or find profiles by text. Save structured post and profile records with public links, dates, media, and engagement counts.
Pricing
$0.90 / 1,000 post returneds
Rating
0.0
(0)
Developer
Maxime Dupré
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
🔎 Find public Bluesky posts and profiles
Bluesky Posts Search Scraper is for researchers, marketers, developers, and anyone who needs public Bluesky data. It returns structured post and profile records with text, public links, author details, dates, media metadata, counts, and optional sentiment and topic annotations. This helps you review public conversations in a dataset.
- Collect public post and profile records with Bluesky Data Scraper for research.
- Find public profiles by text with Bluesky Profile Search.
- Find public posts by keyword phrase with Bluesky Post Search.
- Collect an author's public post feed with Bluesky Scraper.
- Open a public post and collect its replies with Blue Sky Search.
📦 Get structured Bluesky post and profile rows
Each run writes public rows to the default dataset. A row is either a post or a profile. Fields that the public source does not provide may be absent. When several keyword phrases find the same post, the Actor saves the first eligible match once and ignores later matches. The keyword field records the phrase that first found that saved post.
Post rows can include text, stable public links, author identity, publication time, engagement counts, languages, images, link previews, video metadata, reply context, and lightweight sentiment and topic annotations. Profile rows can include a handle, public URL, DID, bio, avatar, and activity counts.
▶️ Choose one Bluesky search path
How to run
- Choose
PostsorProfilesas the result type. - For
Posts, chooseKeywords,Author feed, orPost URL. ForProfiles, enter a profile search query. - Set the fields for the path you chose. Other fields are ignored. Keyword searches use one shared set of filters for every phrase in the run.
- Set
maxItemsto cap the number of saved records. If you leave it empty, the Actor returns all available matching records until the public source is exhausted. - Start the run and open the dataset link in the output.
Only public Bluesky content that the source makes available can be returned. Different criteria need separate runs because one shared set of filters applies to all keyword phrases.
⚙️ Input
Input fields
| Field | Type | What it does |
|---|---|---|
resultType | string | Required. Chooses posts for public post rows or profiles for public profile rows. |
postDiscoveryMethod | string | For posts, chooses keywords, authorFeed, or postUrl. Only fields for the chosen path are used. |
keywords | array of strings | Searches public Bluesky posts for one or more phrases. The same filters apply to every phrase. |
startDate | date string | Optional UTC start date. Keeps posts published on or after this YYYY-MM-DD date. |
endDate | date string | Optional UTC end date. Keeps posts published on or before this YYYY-MM-DD date. |
languages | array of strings | Optional language codes for keyword searches, such as en or es. A post must match one listed language. |
authorFilter | string | Optional public Bluesky handle or DID for keyword searches. Keeps posts from that author only. |
mentionFilter | string | Optional public Bluesky handle or DID for keyword searches. Keeps posts that mention that account. |
hashtags | array of strings | Optional hashtag text for keyword searches, with or without #. Keeps posts that use at least one listed hashtag. |
domains | array of strings | Optional domains for keyword searches, such as example.com. Keeps posts that link to at least one listed domain. |
exactUrl | string | Optional full URL for keyword searches. Keeps posts that share this exact URL. |
minLikes | integer | Optional minimum like count for keyword searches. |
minReposts | integer | Optional minimum repost count for keyword searches. |
minReplies | integer | Optional minimum reply count for keyword searches. |
includeReplies | boolean | For keyword searches, includes matching reply posts when true. When false, it keeps matching original posts only. |
sortBy | string | For keyword searches, chooses latest for newer posts first or top for more popular posts first. |
authorHandle | string | A public Bluesky handle or DID for the authorFeed path. |
postUrl | URL string | A public Bluesky post URL for the postUrl path. |
expandReplies | boolean | For the postUrl path, also collects replies to the selected post when true. |
profileQuery | string | Text used to find public Bluesky profiles when resultType is profiles. |
maxItems | integer | Optional work limit. Stops after this many records. If you leave it empty, the Actor returns all available matching records until the public source is exhausted. |
Example input
This example is copied from the public input of a successful current-beta default-input run:
{"resultType": "posts","postDiscoveryMethod": "keywords","keywords": ["climate"],"includeReplies": false,"sortBy": "latest","expandReplies": false,"maxItems": 20}
🧾 Output
Dataset link
The dataset output is a string link to the default dataset overview. Every saved item uses one of the two row shapes below. Fields not marked as required may be absent when the public source does not provide them.
Post rows
| Field | Type | What it does |
|---|---|---|
recordType | required string | Always post for this shape. |
text | required string | The text written in the public Bluesky post. |
postUrl | required URL string | A direct public link to the post. |
postUri | string | The stable Bluesky URI for the post. |
publishedAt | required date-time string | The date and time when the post was published. |
keyword | string | The keyword phrase that first found the post in a keyword search. |
author | object | Public identity details for the post author. |
author.did | string | The author's stable decentralized identifier. |
author.handle | string | The author's public Bluesky handle. |
author.displayName | string | The author's public display name, when available. |
author.avatarUrl | URL string | A direct link to the author's public avatar, when available. |
likeCount | integer | The number of likes on the post, when available. |
repostCount | integer | The number of reposts of the post, when available. |
replyCount | integer | The number of replies to the post, when available. |
quoteCount | integer | The number of quote posts for the post, when available. |
images | array of objects | Images attached to the post, when available. The array can be empty. |
images[].url | URL string | A direct link to an attached image. |
images[].altText | string | Text that describes an attached image, when available. |
links | array of objects | Web links attached to or shown in the post, when available. The array can be empty. |
links[].url | URL string | The web address shared in the post. |
links[].title | string | The title shown for the linked page, when available. |
links[].description | string | The description shown for the linked page, when available. |
links[].imageUrl | URL string | A direct link to the preview image for the linked page, when available. |
video | object | Metadata for a video attached to the post, when available. |
video.playlistUrl | URL string | The direct playlist link for the video, when available. |
video.thumbnailUrl | URL string | A direct link to the video thumbnail, when available. |
video.altText | string | Text that describes the video, when available. |
video.width | integer | The video width in pixels, when available. |
video.height | integer | The video height in pixels, when available. |
languages | array of strings | Language codes found on the post, when available. The array can be empty. |
replyContext | object | Links a collected reply to the post selected for reply collection, when available. |
replyContext.sourcePostUri | string | The stable URI of the selected source post. |
replyContext.sourcePostUrl | URL string | A direct public link to the selected source post. |
sentiment | object | A lightweight sentiment result for the post or reply, when available. |
sentiment.label | string | The sentiment label: positive, neutral, or negative. |
sentiment.score | number | The sentiment score, from -1 for most negative to 1 for most positive. |
topics | array of strings | Content categories assigned to the post, when available. |
Example post row
This unshortened row comes from a successful current-beta post URL run:
{"recordType": "post","text": "Our final updates have been posted to the Climate.gov website, and this will be our final post to our social media channels.","postUrl": "https://bsky.app/profile/climate.noaa.gov/post/3lsmjv6ncvc2e","postUri": "at://did:plc:ybhjcsleqxtr2oyxiq7jijr7/app.bsky.feed.post/3lsmjv6ncvc2e","publishedAt": "2025-06-27T21:00:03.630Z","author": {"did": "did:plc:ybhjcsleqxtr2oyxiq7jijr7","handle": "climate.noaa.gov","displayName": "NOAA Climate.gov","avatarUrl": "https://cdn.bsky.app/img/avatar/plain/did:plc:ybhjcsleqxtr2oyxiq7jijr7/bafkreigqphneccrf63pygu2ug5tjxws65loq5dwoc6gffc3fsk2e3tb5l4"},"likeCount": 963,"repostCount": 413,"replyCount": 115,"quoteCount": 161,"images": [{"url": "https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:ybhjcsleqxtr2oyxiq7jijr7/bafkreid44tl6gdwtb3sh4j7kypi5feyo3fqk7dhbk4euffq4rmpfzvha54"}],"links": [{"url": "https://climate.gov/"}],"languages": ["en"],"sentiment": {"label": "neutral","score": 0}}
Profile rows
| Field | Type | What it does |
|---|---|---|
recordType | required string | Always profile for this shape. |
did | string | The profile's stable decentralized identifier, when available. |
handle | required string | The profile's public Bluesky handle. |
displayName | string | The profile's public display name, when available. |
description | string | The public profile bio, when available. |
avatarUrl | URL string | A direct link to the profile avatar, when available. |
profileUrl | required URL string | A direct public link to the profile. |
followersCount | integer | The number of public followers, when available. |
followingCount | integer | The number of public accounts this profile follows, when available. |
postsCount | integer | The number of public posts from this profile, when available. |
Example profile row
This unshortened row comes from a successful current-beta profile search run:
{"recordType": "profile","handle": "metoffice.gov.uk","profileUrl": "https://bsky.app/profile/metoffice.gov.uk","did": "did:plc:pzn3wkuiqw224zyfwvdhpn6j","displayName": "Met Office - weather and climate","description": "Official UK Met Office account. Get the weather in your hand with our app: http://linktr.ee/MOContent","avatarUrl": "https://cdn.bsky.app/img/avatar/plain/did:plc:pzn3wkuiqw224zyfwvdhpn6j/bafkreicdxw5q2mxirjgtgze7y6pfplghg55drhstxum6w236x45moryeyy","followersCount": 42365,"followingCount": 35,"postsCount": 2876}
💳 Pricing
How charges work
This Actor uses pay per event pricing. For keyword searches, the Post returned event is charged for each public post found by a keyword phrase and saved to the dataset. The current event price appears in the pricing tab. If no post is saved, no Post returned event occurs. For keyword searches, maxItems can cap saved rows and the matching post charges.
🔌 Integrations
Use the data
Open the dataset link in Apify Console or read its items through the Apify API. Download the rows as JSON, CSV, Excel, XML, RSS, or HTML.
❓ FAQ
Can I search posts and profiles in one run?
No. Choose Posts or Profiles for a run. Start another run for the other type.
Can I use different filters for each keyword?
No. One shared set of post-search filters applies to every phrase in the run. Use separate runs for different filter sets.
What happens when several keywords find the same post?
The Actor saves the first eligible match once and ignores later matches. The keyword field shows the phrase that found the saved row first.
Can I collect an author's feed?
Yes. Choose Posts, choose Author feed, and enter a public handle or DID. The feed returns post rows.
Can I collect replies to a known post?
Yes. Choose Posts, choose Post URL, turn on Collect replies, and set maxItems. The public source may not expose every reply.
What if I leave Maximum results empty?
The Actor returns all available matching records until the public source is exhausted. The source can still limit what it indexes or returns.
Why is a field missing?
Some fields are optional. They appear only when the public source provides them.
Does it access private or deleted content?
No. It reads public content that the source makes available. Private, deleted, blocked, or inaccessible content is not returned.
Are the sentiment and topic fields expert analysis?
No. They are lightweight annotations when available, not expert or machine-learning-grounded interpretation.
📝 Changelog
v0.0 (01-09-2026)
- Initial release.
🆘 Support
For issues, questions, or feature requests, file a ticket and I'll fix or implement it in less than 24h 🫡
🔗 Related Actors
- Twitter (X) Scraper collects public X posts, profiles, network members, and regional trends.
- Reddit Comments Search Scraper searches public Reddit comments for topic or brand mentions.
- Threads Replies Scraper collects public replies and conversation context from Threads posts or profiles.
- Facebook User Posts Scraper collects public posts from Facebook profiles, Pages, or known post URLs.
- Bluesky Starter Pack Scraper finds public Starter Packs by topic, creator, link, or AT Protocol identifier.
Made with ❤️ by Maxime Dupré