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. /Go
  3. /go-bluesky
karalabe

go-bluesky

A Go SDK for Bluesky and AT Protocol by karalabe

Bluesky API client from Go

GitHub Stats

84stars
12forks
4contributors
1open issues

Dates

Created:April 27, 2023
Last updated:May 8, 2025

README

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

Bluesky API client from Go

API Reference Go Report Card

This is a Bluesky client library written in Go. It requires a Bluesky account to connect through and an application password to authenticate with.

This library is highly opinionated and built around my personal preferences as to how Go code should look and behave. My goals are simplicity and security rather than flexibility.

Disclaimer: The state of the library is not even pre-alpha. Everything can change, everything can blow up, nothing may work, the whole thing might get abandoned. Don't expect API stability.

Authentication

In order to authenticate to the Bluesky server, you will need a login handle and an application password. The handle might be an email address or a username recognized by the Bluesky server. The password, however, must be an application key. For security reasons this we will reject credentials that allow full access to your user.

import "errors"
import "github.com/karalabe/go-bluesky"

var (
	blueskyHandle = "example.com"
	blueskyAppkey = "1234-5678-9abc-def0"
)

func main() {
	ctx := context.Background()

	client, err := bluesky.Dial(ctx, bluesky.ServerBskySocial)
	if err != nil {
		panic(err)
	}
	defer client.Close()

	err = client.Login(ctx, blueskyHandle, blueskyAppkey)
	switch {
		case errors.Is(err, bluesky.ErrMasterCredentials):
			panic("You're not allowed to use your full-access credentials, please create an appkey")
		case errors.Is(err, bluesky.ErrLoginUnauthorized):
			panic("Username of application password seems incorrect, please double check")
		case err != nil:
			panic("Something else went wrong, please look at the returned error")
	}
}

Of course, most of the time you won't care about the errors broken down like that. Logging the error and failing is probably enough in general, the introspection is meant for strange power uses.

The above code will create a client authenticated against the given Bluesky server. The client will automatically refresh the authorization token internally when it closes in on expiration. The auth will be attempted to be refreshed async without blocking API calls if there's enough time left, or by blocking if it would be cutting it too close to expiration (or already expired).

Profiles and images

Any user's profile can be retrieved via the bluesky.Client.FetchProfile method. This will return some basic metadata about the user.

profile, err := client.FetchProfile(ctx, "karalabe.bsky.social")
if err != nil {
	panic(err)
}
fmt.Println("Name:", profile.Name)
fmt.Println("  - Followers:", profile.FollowerCount)
fmt.Println("  - Follows:", profile.FolloweeCount)
fmt.Println("  - Posts:", profile.PostCount)

Certain fields, like avatars and banner images are not retrieved by default since they are probably large and most use cases don't need them. If the image URLs are not enough, the images themselves can also be retrieved lazily into image.Image fields.

if err := profile.ResolveAvatar(ctx); err != nil {
	panic(err)
}
fmt.Println("Avatar size:", profile.Avatar.Bounds())

if err := profile.ResolveBanner(ctx); err != nil {
	panic(err)
}
fmt.Println("Banner size:", profile.Banner.Bounds())

Social graph

Being a social network, there's not much fun without being able to hop though the social graph. A user profile is a good starting point to do that! The list of followers and followees of a user can both be retrieved lazily after fetching the profile.

fmt.Println("User followed by:")
if err := profile.ResolveFollowers(ctx); err != nil {
	panic(err)
}
for _, follower := range profile.Followers {
	fmt.Println("  -", follower)
}

fmt.Println("User follows:")
if err := profile.ResolveFollowees(ctx); err != nil {
    panic(err)
}
for _, followee := range profile.Followees {
	fmt.Println("  -", followee)
}

The above resolvers are elegant, self-contained methods, but if the follower/followee count of a user is significant, it might be suboptimal to just wait hoping for the method to eventually return without using up too much memory. A more powerful way is to request the follower/followees to be returned as a stream as they are crawled!

fmt.Println("User followed by:")
followerc, errc := profile.StreamFollowers(ctx)
for follower := range followerc { // Pull the users from the channel as they arrive
	fmt.Println("  -", follower)
}
if err := <-errc; err != nil {
	panic(err)
}

fmt.Println("User follows:")
followeec, errc := profile.StreamFollowees(ctx)
for followee := range followeec { // Pull the users from the channel as they arrive
	fmt.Println("  -", followee)
}
if err := <-errc; err != nil {
	panic(err)
}

Of course, as with the user profiles, follower and followee items also contain certain lazy resolvable fields like the profile picture. In order however to crawl the social graph further, you will need to fetch the profile of a follower/followee first and go from there.

Custom API calls

As with any client library, there will inevitably come the time when the user wants to call something that is not wrapped (or not yet implemented because it's a new server feature). For those power use cases, the library exposes a custom caller that can be used to tap directly into the atproto APIs.

The custom caller will provide the user with an xrpc.Client that has valid user credentials and the user can do arbitrary atproto calls with it.

client.CustomCall(func(api *xrpc.Client) error {
	_, err := atproto.ServerGetSession(context.Background(), api)
	return err
})

Note, the user should not retain the xprc.Client given to the callback as this is only a copy of the internal one and will not be updated with new JWT tokens when the old ones are expired.

Testing

Oh boy, you're gonna freak out 😅. Since there's no Go implementation of a Bluesky API server and PDS, there's nothing to run the test against... apart from the live system 😱.

To run the tests, you will have to provide authentication credentials to interact with the official Bluesky server. Needless to say, your testing account may not become the most popular with all the potential spam it might generate, so be prepared to lose it. ¯_(ツ)_/¯

To run the tests, set the GOBLUESKY_TEST_HANDLE, GOBLUESKY_TEST_PASSWD and GOBLUESKY_TEST_APPKEY env vars and run the tests via the normal Go workflow.

$ export GOBLUESKY_TEST_HANDLE=example.com
$ export GOBLUESKY_TEST_PASSWD=my-pass-phrase
$ export GOBLUESKY_TEST_APPKEY=1234-5678-9abc-def0

$ go test -v

License

3-Clause BSD

Topics

api-clientblueskygolang

Related SDKs

bluesky-socialindigo

Go source code for Bluesky's atproto services.

1123•Go
bluesky-socialjetstream

A simplified JSON event stream for AT Proto

385•Go
uabluerailindexer

ATproto PDS indexer

21•Go
CharlesDardamanblueskyfirehose

Simple golang firehose for Bluesky.

62•Go
danruseigobot-bsky

Bluesky Bot library in Go

18•Go
ericvolp12go-bsky-feed-generator

A minimal implementation of a BlueSky Feed Generator in Go

32•Go

Resources

GitHub Repository

License

BSD-3-Clause

Author

karalabe
karalabe

Activity

Last commit: May 8, 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.