AD
Boost Your Brand on BlueSky—Exclusive banner space to amplify your reach within the BlueSky community.
BSkyInfo LogoBskyInfo
All ToolsCategoriesCollectionsFeed DirectoryLabeler DirectoryArticlesGuidesGlossaryBluesky SDKsSponsor
Submit
All ToolsCategoriesCollectionsFeed DirectoryLabeler DirectoryGuidesGlossaryArticlesBluesky SDKsSponsorSubmit
  1. SDKs
  2. /r
  3. /atrrr
JBGruber

atrrr

A r SDK for Bluesky and AT Protocol by JBGruber

AT Protocol (Authenticated Transfer Protocol behind Bluesky) R package

GitHub Stats

34stars
8forks
7contributors
5open issues

Dates

Created:September 27, 2023
Last updated:May 15, 2025

README

The following content is from atrrr's GitHub repository. All rights reserved by the original author.

atrrr

CRAN
status CRAN_Download_Badge R-CMD-check Codecov test
coverage

The goal of atrrr1 is to wrap the AT Protocol (Authenticated Transfer Protocol) behind Bluesky. And we have actually already fulfilled this goal!.

The entire protocol is open and documented in so-called lexicons, from which we autogenerated R functions.

These are not exported, however, since dealing with them is a bit advanced. Rather we have some nice human-generated functions with documentation and examples.

Installation

You can install atrrr from CRAN with:

install.packages("atrrr")

You can install the development version of atrrr like so (install the remotes package first, with install.packages("remotes"), if you don’t have that yet):

# install.packages("remotes")
remotes::install_github("JBGruber/atrrr")

Load the package

library(atrrr)

Authentication

The first time you make a request, you will be prompted automatically to enter your user handle and an app password to authenticate atrrr to communicate with BlueSky for you.

RStudio Popup
RStudio Popup

The page to generate app passwords is also automatically opened for you.

page to create new app passwords
page to create new app passwords

However, you can also trigger this process manually:

auth("jbgruber.bsky.social")

This can be useful if you want to replace an old token as it is permanently stored encrypted on disk.

Retrieve Skeets (get_skeets_authored_by)

To fetch all the skeets by a specific user, use the get_skeets_authored_by function. Note this also includes quote skeets and reskeets. You can also opt not to parse the result by setting parse = FALSE, however it is recommended to use the default parse option which results in a (more) tidy tibble.

get_skeets_authored_by(actor = "benguinaudeau.bsky.social", parse = TRUE) |>
  dplyr::glimpse()
#> Rows: 25
#> Columns: 21
#> $ uri           <chr> "at://did:plc:ntd53albt5ffa4rgervvgibd/app.bsky.feed.pos…
#> $ cid           <chr> "bafyreiconry2rc74zkunyalbhwsxa347gxjnhb7uza7y4njnecu3ek…
#> $ author_handle <chr> "jbgruber.bsky.social", "jacobmontgomery.bsky.social", "…
#> $ author_name   <chr> "Johannes B. Gruber", "Jacob Montgomery", "Beatrice Magi…
#> $ text          <chr> "I didn't even notice CRAN already approved it, but our …
#> $ author_data   <list> ["did:plc:ntd53albt5ffa4rgervvgibd", "jbgruber.bsky.soc…
#> $ post_data     <list> ["app.bsky.feed.post", "2024-10-04T12:43:04.752Z", ["ap…
#> $ embed_data    <list> ["app.bsky.embed.record#view", ["app.bsky.embed.record#…
#> $ reply_count   <int> 0, 0, 0, 1, 4, 0, 0, 4, 0, 1, 9, 0, 1, 0, 1, 0, 0, 0, 0,…
#> $ repost_count  <int> 5, 3, 6, 6, 8, 0, 0, 15, 2, 1, 432, 3, 1, 5, 28, 0, 0, 0…
#> $ like_count    <int> 11, 13, 13, 20, 13, 1, 1, 42, 6, 1, 606, 7, 3, 10, 35, 1…
#> $ indexed_at    <dttm> 2024-10-04 12:43:04, 2024-03-18 21:09:28, 2024-02-16 17…
#> $ in_reply_to   <chr> NA, NA, NA, NA, NA, NA, "at://did:plc:eotrvt2wp6mqooxjf3…
#> $ in_reply_root <chr> NA, NA, NA, NA, NA, NA, "at://did:plc:eotrvt2wp6mqooxjf3…
#> $ quotes        <chr> "at://did:plc:vgvueqvmbqgoyxtcdebqdcgb/app.bsky.feed.pos…
#> $ tags          <list> "rstats", <NULL>, <NULL>, "rstats", "rstats", <NULL>, <…
#> $ mentions      <list> <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>,…
#> $ links         <list> <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>,…
#> $ langs         <list> ["en"], ["en"], ["it"], ["en"], ["en"], ["en"], ["en"],…
#> $ labels        <list> [], [], [], [], [], [], [], [], [], [], [], [], [], [],…
#> $ is_reskeet    <lgl> TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, …

Analyzing Feeds on Blue Sky

On Blue Sky users have the ability to create custom feeds based on specific keywords. These feeds aggregate content, for instance, a user might curate a feed around the hashtag #rstats to gather all relevant content about. Let’s delve into the dynamics of such feeds.

Our starting point is to extract the posts from the #rstats feed created by “andrew.heiss.phd”.

# Fetching the feed posts
feeds <- get_feeds_created_by(actor = "andrew.heiss.phd") 

# Filtering for a specific keyword, for example "#rstats"
rstat_feed <- feeds |>
  filter(displayName == "#rstats")

# Extracting posts from this curated feed
rstat_posts <- get_feed(rstat_feed$uri, limit = 200) |>
  dplyr::glimpse()
#> Rows: 292
#> Columns: 20
#> $ uri           <chr> "at://did:plc:7crs3axm67jhrc57gi7ojyjn/app.bsky.feed.pos…
#> $ cid           <chr> "bafyreicru2iryln3mqm6skdhym4illw2kn6z7qqig34trfvsp72zyi…
#> $ author_handle <chr> "timbulwidodostp.bsky.social", "bigbookofr.bsky.social",…
#> $ author_name   <chr> "Timbul Widodo, S.TP", "Big Book of R", "Craig Hamilton"…
#> $ text          <chr> "Sequential analysis poisson binomial data g estimation …
#> $ author_data   <list> ["did:plc:7crs3axm67jhrc57gi7ojyjn", "timbulwidodostp.b…
#> $ post_data     <list> ["app.bsky.feed.post", "2024-11-16T13:08:30.723Z", [[[[…
#> $ embed_data    <list> <NULL>, <NULL>, <NULL>, ["app.bsky.embed.record#view", …
#> $ reply_count   <int> 0, 0, 0, 0, 1, 2, 0, 0, 1, 2, 1, 0, 0, 3, 1, 0, 0, 0, 0,…
#> $ repost_count  <int> 0, 0, 0, 3, 0, 19, 0, 1, 0, 2, 1, 4, 0, 11, 0, 0, 1, 0, …
#> $ like_count    <int> 0, 0, 0, 3, 1, 37, 0, 3, 1, 4, 1, 14, 1, 21, 1, 1, 4, 5,…
#> $ indexed_at    <dttm> 2024-11-16 13:08:30, 2024-11-16 12:31:26, 2024-11-16 12…
#> $ in_reply_to   <chr> NA, NA, "at://did:plc:ntd53albt5ffa4rgervvgibd/app.bsky.…
#> $ in_reply_root <chr> NA, NA, "at://did:plc:ntd53albt5ffa4rgervvgibd/app.bsky.…
#> $ quotes        <chr> NA, NA, NA, "at://did:plc:ntd53albt5ffa4rgervvgibd/app.b…
#> $ tags          <list> <"RStats", "rstats", "rsoftware", "rstatistics">, <NULL…
#> $ mentions      <list> <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>,…
#> $ links         <list> <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>,…
#> $ langs         <list> ["en"], <NULL>, ["en"], ["en"], ["en"], ["en"], <NULL>,…
#> $ labels        <list> [], [], [], [], [], [], [], [], [], [], [], [], [], [],…

Learn More?

Start with the Basic Usage vignette to learn more.

Want to help?

You can help by creating an issue requesting new features or reporting bugs.

If you are a developer, we are happy to accept pull requests. It should be fairly straightforward, as all endpoints are already covered by automatically generated function. For example, the endpoint app.bsky.actor.getProfiles is accessible via atrrr:::app_bsky_actor_get_profiles(). The function get_user_info() is just a thin wrapper around that and calls an optional parsing function:

get_user_info <- function(actor,
                          parse = TRUE,
                          .token = NULL) {

  # we need to use do.call so objects are passed to the right environment
  res <- do.call( 
    what = app_bsky_actor_get_profiles,
    args = list(
      actor,
      .token = .token, # tokens are handled automatically under the hood
      .return = "json"
    )) |>
    purrr::pluck("profiles")

  if (parse) {
    res <- parse_actors(res)
  }
  return(res)
}

If you find an endpoint at https://docs.bsky.app/docs/category/http-reference that interests you, you can write a similar wrapper and contribute it to the package (or build something new on top of it). But please open an issue first, so we don’t do duplicated work.

Footnotes

  1. before 2024-01-04, this package was called atr, meaning an R package for the AT protocol (similar to httr, which is a package for the HTTProtocol). Unfortunatley, when we wanted to release the package on CRAN, the name atr was rejected, as a package of the same name existed some time ago. So we added two “r” to make the package go brrr anyway! ↩

Topics

atprotoblueskyr

Related SDKs

colin-fraserblueRsky

Talk to bluesky

6•r

Resources

GitHub RepositoryProject Website

License

NOASSERTION

Author

JBGruber
JBGruber
did:plc:ntd53albt5ffa4rgervvgibd

Activity

Last commit: May 15, 2025
Commit frequency: Unknown

Our Sponsors

Your Brand Here!

50K+ engaged viewers every month

Limited spots available!

📧 Contact us via email🦋 Contact us on Bluesky
BSkyInfo LogoBskyInfo

The Most Comprehensive Bluesky Tools Directory

Stay updated with the latest Bluesky tools and ecosystem news 🦋

Bluesky butterfly logo
Quick LinksSubmit a ToolSponsorAboutLegal Information
ToolsFeed DirectoryLabeler DirectorySchedulingAnalyticsAll ToolsCategoriesCollectionsTags
ResourcesArticlesBluesky GuidesBluesky GlossaryBluesky SDKsBluesky ResourcesSkyRaffleMeida Coverage
Our ProductsRaffleBlueAiTeach ToolsLaiewAI affiliate listFirsto

This website may contain affiliate links

© 2025 BskyInfo. All rights reserved.