Bluesky avatar API: getting a profile picture from a handle

Bluesky's public AppView API returns avatars without authentication. Here's how to call it, and when a plain image URL is simpler.

Bluesky is the friendliest major platform for this job: its public API returns profile data, avatar included, without a login.

The public API

curl "https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=bsky.app"

The JSON response has an avatar field with a URL on cdn.bsky.app. No token is needed for public profiles (example). actor takes a handle (jay.bsky.team, or a custom domain handle) or a DID. To fetch several at once, app.bsky.actor.getProfiles takes a list (docs).

Two things to handle yourself:

If you are already building on AT Protocol, use the API directly.

One image URL

<img src="https://avatarsapi.com/bluesky/bsky.app" alt="">

avatarapi does the lookup on a cache miss and answers with the image itself, so it goes straight into src with no fetch step. It is cached at the edge for 7 days by default, and the URL stays the same when the picture changes.

When the image URL wins

Use it when your app shows people from several networks. The same pattern covers Mastodon (/mastodon/user@instance), Twitch, X, and GitHub, so one <img> component handles all of them.

Try it: put https://avatarsapi.com/github/torvalds in an <img src>. No key, no signup. Read the docs or create a Project.