Bluesky Posts Search Scraper avatar

Bluesky Posts Search Scraper

Pricing

$0.90 / 1,000 post returneds

Go to Apify Store
Bluesky Posts Search Scraper

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é

Maxime Dupré

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

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.

📦 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

  1. Choose Posts or Profiles as the result type.
  2. For Posts, choose Keywords, Author feed, or Post URL. For Profiles, enter a profile search query.
  3. 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.
  4. Set maxItems to cap the number of saved records. If you leave it empty, the Actor returns all available matching records until the public source is exhausted.
  5. 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

FieldTypeWhat it does
resultTypestringRequired. Chooses posts for public post rows or profiles for public profile rows.
postDiscoveryMethodstringFor posts, chooses keywords, authorFeed, or postUrl. Only fields for the chosen path are used.
keywordsarray of stringsSearches public Bluesky posts for one or more phrases. The same filters apply to every phrase.
startDatedate stringOptional UTC start date. Keeps posts published on or after this YYYY-MM-DD date.
endDatedate stringOptional UTC end date. Keeps posts published on or before this YYYY-MM-DD date.
languagesarray of stringsOptional language codes for keyword searches, such as en or es. A post must match one listed language.
authorFilterstringOptional public Bluesky handle or DID for keyword searches. Keeps posts from that author only.
mentionFilterstringOptional public Bluesky handle or DID for keyword searches. Keeps posts that mention that account.
hashtagsarray of stringsOptional hashtag text for keyword searches, with or without #. Keeps posts that use at least one listed hashtag.
domainsarray of stringsOptional domains for keyword searches, such as example.com. Keeps posts that link to at least one listed domain.
exactUrlstringOptional full URL for keyword searches. Keeps posts that share this exact URL.
minLikesintegerOptional minimum like count for keyword searches.
minRepostsintegerOptional minimum repost count for keyword searches.
minRepliesintegerOptional minimum reply count for keyword searches.
includeRepliesbooleanFor keyword searches, includes matching reply posts when true. When false, it keeps matching original posts only.
sortBystringFor keyword searches, chooses latest for newer posts first or top for more popular posts first.
authorHandlestringA public Bluesky handle or DID for the authorFeed path.
postUrlURL stringA public Bluesky post URL for the postUrl path.
expandRepliesbooleanFor the postUrl path, also collects replies to the selected post when true.
profileQuerystringText used to find public Bluesky profiles when resultType is profiles.
maxItemsintegerOptional 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

FieldTypeWhat it does
recordTyperequired stringAlways post for this shape.
textrequired stringThe text written in the public Bluesky post.
postUrlrequired URL stringA direct public link to the post.
postUristringThe stable Bluesky URI for the post.
publishedAtrequired date-time stringThe date and time when the post was published.
keywordstringThe keyword phrase that first found the post in a keyword search.
authorobjectPublic identity details for the post author.
author.didstringThe author's stable decentralized identifier.
author.handlestringThe author's public Bluesky handle.
author.displayNamestringThe author's public display name, when available.
author.avatarUrlURL stringA direct link to the author's public avatar, when available.
likeCountintegerThe number of likes on the post, when available.
repostCountintegerThe number of reposts of the post, when available.
replyCountintegerThe number of replies to the post, when available.
quoteCountintegerThe number of quote posts for the post, when available.
imagesarray of objectsImages attached to the post, when available. The array can be empty.
images[].urlURL stringA direct link to an attached image.
images[].altTextstringText that describes an attached image, when available.
linksarray of objectsWeb links attached to or shown in the post, when available. The array can be empty.
links[].urlURL stringThe web address shared in the post.
links[].titlestringThe title shown for the linked page, when available.
links[].descriptionstringThe description shown for the linked page, when available.
links[].imageUrlURL stringA direct link to the preview image for the linked page, when available.
videoobjectMetadata for a video attached to the post, when available.
video.playlistUrlURL stringThe direct playlist link for the video, when available.
video.thumbnailUrlURL stringA direct link to the video thumbnail, when available.
video.altTextstringText that describes the video, when available.
video.widthintegerThe video width in pixels, when available.
video.heightintegerThe video height in pixels, when available.
languagesarray of stringsLanguage codes found on the post, when available. The array can be empty.
replyContextobjectLinks a collected reply to the post selected for reply collection, when available.
replyContext.sourcePostUristringThe stable URI of the selected source post.
replyContext.sourcePostUrlURL stringA direct public link to the selected source post.
sentimentobjectA lightweight sentiment result for the post or reply, when available.
sentiment.labelstringThe sentiment label: positive, neutral, or negative.
sentiment.scorenumberThe sentiment score, from -1 for most negative to 1 for most positive.
topicsarray of stringsContent 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

FieldTypeWhat it does
recordTyperequired stringAlways profile for this shape.
didstringThe profile's stable decentralized identifier, when available.
handlerequired stringThe profile's public Bluesky handle.
displayNamestringThe profile's public display name, when available.
descriptionstringThe public profile bio, when available.
avatarUrlURL stringA direct link to the profile avatar, when available.
profileUrlrequired URL stringA direct public link to the profile.
followersCountintegerThe number of public followers, when available.
followingCountintegerThe number of public accounts this profile follows, when available.
postsCountintegerThe 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 🫡

Made with ❤️ by Maxime Dupré