Use Bluesky Posts, Profiles, Feeds & Threads Scraper with Python
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.
1. Choose the data you need
Review the published README for supported collection modes, examples, and limits. The recipe below uses the current published input definition.
2. Prepare a source-based input
This JSON contains published prefills and required-field defaults. Review every value for your task before running it; it is not a promise of successful collection.
{
"actor": "bsky.app",
"actors": [],
"authorFeedFilter": "posts_with_replies",
"discoveryType": "trendingTopics",
"excludeLabeled": false,
"excludeReplies": false,
"excludeReposts": false,
"feedPreset": "whats-hot",
"feedUris": [],
"hydrateAuthors": false,
"includeListMetadata": false,
"includeParents": false,
"includePins": false,
"includeStarterPackMembers": true,
"language": "",
"listUris": [],
"maxItems": 3,
"maxRepliesPerPost": 100,
"mediaOnly": false,
"mode": "profile",
"postUris": [],
"postUrls": [],
"respectNoUnauthenticated": true,
"searchQuery": "bluesky",
"searchSort": "latest",
"searchTags": [],
"starterPackUris": [],
"threadDepth": 6,
"verifiedOnly": false
}
Download input.example.json and save your reviewed copy as input.json.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | required | What to fetch. |
searchQuery | string | optional | Keyword, hashtag, phrase, or Lucene-style query. Used by search, actorSearch, starterPackSearch, and feedGeneratorsDiscovery. |
searchSort | string | optional | Search ranking. `latest` returns newest first; `top` returns engagement-ranked posts. Both use time-window pagination to collect beyond one page. |
searchTags | array | optional | Only posts with these hashtags (without `#`). Multiple tags are AND-matched. (mode=search) |
searchDomain | string | optional | Only posts linking to this domain, e.g. `github.com`. (mode=search) |
searchUrl | string | optional | Only posts linking to this exact URL. (mode=search) |
mentionsUser | string | optional | Only posts mentioning this handle or DID. (mode=search) |
fromUser | string | optional | Only posts authored by this handle or DID. (mode=search) |
since | string | optional | Earliest post date as `YYYY-MM-DD` or an ISO datetime. (mode=search) |
until | string | optional | Latest post date as `YYYY-MM-DD` or an ISO datetime. (mode=search) |
language | string | optional | ISO 639-1 language filter for post search and post records. Empty means no filter. |
authorFeedFilter | string | optional | Which posts to include in the author feed. (mode=profile) |
includePins | boolean | optional | Include the pinned post at the top of the author feed. (mode=profile) |
includeParents | boolean | optional | Include ancestor posts above the requested post. (mode=postThread) |
threadDepth | integer | optional | How many reply levels and ancestor levels to walk. Depths beyond about 10 reply levels are reached by walking reply branches across requests. 0 returns only the requested post. (mode=postThread) |
maxRepliesPerPost | integer | optional | Maximum direct replies followed under each post while walking a thread. Larger values reach more branches but cost more requests. (mode=postThread) |
actor | string | optional | Bluesky handle or DID. Used by profile, follows, followers, lists, actorLikes, actorFeeds, relationships, and discoveryType=suggestedFollows. |
actors | array | optional | Handles, DIDs, or profile URLs for batch lookup. Used by profiles and by relationships as the accounts to check against `actor`. |
postUri | string | optional | AT URI of a post. Used by postThread, getLikes, repostedBy, and quotes. |
postUris | array | optional | AT URIs of posts to hydrate. Used by getPosts and as a fallback for single-post modes. |
postUrls | array | optional | bsky.app post, profile, list, feed, or starter-pack URLs. Used by urlFetch, getPosts, and as a fallback for single-post modes. |
listUri | string | optional | AT URI of a Bluesky list. Used by getList and listFeed. |
listUris | array | optional | AT URIs or bsky.app list URLs for batch list processing. (mode=getList) |
starterPackUri | string | optional | AT URI of a starter pack. (mode=getStarterPack) |
starterPackUris | array | optional | AT URIs or bsky.app starter-pack URLs for batch processing. (mode=getStarterPack) |
feedPreset | string | optional | Built-in feed preset. Live presets are listed first, followed by legacy aliases mapped to What's Hot. An explicit `feedUri` always takes precedence; if neither is set, What's Hot is used for mode=feed. |
feedUri | string | optional | AT URI or bsky.app feed URL of a custom feed generator. (mode=feed / feedGenerator) |
feedUris | array | optional | AT URIs or bsky.app feed URLs for batch feed-generator lookup. (mode=feedGenerator) |
discoveryType | string | optional | Which discovery surface to fetch. (mode=discovery) |
excludeReplies | boolean | optional | Drop posts that are replies to another post. |
excludeReposts | boolean | optional | Drop posts surfaced as reposts. |
mediaOnly | boolean | optional | Only emit posts with at least one image, video, or external embed. |
excludeLabeled | boolean | optional | Drop posts and accounts that carry moderation or self-labels, including labels on a post's author. |
respectNoUnauthenticated | boolean | optional | Skip records whose author carries the `!no-unauthenticated` label. The run status reports how many records were skipped. |
verifiedOnly | boolean | optional | Only emit accounts with a valid Bluesky verification, or posts whose author is verified. Records with no verification object are excluded. Post modes hydrate author profiles so verification can be checked. |
minLikes | integer | optional | Drop posts with fewer likes. |
minReposts | integer | optional | Drop posts with fewer reposts. |
minReplies | integer | optional | Drop posts with fewer replies. |
minQuotes | integer | optional | Drop posts with fewer quote posts. |
minFollowers | integer | optional | Keep accounts with at least this many followers. |
maxFollowers | integer | optional | Keep accounts with at most this many followers. |
includeListMetadata | boolean | optional | Emit a list record before its members. (mode=getList) |
includeStarterPackMembers | boolean | optional | Emit the accounts in the starter pack's list after the pack record. (mode=getStarterPack) |
hydrateAuthors | boolean | optional | Fetch full author profiles for post records. Adds one batched profile request per 25 unique authors and flat author follower, following, post and verification fields. Enabled by default; the daily profile prefill leaves it off to stay cheap. |
maxItems | integer | optional | Hard cap on emitted records. For batch modes the cap applies across the whole run. |
3. Start an Actor run
Set APIFY_TOKEN in your environment. Python 3.10 or newer is sufficient; this recipe uses no third-party packages.
Execution may incur charges. Review current pricing on Apify. The request asks for a 120-second timeout and a charge limit; these settings are subject to Apify’s pricing and do not guarantee an all-inclusive spending cap.
import json
import os
import urllib.request
# Save the schema-derived example as input.json; review and edit it first.
with open("input.json", encoding="utf-8") as stream:
actor_input = json.load(stream)
token = os.environ["APIFY_TOKEN"]
request = urllib.request.Request(
"https://api.apify.com/v2/acts/MFlAz6T5BhkrS9qhc/runs?timeout=120&maxTotalChargeUsd=0.50",
data=json.dumps(actor_input).encode("utf-8"),
headers={"Authorization": "Bearer " + token, "Content-Type": "application/json"},
method="POST",
)
# This starts a potentially billable run. Do not automatically retry this POST.
with urllib.request.urlopen(request, timeout=40) as response:
run = json.load(response)["data"]
print("Run ID:", run["id"])
print("Status:", run["status"])
# Inspect and download results in Apify Console once the run succeeds.
4. Inspect the actual results
Open the run in Apify Console and wait for a successful completion. Use the published output schema to locate results and the dataset schema to understand declared views. Missing or optional record fields must not be treated as guaranteed values.
Bluesky posts, accounts, lists, starter packs, feed generators, trending topics and tag suggestions from the public read API.
Questions before you run
Which inputs are required?
The published required fields are mode
What does this guide verify?
The fields, prefills, and schema links are rendered from the published build. This is a usage recipe, not a paid live extraction test. Source availability and collection results can vary.
What if the run request times out?
Check Apify Console before retrying. The first request may already have created a run. Do not automatically repeat a run-creation POST.
Generated from source build QVca54L51kgdV5Lsb and its README and schemas. Source changes regenerate this guide; no third-party editorial claims are inferred.