Bluesky Posts, Profiles, Feeds & Threads Scraper avatar

Bluesky Posts, Profiles, Feeds & Threads Scraper

Pricing

from $0.49 / 1,000 results

Go to Apify Store
Bluesky Posts, Profiles, Feeds & Threads Scraper

Bluesky Posts, Profiles, Feeds & Threads Scraper

Search Bluesky posts by keyword, hashtag, author, mention, domain or URL; read profiles, threads, lists, starter packs, feeds and followers; export likes, reposts, follows, quotes and relationships.

Pricing

from $0.49 / 1,000 results

Rating

0.0

(0)

Developer

Nimbryxo-studio

Nimbryxo-studio

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 hours ago

Last modified

Security

Limited permissions

Share

Scrape Bluesky public data without a login, cookies or an API key. Search posts by keyword, hashtag, author, mention, domain or URL; read profiles, author feeds, full thread reply branches, lists, starter packs, custom feeds, likes, reposts, quotes, actor liked posts and public relationships; and discover trending topics and suggested communities. Every record has flat top-level fields with a few natural nested objects, absolute URLs, ISO dates and omit-empty output.

What this actor does

  • 24 modes across posts, accounts, threads, lists, starter packs, feed generators, relationships and discovery.
  • Post search with the full public filter surface: keyword, hashtag, author, mention, domain, URL, date range, language and top/latest ranking.
  • Search beyond the first page: both searchSort=latest and searchSort=top walk backwards through time windows. Latest is newest-first; Top preserves engagement ranking within each window. Cursor paging is not used because Bluesky rejects anonymous cursors.
  • Full thread reply trees: threadDepth walks deeper than the ~10-level per-request limit by fetching truncated reply branches separately. maxRepliesPerPost bounds fan-out and threadTruncated marks records whose children were cut short.
  • Actor likes without credentials: mode=actorLikes reads the account's public like records from its personal data server and hydrates the liked posts, with likedAt and like-record fields.
  • More public surfaces: mode=actorFeeds lists an account's feed generators, mode=starterPackSearch searches starter packs, and mode=relationships checks public follow/block relationships for supplied accounts.
  • Rich records: engagement counts, languages, mentions, hashtags, links, domains, images, video, external embeds, quoted posts, reposts, reply roots, labels, self-labels, verification, live status, pinned posts, profile counts and flat author follower counts.
  • Privacy-aware: accounts marked !no-unauthenticated are skipped by default, and the run status reports how many records were skipped.
  • Batch-friendly: multiple profiles, posts, lists, starter packs, feeds and URLs per run, with automatic de-duplication.
  • No credentials required. Every mode reads public data. If Bluesky temporarily blocks a search request from the actor's network, the actor retries it automatically and reports a clear status if it still fails.

Output per record

Every record carries recordType, sourceUrl and scrapedAt. Empty values are omitted at every depth, so the dataset never contains nulls or empty placeholders.

Post records (recordType=post)

  • uri - canonical AT URI
  • cid - content identifier
  • id - same as uri
  • url - public bsky.app post URL
  • sourceUrl - same as url
  • text - post text
  • createdAt, indexedAt - ISO 8601 timestamps
  • language - first declared language
  • languages[] - all declared languages
  • replyCount, repostCount, likeCount, quoteCount, bookmarkCount
  • isReply - true when the post replies to another post
  • inReplyToUri, inReplyToCid - parent post
  • rootUri, rootCid - thread root
  • isRepost - true when surfaced as a repost
  • repostedBy - handle that reposted it
  • repostUri, repostCid, repostedAt - repost metadata
  • isQuote - true when the post quotes another post
  • threadTruncated - true on a thread record whose direct replies were cut by maxRepliesPerPost, maxItems or a public-API gap (mode=postThread)
  • likedAt, likedBy, likedByDid, likeUri, likeCid - like-record metadata added by mode=actorLikes
  • quotedPost - {uri, cid, text, createdAt, indexedAt, authorHandle, authorDid, authorDisplayName, authorAvatar, url, likeCount, repostCount, replyCount, quoteCount, labels, labelValues, mediaAttachments}
  • mentions[] - mentioned DIDs
  • tags[] - hashtags, lowercase
  • urls[] - external links
  • domains[] - hostnames from urls[]
  • mediaAttachments[] - {type, url, previewUrl, description, width, height, presentation, title} for images, video and external embeds
  • hasMedia, mediaTypes[]
  • labels[] - {val, src, uri, cid, cts, ver}
  • labelValues[] - label values only
  • selfLabels[] - author-applied labels
  • author - {did, handle, displayName, avatar, createdAt, profileUrl, labels, labelValues, verification, status}; with hydrateAuthors=true (the default) it also includes description, banner, followersCount, followsCount, postsCount, indexedAt, pinnedPostUri, pinnedPostCid. The hydrated profile's handle and did replace stale values, and url, sourceUrl and authorHandle are recomputed
  • authorFollowersCount, authorFollowsCount, authorPostsCount, authorVerified - flat author stats added when hydrateAuthors=true
  • authorHandle - convenience field
  • hitsTotal, searchHitsTotal - search-result totals when Bluesky returns them (the value is capped/rounded by the source, so treat it as an estimate)

Account records (recordType=account, like, listMember, repost or starterPackMember)

  • did, id, handle, displayName, description, pronouns
  • avatar, banner
  • followersCount, followsCount, postsCount
  • createdAt, indexedAt
  • url, sourceUrl - public profile URL
  • labels[], labelValues[]
  • verification - {verifiedStatus, trustedVerifierStatus, verifications[]}
  • associated - {listsCount, feedGeneratorsCount, starterPacksCount, isLabeler, chatAllowIncoming, chatAllowGroupInvites, activitySubscription}
  • status - {type, createdAt, durationMinutes, expiresAt, isActive, embed}
  • pinnedPostUri, pinnedPostCid
  • relation - profile, searchMatch, follower, following, liked, reposted, listMember, starterPackMember, suggestedFollow or relationship
  • likedAt, likedPostUri - for mode=getLikes
  • repostedPostUri - for mode=repostedBy
  • listUri, listName - for list members
  • starterPackUri - for starter-pack members
  • relationshipActor, isFollowing, isFollowedBy, isMutualFollow - for mode=relationships
  • following, followedBy, blocking, blockedBy - public relationship record URIs when present

List records (recordType=list)

  • uri, cid, id, name, purpose, description
  • listItemCount
  • creator - account summary
  • creatorHandle, creatorDid
  • labels[], labelValues[], indexedAt
  • url, sourceUrl - public list URL

Starter-pack records (recordType=starterPack)

  • uri, cid, id, name, description
  • creator - account summary
  • creatorHandle, creatorDid
  • listUri, listName, listItemCount
  • joinedAllTimeCount, joinedWeekCount
  • createdAt, updatedAt
  • feeds[] - {uri, displayName, description, avatar, creatorHandle}
  • listItemsSample[] - sample account summaries
  • labels[], labelValues[], indexedAt
  • url, sourceUrl - public starter-pack URL

Feed-generator records (recordType=feedGenerator)

  • uri, cid, id, did
  • displayName, description, avatar
  • likeCount, acceptsInteractions
  • creator - account summary
  • creatorHandle, creatorDid
  • labels[], labelValues[], indexedAt
  • isOnline, isValid - when fetched with mode=feedGenerator
  • url, sourceUrl - public feed URL

Discovery records

  • recordType=trendingTopic: topic, displayName, description, link, url, sourceUrl, rank
  • recordType=taggedSuggestion: tag, subjectType, subject, url, sourceUrl

When a discovery item has no public target URL, url and sourceUrl fall back to the Bluesky home page so every record still has a source link.

Input

FieldTypeDefaultDescription
modeEnumsearchsearch / profile / profiles / actorSearch / feed / postThread / urlFetch / getPosts / follows / followers / getLikes / repostedBy / quotes / actorLikes / getList / listFeed / lists / actorFeeds / getStarterPack / starterPackSearch / feedGenerator / feedGeneratorsDiscovery / relationships / discovery
searchQueryStringblueskyKeyword, hashtag, phrase or Lucene-style query. Used by search, actorSearch, starterPackSearch and feedGeneratorsDiscovery
searchSortEnumlatestlatest (newest first; supports deeper collection) or top (engagement-ranked, capped at about 100 posts)
searchTagsArray[]Hashtags without #; multiple tags are AND-matched (mode=search)
searchDomainString–Only posts linking to this domain (mode=search)
searchUrlString–Only posts linking to this exact URL (mode=search)
mentionsUserString–Only posts mentioning this handle or DID (mode=search)
fromUserString–Only posts authored by this handle or DID (mode=search)
sinceString–Earliest post date (YYYY-MM-DD or ISO datetime); a bare date starts at 00:00 UTC (mode=search)
untilString–Latest post date (YYYY-MM-DD or ISO datetime); a bare date includes the whole day through 23:59:59.999999 UTC (mode=search)
languageEnum–ISO 639-1 language filter; empty means no filter
authorFeedFilterEnumposts_with_repliesposts_with_replies / posts_no_replies / posts_with_media / posts_and_author_threads (mode=profile)
includePinsBooleanfalseInclude the pinned post at the top of the author feed (mode=profile)
includeParentsBooleanfalseInclude ancestor posts above the requested post (mode=postThread)
threadDepthInteger6Reply and ancestor levels to walk, 0-1000. Depths beyond about 10 reply levels are reached by walking branches across requests (mode=postThread)
maxRepliesPerPostInteger100Maximum direct replies followed under each post while walking a thread, 1-1000 (mode=postThread)
actorString–Handle or DID. Used by profile, follows, followers, lists, actorLikes, actorFeeds, relationships and discoveryType=suggestedFollows
actorsArray[]Handles, DIDs or profile URLs for mode=profiles; the accounts to check against actor for mode=relationships
postUriString–AT URI of a post. Used by postThread, getLikes, repostedBy and quotes
postUrisArray[]AT URIs to hydrate (mode=getPosts; fallback for single-post modes)
postUrlsArray[]bsky.app post URLs for getPosts; post, profile, list, feed or starter-pack URLs for urlFetch; fallback for single-post modes
listUriString–AT URI of a list (mode=getList, mode=listFeed)
listUrisArray[]AT URIs or list URLs for batch list processing (mode=getList)
starterPackUriString–AT URI of a starter pack (mode=getStarterPack)
starterPackUrisArray[]AT URIs or starter-pack URLs for batch processing (mode=getStarterPack)
feedPresetEnum-whats-hot / bsky-team / hot-classic; an explicit feedUri always wins. Legacy names (discover, mutuals, popular-with-friends, for-you, news, trending-videos, quiet-posters) are accepted and mapped to What's Hot. If neither is set, mode=feed uses What's Hot
feedUriString–AT URI or bsky.app feed URL (mode=feed, mode=feedGenerator)
feedUrisArray[]AT URIs or feed URLs for batch lookup (mode=feedGenerator)
discoveryTypeEnumtrendingTopicstrendingTopics / suggestedFeeds / suggestedStarterPacks / taggedSuggestions / suggestedFollows (mode=discovery)
excludeRepliesBooleanfalseDrop posts that are replies
excludeRepostsBooleanfalseDrop reposts
mediaOnlyBooleanfalseOnly posts with at least one image, video or external embed
excludeLabeledBooleanfalseDrop posts and accounts that carry moderation or self-labels, including labels on a post's author
respectNoUnauthenticatedBooleantrueSkip records whose author carries !no-unauthenticated; the run status reports the skipped count
verifiedOnlyBooleanfalseOnly verified accounts, or posts whose author is verified. Records with no verification object are excluded; post modes hydrate author profiles to check
minLikesInteger–Drop posts below this like count, 0-10,000,000
minRepostsInteger–Drop posts below this repost count, 0-10,000,000
minRepliesInteger–Drop posts below this reply count, 0-10,000,000
minQuotesInteger–Drop posts below this quote count, 0-10,000,000
minFollowersInteger–Keep accounts with at least this many followers, 0-1,000,000,000
maxFollowersInteger–Keep accounts with at most this many followers, 0-1,000,000,000
includeListMetadataBooleanfalseEmit a list record before its members (mode=getList)
includeStarterPackMembersBooleantrueEmit the pack's member accounts (mode=getStarterPack)
hydrateAuthorsBooleantrueFetch full author profiles for post records in batches of 25 and add flat author follower, following, post and verification fields. Automatically enabled when verifiedOnly=true; the daily profile prefill leaves it off to stay cheap
maxItemsInteger40Hard cap on emitted records, 1-5000. Source exhaustion or Bluesky caps may return fewer; the run status reports a shortfall

Legacy saved tasks that specify mode=getActorLikes are mapped to actorLikes with a status message. That mode reads the account's public like records from its personal data server and hydrates the liked posts; no login or app password is used.

Example: brand monitoring with filters

{
"mode": "search",
"searchQuery": "bluesky",
"searchSort": "latest",
"searchTags": ["opensource"],
"language": "en",
"minLikes": 10,
"maxItems": 300
}

Example: a user's profile and recent media posts

{
"mode": "profile",
"actor": "bsky.app",
"authorFeedFilter": "posts_with_media",
"includePins": true,
"maxItems": 50
}

Example: a thread with parents and replies

{
"mode": "postThread",
"postUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3l6oveex3ii2l",
"includeParents": true,
"threadDepth": 30,
"maxRepliesPerPost": 100,
"maxItems": 200
}

Example: posts an account liked

{
"mode": "actorLikes",
"actor": "bsky.app",
"maxItems": 100
}

Example: audience export with follower counts

{
"mode": "followers",
"actor": "jay.bsky.team",
"minFollowers": 100,
"maxItems": 500
}
{
"mode": "discovery",
"discoveryType": "trendingTopics",
"maxItems": 20
}

Use cases

  • Social listening and brand monitoring - track keywords, hashtags, mentions, domains and authors with date and engagement filters.
  • Influencer and KOL research - combine account search with follower ranges, verification and profile counts.
  • Audience and lead export - export followers, follows, likers, reposters, list members and starter-pack members with handles, bios and counts.
  • Conversation analysis - capture a post, its ancestors and replies up to threadDepth for sentiment or narrative research.
  • Content and LLM datasets - collect post text, languages, hashtags, links, media metadata and engagement counts.
  • Community mapping - explore lists, list feeds, starter packs, custom feeds and trending topics.

FAQ

Do I need a Bluesky account or login? No. Every mode reads public data. No cookies or API keys are needed. If Bluesky temporarily blocks a search request from the actor's network, the actor retries it automatically through an Apify connection and reports a clear status if it still fails. No proxy setup is required.

How far back can a keyword search go? searchSort=latest walks backwards through time windows and can return far more than the 100-post relevance cap. searchSort=top is relevance-ranked and limited to about 100 posts per query. Time-window search is approximate: pages can overlap, so results are de-duplicated by post URI, and a narrow or wide date range changes how predictable the volume is. When Bluesky returns a search hit total it is exposed as hitsTotal/searchHitsTotal, but the source caps and rounds that number.

Why do some posts have no text? Bluesky allows media-only posts. The actor omits empty text and keeps the media metadata.

Why are some fields missing from an account? Basic account views do not always include a bio, banner, follower counts or a pinned post. The actor hydrates accounts in batches so those fields are present whenever Bluesky publishes them. Labels, verification and live status are conditional by nature.

Why are some accounts missing from results? Some accounts opt out of unauthenticated access and carry the !no-unauthenticated label. They are skipped by default and counted in the run status. Set respectNoUnauthenticated=false to include them when Bluesky returns them.

Why does a follower export contain fewer rows than the profile's follower count? Profile counts are cached totals; deactivated or unindexed accounts can make them larger than the returned list. !no-unauthenticated accounts are filtered by this actor by default. The export is complete for what the public API exposes after that policy.

How are reposts and quote posts handled? A repost is one record with isRepost=true, repostedBy and the original post's content. A quote post is one record with the quoter's text and a nested quotedPost object containing the quoted post's text, author, URL, counts and media.

What is the difference between mode=search and mode=actorSearch? search finds posts. actorSearch finds accounts by handle, display name or bio.

What is a feed, and which presets are available? A feed is a curated post stream produced by a feed generator. The built-in presets are What's Hot, Bluesky Team and Hot Classic. Paste any other generator's AT URI or bsky.app feed URL into feedUri. An explicit feedUri always takes precedence over feedPreset; legacy preset names are mapped to What's Hot.

Does feedPreset override my custom feedUri? No. feedUri/feedUris win whenever they are supplied. feedPreset is only used when no feed URI is given, and mode=feedGenerator never adds an unrequested feed.

How does verifiedOnly work? It keeps only accounts with a valid Bluesky verification and posts whose author is verified. Records with no verification object are excluded. Post modes hydrate author profiles so verification can be checked, which adds batched profile requests and may return fewer posts than an unfiltered search.

How do actor likes work without a login? mode=actorLikes resolves the account's personal data server from its public DID document, lists the public app.bsky.feed.like records stored there, and hydrates each liked post. No credentials are used. Likes whose posts were deleted, or accounts whose DID document does not expose a public data server, return no rows for that part. mode=getLikes is the opposite direction: it lists the accounts that liked a given post.

How deep can a thread go? threadDepth can be set up to 1000. The public thread endpoint returns about 10 reply levels per request, so the actor detects reply branches that still have children and fetches those branches separately. maxRepliesPerPost caps how many direct replies are followed under each post; when a branch is cut, the affected post carries threadTruncated=true and the run status explains why.

What is mode=relationships? It checks public follow and block relationships between actor and each account in actors (up to batches of 30). Each account record gets isFollowing, isFollowedBy, isMutualFollow and the public relationship record URIs. It is not a replacement for a logged-in viewer's personalised "known followers" list, which needs an account context.

Why did I get fewer records than maxItems? Filters can exclude many candidates, Bluesky can exhaust the source, and some search modes have source caps. The run status message reports the shortfall; it does not silently pretend the result is complete.

Can I export followers of a very large account? Yes, up to maxItems. Bluesky returns followers in cursor-paged batches; the actor keeps walking short pages until the cap or the end of the list.

How current is the data? Live. Every run reads Bluesky at request time, so schedule the actor hourly or daily for ongoing refreshes.

Is this affiliated with Bluesky? No. This is an independent actor that reads public Bluesky data.

Limitations

  • Top search uses time windows. searchSort=top is engagement-ranked; the actor walks older time windows to collect more than one page, preserving ranking within each window. Results are deduplicated by post URI.
  • Time-window search is approximate. The latest walk can return posts outside the exact window, can overlap between windows, and is de-duplicated by post URI. The until boundary uses the newer of a post's createdAt and indexedAt, and a date-only until includes the whole UTC day.
  • Search hit totals are estimates. When Bluesky returns hitsTotal/searchHitsTotal, the source caps and rounds the number; it is not an exact result count.
  • Search can be temporarily blocked. If Bluesky returns HTTP 403 even after the automatic Apify retry, the run stops with a clear status message. Try again later or use mode=profile, mode=feed or a direct post/list feed.
  • Search coverage is not exhaustive. Bluesky's search index is recency-weighted and does not include every post.
  • Thread walking is bounded on purpose. Each request returns about 10 reply levels, so deeper replies are fetched branch by branch. The walk stops at threadDepth, maxRepliesPerPost, maxItems or the per-run branch budget; affected records carry threadTruncated=true. Deleted, blocked, hidden or rate-limited branches still create gaps.
  • Actor likes depend on the public data server. The like records are read from the account's personal data server rather than the public feed service. If that server is unreachable, does not appear in the DID document, or no longer stores the like record, those likes cannot be returned. Deleted posts are skipped even when their like record remains.
  • Personalised known followers need a login. The public relationship check in mode=relationships can tell you whether supplied accounts follow or block a target, but a viewer-specific "followers you know" list requires an authenticated account context, which this actor does not use.
  • Starter-pack typeahead is not a separate mode. mode=starterPackSearch uses the public starter-pack search endpoint, which covers keyword search and paging; a viewer-boosted typeahead ordering is not exposed without an account context.
  • Hidden accounts are skipped by default. Accounts that carry !no-unauthenticated are filtered out unless respectNoUnauthenticated=false, and the status message reports how many records were skipped.
  • Follower counts can exceed exported rows. Profile totals are cached by Bluesky and include accounts that are deactivated or no longer indexed. !no-unauthenticated accounts are returned by the API and then filtered by this actor by default, so followersCount can exceed the exported rows. Set respectNoUnauthenticated=false to include them.
  • Private data is out of scope. Direct messages, private accounts, notifications and muted/blocked relationships are not available.
  • Some fields are conditional. Labels, verification, live status, pinned posts, banners and media are present only when the source has them.
  • Custom feeds depend on third-party generators. If a generator is offline, its feed returns no posts.
  • Follower lists can be very large. Use maxItems to bound a run.
  • maxItems is capped at 5,000 per run. Larger requests are clamped by the input schema.
  • Filtered account modes keep walking cursor pages until the cap or source exhaustion. If Bluesky has no more matches, the run reports a shortfall in its status message.
  • verifiedOnly can return far fewer records. Most post authors do not publish a verification object, so verified-only post searches are intentionally narrow.
  • mode=feedGenerator returns only the feeds you request. It does not append a default What's Hot record.