Short answer: open the list and tap the People tab. Every Bluesky list's members are public, including moderation lists and starter packs. For long lists, or to keep a copy, the public API returns the same members in pages of 100, and the script below turns any list into a CSV file you can open in Numbers, Excel or Google Sheets.
In the Bluesky App
- Open the list, from a link, a post or the owner's profile under Lists.
- Curation lists open on Posts. Switch to People to see the members.
- Moderation lists open on the member list directly.
The app shows members in pages as you scroll. On a big blocklist with thousands of members, that's a lot of scrolling, and there's no search inside the list.
From the API
The endpoint is app.bsky.graph.getList. It doesn't need you to sign in. It takes the list's AT-URI, which you can build from its web address:
Web link: https://bsky.app/profile/someone.bsky.social/lists/3abc123xyz
AT-URI: at://did:plc:OWNER_DID/app.bsky.graph.list/3abc123xyz
The last part of the link is the record key. The owner's DID comes from resolving their handle (com.atproto.identity.resolveHandle). Then:
https://public.api.bsky.app/xrpc/app.bsky.graph.getList?list=at://did:plc:OWNER_DID/app.bsky.graph.list/3abc123xyz&limit=100
The response has the list's details (name, purpose, listItemCount) and an items array with each member's handle, display name and DID. If there are more than 100 members it also returns a cursor; pass it back as &cursor=... to get the next page.
Export Any List to CSV
This script does all of that and downloads the result. Open the developer console in your browser (Cmd+Option+J in Chrome on a Mac, Ctrl+Shift+J on Windows), paste it, replace the link on the second line with the list you want, and press Enter:
// Paste into your browser's developer console. Downloads a CSV of a list's members.
const listUrl = "https://bsky.app/profile/someone.bsky.social/lists/3abc123xyz"; // <- change this
const [, actor, rkey] = listUrl.match(/profile\/([^/]+)\/lists\/([^/?#]+)/);
const did = actor.startsWith("did:") ? actor : (await (await fetch(
`https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle?handle=${actor}`)).json()).did;
const uri = `at://${did}/app.bsky.graph.list/${rkey}`;
const rows = [["handle", "display_name", "did"]];
let cursor = "";
do {
const page = await (await fetch(
`https://public.api.bsky.app/xrpc/app.bsky.graph.getList?list=${uri}&limit=100${cursor ? "&cursor=" + cursor : ""}`)).json();
for (const { subject } of page.items) {
rows.push([subject.handle, subject.displayName ?? "", subject.did]);
}
cursor = page.cursor;
} while (cursor);
const csv = rows.map(r => r.map(v => `"${String(v).replaceAll('"', '""')}"`).join(",")).join("\n");
const a = Object.assign(document.createElement("a"), {
href: URL.createObjectURL(new Blob([csv], { type: "text/csv" })),
download: "bluesky-list.csv",
});
a.click();
console.log(`Exported ${rows.length - 1} members`);
You get a file called bluesky-list.csv with three columns: handle, display name and DID. Keep the DID column if you plan to compare lists later, because handles change and DIDs don't.
Things People Use This For
- Checking a blocklist before subscribing. Subscribing to a moderation list blocks everyone on it, including people added later. Scan the members first.
- Copying a list into your own. If you want to edit someone else's curation list, export it and add the accounts to a list of your own. Theirs will keep changing; yours won't.
- Comparing two lists. Two exports and a spreadsheet lookup show who's on both.
- Seeing how a list changes. Export it today and again next month. The difference is who was added and removed.
- Archiving a list you made before you edit or delete it. See how to edit or delete a list.
Limits and Gotchas
- Lists taken down by moderators return an error instead of members.
- Accounts that have been deleted or suspended may be missing from the results even though the listitem record exists, so the exported row count can be a little lower than
listItemCount. - Very large lists take a few seconds: a 10,000-member list is 100 requests. The public API is generous, but don't run the script in a loop.
- Starter packs use a list too. Open the starter pack, find its list link in the share menu, or look it up with
app.bsky.graph.getStarterPack.
Frequently Asked Questions
Can anyone see who is on a Bluesky list?
Yes. All Bluesky lists are public, including moderation lists, and anyone can see their members without signing in.
Can I export a Bluesky list?
Not from the app, but the public getList API returns every member, and the script in this post saves them to a CSV file.
Can I see who is on a Bluesky block list before I subscribe?
Yes. Open the moderation list to see its members, or export it to check it in a spreadsheet first.
How do I copy someone else's Bluesky list?
Export the members, create your own list, and add the accounts you want. There's no built-in copy button.
Does exporting a list notify the owner?
No. Reading a list is a public, anonymous request and nobody is notified.
Lists in Skyscraper
Skyscraper reads, pins and browses Bluesky lists on iPhone, iPad and Mac, alongside your feeds and saved searches, and keeps blocked and muted accounts on their own pages in Settings. If you also use Mastodon, Skyscraper Pro adds Mastodon lists next to your Bluesky ones.