Viewing feeds
Feeds are lists of posts, paginated by cursors. Bluesky has a few types of feeds, including
- timelines: the default chronological feed of posts from users the authenticated user follows
- feed generators: custom feeds made by users and organizations
- author feeds: a feed of posts by a single author
Warning
Treat data received from Bluesky, AT Protocol services, and streams such as Jetstream and the firehose as untrusted. This includes post and message text, profile and
list metadata, labels, error details such as AtErrorDetail, and raw JSON. Before displaying it, encode it for the output context (for example, HTML-encode it for a web page). Before using
a URL in a link or other active context, check its scheme against an allow-list of the schemes your application expects, such as https; a
well-formed URL can still use an active scheme such as javascript:, which can lead to cross-site scripting.
Validate other values before using them in active contexts.
The sample code on this page is for illustration. It does not sanitize or otherwise validate the input it uses; apply the validation and encoding appropriate for your application.
Viewing a user's timeline
The Bluesky agent you created in the Get Started section has a dedicated GetTimeline() method that returns the authenticated user's timeline.
It accepts two key parameters: cursor and limit.
GetTimeline(cursor?, limit?)
| Parameter | Type | Description | Required | Default |
|---|---|---|---|---|
| cursor | string | A cursor that tells the server where to paginate from | No | null |
| limit | int | The number of posts to return per page (max 100) | No | 50 |
var timelineResult = await agent.GetTimeline(limit: 10);
You can then iterate through the results, assuming the API call succeeded,
foreach (var feedViewPost in timelineResult.Result!)
{
// Process the feed's view over the post
}
To get the next page of results take the Cursor property from the previous call's results and pass it into GetTimeline().
If the Cursor is null there are no more results to retrieve.
if (timelineResult.Result.Cursor is not null)
{
var nextResults = await agent.GetTimeline(cursor:timelineResult.Result.Cursor, limit: 10);
}
You can put it altogether;
int maximumPagesToRetrieve = 5;
int numberOfEntriesPerPage = 5;
int pageCount = 0;
var timelineResult =
await agent.GetTimeline(limit: numberOfEntriesPerPage);
if (timelineResult.Succeeded && timelineResult.Result.Count != 0)
{
do
{
// Do whatever needs to be done on the page of timeline entries.
// Get the next page
if (!string.IsNullOrEmpty(timelineResult.Result.Cursor))
{
timelineResult =
await agent.GetTimeline(
limit: numberOfEntriesPerPage,
cursor: timelineResult.Result.Cursor, cancellationToken: cancellationToken);
}
pageCount++;
} while (timelineResult.Succeeded &&
!string.IsNullOrEmpty(timelineResult.Result.Cursor) &&
pageCount < maximumPagesToRetrieve);
}
Tip
The code above will work for any method that returns a paginated result, like GetFeed(), GetAuthorFeed(), ListNotifications(), etc.
Feed Generators
Feed generators (custom feeds) are created by users and organizations, and are therefore tied to an account via its DID. References to feed generators take the form of a at:// uri with the following shape:
at://<did>/app.bsky.feed.generator/<record_key>
To fetch a feed from a generator use the GetFeed() method on the agent. It accepts three key parameters,
GetFeed(feed, cursor?, limit?)
| Parameter | Type | Description | Required | Default |
|---|---|---|---|---|
| feed | AtUri | The at:// uri of the feed | Yes | |
| cursor | string | A cursor that tells the server where to paginate from | No | null |
| limit | int | The number of posts to return per page (max 100) | No | 50 |
var feedResult = await agent.GetFeed(
feed: "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot",
limit: 30,
headers: [new("Accept-Language", "en")]);
Tip
Bluesky recommends sending the Accept-Language header to get posts in the user's preferred language.
This header accepts a comma separated string of two-character language codes, e.g. en,es.
Feed generators also described by data accessible via the GetFeedGenerator() method.
This method returns metadata about the generator including its name, description etc.
GetFeedGenerator() accepts one key parameter,
GetFeedGenerator(feed)
| Parameter | Type | Description | Required | Default |
|---|---|---|---|---|
| feed | AtUri | The at:// uri of the feed | Yes |
var feedGeneratorResult = await agent.GetFeedGenerator(
feed: "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot");
Author Feeds
Author feeds return posts by a single user. You can retrieve an author feed with GetAuthorFeed,
which accepts four key parameters
GetAuthorFeed(actor, filter?, cursor?, limit?)
| Parameter | Type | Description | Required | Options | Default |
|---|---|---|---|---|---|
| actor | Did | The DID of the user whose posts you'd like to fetch | Yes | ||
| filter | FeedFilter | The type of posts you'd like to receive in the results | No | FeedFilter.PostsWithReplies FeedFilter.PostsNoReplies FeedFilter.PostsWithMedia FeedFilter.PostsAndAuthorThreads |
FeedFilter.PostsNoReplies |
| cursor | string | A cursor that tells the server where to paginate from | No | null | |
| limit | int | The number of posts to return per page (max 100) | No | 50 |
var authorFeedResult = await agent.GetAuthorFeed(
actor: "did:plc:z72i7hdynmk6r22z27h6tvur",
filter: FeedFilter.PostsAndAuthorThreads,
limit: 30);