
Working with Lists and Starter Packs
Source:vignettes/lists_and_starter_packs.Rmd
lists_and_starter_packs.Rmd
Introduction
Bluesky lists and starter packs are
two features for organizing and sharing groups of users (and content). A
list (lexicon type app.bsky.graph.list
) is a
curated set of user accounts (actors) – similar to Twitter lists – that
can be used for curation or moderation purposes. A starter pack
(lexicon type app.bsky.graph.starterpack
) is a shareable
collection of accounts (and optionally algorithmic feeds) intended to
help onboard new users by suggesting who to follow and which feeds to
try. In practice, a starter pack is backed by a list of accounts and up
to a few feeds.
In this vignette, we demonstrate how to use bskyr
to
programmatically interact with Bluesky lists and starter packs: fetching
existing lists/packs, creating and managing lists, and using lists as
the basis for starter packs.
Authentication: Before proceeding, ensure you are
authenticated with Bluesky. Assuming you have already configured your
Bluesky credentials (via set_bluesky_user()
and
set_bluesky_pass()
or environment variables), you can
authenticate once at the start:
library(bskyr)
auth <- bs_auth(user = bs_get_user(), pass = bs_get_pass())
Fetching and Exploring Lists
To retrieve the lists belonging to a specific user (actor), use
bs_get_actor_lists()
. This function returns a tibble of the
actor’s list records. Each list entry includes fields like its
uri
(the unique AT URI for the list record),
name
, purpose
, and any description:
# Fetch all lists created by a given user (actor)
user_lists <- bs_get_actor_lists('bskyr.bsky.social')
user_lists
You can inspect the details of a particular list using its URI. For example, to get a view of the first list from the above results:
first_list_uri <- user_lists$uri[1] # AT URI of the first list
first_list <- bs_get_list(first_list_uri) # retrieve detailed list info
first_list
The bs_get_list()
function returns the list’s metadata
and its members. If clean = TRUE
, it will be formatted as a
tibble for convenience. In addition, Bluesky provides mechanisms to mute
or block entire lists. You can retrieve lists that the current user has
muted or blocked via:
These return tibble
of list records that you have muted
or blocked, which is useful for moderation or content filtering.
Creating and Managing Lists
To create a new list, use bs_new_list()
. At minimum you
must provide a name
and a purpose
. The
purpose
should be one of 'curatelist'
,
'modlist'
, or 'referencelist'
, distinguishing
a normal curated list from a moderation list, etc. For typical
user-curated lists, use 'curatelist'
. You may also include
an optional description
(and even an avatar
image file if desired).
Here we’ll make a list on redistricting experts. My day job is redistricting research, so I’ll add some of my colleagues to the list.
# Create a new curated list
new_list <- bs_new_list(
name = '[vignette] Redistricting Experts',
purpose = 'curatelist',
description = 'A list of interesting people in redistricting'
)
After creating a list, you can add members to it using
bs_new_list_item()
. Each call adds a single account,
identified by handle or DID, to the specified list. You must provide the
subject
(the account to add) and the list’s
uri
:
# Add members to the list
bs_new_list_item(
subject = 'chriskenny.bsky.social',
uri = new_list$uri
)
bs_new_list_item(
subject = 'simko.bsky.social',
uri = new_list$uri
)
bs_new_list_item(
subject = 'corymccartan.com',
uri = new_list$uri
)
If needed, you can remove a member from a list with
bs_delete_list_item()
. This function requires the record
key (rkey
) of the list item (the membership record).
Typically, you can extract that from the uri
of the item
returned when it was added.
Here, we’ll add a new member to the list and then remove it. I’ll use
this testing account (bskyr.bsky.social
) as an example:
fourth_item <- bs_new_list_item(
subject = 'bskyr.bsky.social', uri = new_list$uri
)
item_rkey <- bs_extract_record_key(fourth_item$uri)
bs_delete_list_item(item_rkey)
Finally, to delete an entire list, use bs_delete_list()
with the list’s record key. As with items, you can obtain the list’s
record key from its uri
:
list_rkey <- bs_extract_record_key(new_list$uri)
bs_delete_list(list_rkey)
After deletion, the list and its memberships are removed from your Bluesky account.
Understanding Starter Packs
Starter packs are curated bundles of recommendations. A starter pack typically includes a set of accounts, often centered around a theme or community, and can also include references to up to three custom feeds. Users can use a starter pack to quickly follow a group of people and subscribe to feeds with one click during onboarding. Under the hood, a starter pack record points to a list of accounts and an optional set of feed URIs. In other words, creating a starter pack is essentially packaging an existing list (of actors) and some feeds into a shareable recommendation set.
Fetching Starter Packs
To retrieve starter packs created by a specific user, use
bs_get_actor_starter_packs()
. This is analogous to fetching
lists, but for packs. It returns a tibble
of the user’s
starter pack records:
user_packs <- bs_get_actor_starter_packs('chriskenny.bsky.social')
user_packs |>
dplyr::select(record_name, record_description)
If you have the AT URI of a particular starter pack, you can fetch
its details with bs_get_starter_pack()
. This will return
the pack’s metadata along with the contents (the list of accounts and
any feeds it includes):
bs_get_starter_pack('https://bsky.app/starter-pack/jkertzer.bsky.social/3laywns2q2v27') |>
dplyr::select(record_name, record_description)
For convenience, bskyr
also provides
bs_get_starter_packs()
, which can fetch multiple packs in
one call. You can supply a vector of starter pack URIs to
bs_get_starter_packs()
to retrieve them all at once:
bs_get_starter_packs(c(
'at://did:plc:bmc56x6ksb7o7sdkq2fgm7se/app.bsky.graph.starterpack/3laywns2q2v27',
'https://bsky.app/starter-pack/chriskenny.bsky.social/3lb3g5veo2z2r'
)) |>
dplyr::select(record_name, record_description)
Creating and Managing Starter Packs
Creating a new starter pack is done with
bs_new_starter_pack()
. The required arguments are a display
name
for the pack and a list
to base the pack
on. The list
should be the AT URI of a Bluesky list record
containing the accounts you want in the starter pack. If you don’t
already have a list prepared, you can omit the list
argument – in that case, bs_new_starter_pack()
will create
a new (empty) list for you behind the scenes. You would then need to add
accounts to it with bs_new_list_item()
. You can also
provide an optional description
for the pack, as well as a
feeds
vector of up to 3 feed generator URIs to include.
Here’s an example:
pack <- bs_new_starter_pack(
name = '[vignette] Redistricting people',
list = new_list$uri, # use an existing list of accounts
description = 'A starter pack of interesting redistricters'
)
After running the above, pack
will contain the newly
created starter pack record (including its own uri
). The
pack references the accounts in new_list
and the specified
feeds. If you omitted the list
parameter, remember to add
accounts to the pack’s list (accessible via pack$list
URI)
using bs_new_list_item()
calls.
If a starter pack is no longer needed, you can delete it with
bs_delete_starter_pack()
. As with lists, you must supply
the record key of the pack. For example:
# Delete the starter pack by its record key
pack_rkey <- bs_extract_record_key(pack$uri)
bs_delete_starter_pack(pack_rkey)
Deleting the pack removes the starter pack record, nbut does not delete the underlying list or its members. You may delete the list separately if desired.
Conclusion
In this vignette, we covered how to work with Bluesky lists and
starter packs using bskyr
. We saw how to fetch and view
existing lists, create new lists and manage their membership, and how
lists serve as the basis for starter packs. We also demonstrated
creating and deleting starter packs, including how to incorporate custom
feeds. Together, these tools enable you to programmatically organize
accounts into lists and craft shareable starter packs for recommending
content to others.
DISCLAIMER: This vignette has been written with help from ChatGPT 4o. It has been reviewed for correctness and edited for clarity by the package author. Please note any issues at https://github.com/christopherkenny/bskyr/issues.