Disclaimer: This article is for education and for lawful, authorised professional research. Use these methods only where you have a legitimate purpose and a lawful basis, and follow the laws and platform terms that apply to you, including data protection law such as the UK GDPR and EU GDPR. See our Terms of Service.
TL;DR
- In Bluesky OSINT, remember that every account has a permanent DID (usually
did:plc:...) and a changeable handle. Cite the DID, and treat the handle as a label. - The PLC directory publishes each account's audit log, so you can see when it was created and every handle it has used, with no login and no API key.
- Domain handles and the verification records Bluesky introduced in 2025 are strong signals for confirming that an account belongs to the organisation it names.
- Starter packs, lists and custom feeds are public and show how communities organise. For disinformation researchers they are often more revealing than the posts themselves.
- UserSearch lets you take a handle or domain off Bluesky and check it across other platforms and data sources in one auditable Case.
Why Does Bluesky OSINT Reward Researchers Who Read the Protocol?
Bluesky OSINT is research into Bluesky accounts, posts and communities using the public records of the AT Protocol, including each account's permanent DID, its handle history and its public lists and feeds. Most platforms give researchers a finished product: a page, a feed, a search box, and whatever the company decides to show. Bluesky is different. It runs on an open protocol, and almost everything the app shows you is a public record that you can fetch directly. That includes some things other platforms keep to themselves, such as a machine-readable history of every handle an account has used.
That openness is a gift for journalists and disinformation researchers, but only if you know where to look. The app shows you a handle like news.example.com and a display name. Underneath, there is a permanent identifier, a hosting server, a signed repository of records and a public log of changes. When a lookalike news account appears during a breaking story, the answer to "is this real?" is usually sitting in that log.
This guide explains the pieces you need: the AT Protocol basics, DIDs versus handles, domain handles and verification, the public endpoints you can query without an account, and the community signals in starter packs, lists and custom feeds.
What Are DIDs, Handles and Repositories in the AT Protocol?
Bluesky is built on the AT Protocol (atproto), an open protocol for social apps. Three concepts matter for research:
- DID (decentralised identifier): the permanent account ID. Most accounts use
did:plc:identifiers registered with the PLC directory; a few usedid:web:, tied to a domain. The atproto DID specification explains both. A DID resolves to a DID document listing the account's current handle, its signing key and the server that hosts its data. - Handle: the human-readable name, either a subdomain such as
example.bsky.socialor a domain the owner controls, such asnews.example.com. Handles can change. Bluesky's documented rate limits allow up to 10 handle updates per five minutes and 50 per day per account, so a busy operator can churn names quickly. - Repository and PDS: each account's posts, likes, follows, lists and other records live in a signed repository on a Personal Data Server (PDS). Bluesky runs most PDS instances, but any organisation or individual can run their own.
Two further services matter. The AppView (Bluesky's API) collects records from across the network and serves the timelines and threads you see in the app. The relay streams every change on the network, which is how custom feeds and research datasets are built.
Why It Matters: Verification and Influence Operations on Bluesky
Bluesky is now large enough to attract organised manipulation. Its 2025 transparency report, published in January 2026, says the service removed 3,619 accounts for involvement in suspected influence operations during the year, most assessed as linked to foreign state-aligned actors, including actors likely operating from Russia. The same report says the user base grew from about 26 million to 41 million during 2025, and that more than 309,000 accounts use domain handle verification.
Bluesky's response to copycat accounts has been layered. In April 2025 it launched blue check verification, with Bluesky verifying notable accounts directly and a set of "Trusted Verifiers" (organisations such as newsrooms) able to verify their own staff. The transparency report counts 4,327 verified accounts at the end of 2025, 777 of them via 21 Trusted Verifiers. For a newsroom deciding whether a quote came from a real minister or a lookalike, these signals are the first check. For teams researching coordinated campaigns, the protocol's public records show account creation times and rename histories that the app never displays. Our journalism research workflows are built for exactly this kind of verification.
How Do You Research Bluesky by Hand with Endpoints, Logs and Records?
Everything in this section runs with curl and jq and needs no Bluesky account, unless noted. Bluesky's API hosts documentation recommends public.api.bsky.app for unauthenticated public requests because it adds caching. Its rate limit page describes these direct API hosts as having generous limits, while PDS requests are limited to 3,000 per five minutes per IP. Be polite: add pauses and cache results.
Resolve a handle to its permanent DID
curl -s "https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle?handle=news.example.com"Returns a JSON object like {"did":"did:plc:..."}. Record the DID in your notes next to the handle, every time. If the handle changes tomorrow, the DID still points to the same account.
For a domain handle, check the proof yourself. The handle specification allows two methods, a DNS TXT record or an HTTPS well-known file:
dig +short TXT _atproto.news.example.com
curl -s https://news.example.com/.well-known/atproto-didThe first queries the _atproto TXT record, which should return "did=did:plc:...". The second fetches the well-known file, which should contain the DID as plain text. Bluesky's domain handle tutorial walks account holders through the TXT method. A matching record proves that whoever controls the domain's DNS or web server chose to link it to that DID. It does not prove the domain belongs to the organisation it names, so check the domain too.
Read the account's history in the PLC audit log
This is the most valuable free source on Bluesky. The PLC directory keeps a signed log of every operation on a did:plc account, and its HTTP API provides the full audit log per DID:
curl -s "https://plc.directory/did:plc:EXAMPLE/log/audit" \
| jq '.[] | {createdAt, handles: .operation.alsoKnownAs, pds: .operation.services.atproto_pds.endpoint}'Each entry has a createdAt timestamp, the handles in alsoKnownAs (prefixed at://) and the PDS endpoint at that time. The first entry is effectively the account's creation date. Later entries show every rename and every move between servers. Bluesky's own account, for example, started as bluesky-team.bsky.social in April 2023 and switched to bsky.app the same day. The log also lists rotation keys; accounts that share unusual self-hosted PDS endpoints or change handles in lockstep are worth a closer look.
Use goat and the Python SDK for repeatable lookups
If you do this often, use tooling. goat is Bluesky's official Go command-line tool for atproto. Install it with brew install goat, a release binary, or:
go install github.com/bluesky-social/goat@latest
goat resolve news.example.com
goat plc history news.example.com
goat syntax tid inspect 3kzifvcppte22goat resolve prints the DID document. goat plc history shows the PLC operation history in readable form. goat syntax tid inspect decodes a record key: Bluesky post IDs are TIDs (timestamp identifiers), so the last part of a post's at:// URI tells you when the record key was generated. Most read commands need no login; writing records requires an account.
For Python, the community atproto SDK installs with pip install atproto and includes an identity resolver that tries DNS first, then HTTPS:
from atproto import IdResolver
r = IdResolver()
did = r.handle.resolve("news.example.com")
print(did, r.did.resolve(did).get_pds_endpoint())No API key is required for resolution. It returns None when a handle does not resolve, whether because it does not exist or because the domain did not answer, so log failures separately from negatives.
Compare the three timestamps on every post
A Bluesky post carries more than one time, and they do not always agree. The record's createdAt field is written by the posting client, so it can be set to any date, including one years in the past. Imported or backdated posts are a feature of the protocol, not a bug, which is exactly why you should not rely on the claimed date alone. The AppView adds an indexedAt time when it first saw the record, which the author does not control. The record key (the TID at the end of the at:// URI) is also generated by the client, usually at posting time. When you run getAuthorFeed, pull both values:
curl -s "https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed?actor=news.example.com&limit=100" \
| jq -r '.feed[].post | [.uri, .record.createdAt, .indexedAt] | @tsv'The jq filter prints each post's URI, claimed creation time and indexing time as tab-separated columns. Gaps of a few seconds are normal. A post claiming to be from 2023 that was indexed last Tuesday tells you the history was manufactured, and that single row is often the strongest evidence in a report about a lookalike account.
Check verification records directly
Verification on Bluesky is itself a public record. A verifier's repository holds app.bsky.graph.verification records containing the subject's DID, the handle and display name at the moment of verification, and a timestamp. The verification record definition states that a verification is only valid if the account's current handle and display name still match. So if a verified account renames itself, the badge stops applying until it is re-verified. You can list a verifier's records from its PDS (the endpoint comes from the DID document):
curl -s "https://PDS_HOST/xrpc/com.atproto.repo.listRecords?repo=did:plc:VERIFIER&collection=app.bsky.graph.verification&limit=50"Read posts, starter packs, lists and feeds without an account
curl -s "https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed?actor=news.example.com&filter=posts_no_replies&limit=50"
curl -s "https://public.api.bsky.app/xrpc/app.bsky.graph.getActorStarterPacks?actor=news.example.com"
curl -s "https://public.api.bsky.app/xrpc/app.bsky.graph.getLists?actor=news.example.com"
curl -s "https://public.api.bsky.app/xrpc/app.bsky.feed.getActorFeeds?actor=news.example.com"In order: the account's own posts without replies (other filters include posts_with_media and posts_with_video), the starter packs it created, the lists it owns, and the custom feeds it runs. All four worked unauthenticated when we tested them in September 2026. Post search is different: unauthenticated calls to app.bsky.feed.searchPosts on the public host returned 403 Forbidden in our tests, so search from a logged-in account. The search method documents useful filters:
q="bridge collapse" author=news.example.com since=2026-03-01T00:00:00Z until=2026-03-08T00:00:00Z domain=example.org lang=enauthor and mentions resolve handles to DIDs before searching. since is inclusive and until exclusive, and both use the time the AppView sorted the post, which may differ from the createdAt the client claimed. domain matches posts linking to a hostname.
A note on what is visible without an account. Bluesky lets account holders ask apps not to show their account to logged-out visitors. The official app respects that choice, but it is a request to apps: the records remain public on the network. Respect it in your own work. If an account has opted out of logged-out viewing, treat its content as something the owner expected a narrower audience for, and weigh that in your proportionality assessment.
Taking Bluesky Research Further with UserSearch
The protocol answers questions about the account. The next questions usually sit elsewhere. Who registered the domain behind a domain handle, and what else is hosted with it? Does the same handle appear on X, Telegram or Reddit? Is the avatar a stock image or a synthetic face? Each of those is a separate tool and a separate set of notes if you do it by hand.
UserSearch puts those pivots in one place. Domain Intelligence covers ownership, history and favicon links; our guide to domain OSINT and WHOIS infrastructure explains how to read them. Username Intelligence checks a handle across many platforms. The Picture Search type runs reverse image search, geolocation and synthetic-image checks. OneScan runs one input across the data sources you choose and merges results with source attribution, with the Credit cost shown before you run, and bulk search lets you push up to five inputs through one Module in a batch, which suits a cluster of related handles.
Keep the work in a Case with Forensic Mode on, so the search history and bookmarks sit with the evidence. Our free Forensic Capture extension saves Bluesky pages as full-page captures with SHA-256 fingerprints and RFC 3161 and OpenTimestamps timestamps, running locally in your browser. UserSearch results are leads to corroborate, and coverage depends on the third-party source.
Community Signals: Starter Packs, Lists and Custom Feeds
Starter packs show who a community recommends
Bluesky introduced starter packs in June 2024: shareable bundles of up to 150 recommended accounts and up to three custom feeds. They are public records, so they show how a community describes itself and whom it promotes. For disinformation research, a starter pack that bundles a set of new accounts under a trusted-sounding name ("verified local journalists", for instance) is a signal worth mapping. Compare the pack's creation date with the PLC creation dates of its members.
Lists and feeds reveal curation choices
Curation lists group accounts for reading; moderation lists are shared mute or block lists. Both are public. Custom feeds are algorithms run by independent services, often under a did:web identifier, and Bluesky's custom feed documentation explains how they are built. A feed's description and creator tell you who is shaping what a community sees. When a narrative spreads unusually fast, check which feeds carried it.
Scenario: confirming a news outlet's account during a breaking story
Context. During a fast-moving story, two accounts post a statement attributed to a fictional national broadcaster, Example News: news.example.com and examplenews-official.bsky.social. The second has more reposts.
Actions. A verification editor resolves both handles and runs the PLC audit log. news.example.com was created in 2023, has used one handle, and its _atproto TXT record on the broadcaster's own domain returns the matching DID. It carries a blue check, and the verification record's handle and display name match the current ones. examplenews-official.bsky.social was created 36 hours earlier under a different name and renamed twice since. Its bio links to example.org, a domain registered last week.
Outcome. The desk quotes only the domain-handle account, includes both DIDs in its internal notes and reports the lookalike to Bluesky's moderation team with the audit log as evidence.
Scenario: mapping a coordinated cluster for a research report
Context. A fictional non-profit research group, Example Institute, studies a sudden burst of identical posts about a regional election.
Actions. Researchers collect the DIDs of 40 accounts that posted the text. The PLC logs show 31 were created within a 90-minute window on the same PDS, and 22 renamed themselves from numbered placeholder handles to local-sounding names in the same week. Decoding post TIDs shows posting in tight bursts. Twenty-eight of the accounts appear in the same starter pack, created by an account that is itself two days old.
Outcome. The report describes the cluster by DIDs and behaviour, not by guessing who is behind it. The group shares its findings with Bluesky's trust and safety team and publishes the method so others can reproduce it.
Research Ethics on an Open Protocol
The fact that data is easy to fetch does not settle whether you should fetch it. Public posts on Bluesky are still personal data under the UK GDPR and EU GDPR when they relate to identifiable people. Record your lawful basis (journalism or legitimate interests are common), collect what answers the question and set a retention period. Bluesky's developer guidelines require services built on the network to have a method for deleting content a user has asked to be deleted, and research tooling should follow the same spirit: if an account deletes a post, your dataset should not keep republishing it without a strong public interest reason.
- Study organisations, public figures acting in public roles and account behaviour. Keep private individuals out of your published findings unless there is a clear public interest.
- Honour the logged-out visibility choice and deletions in anything you publish.
- Describe clusters by DIDs and observable behaviour. Attribution to a named person or state needs far more than protocol metadata.
- Use the public host, cache results and stay well inside the documented rate limits.
Frequently Asked Questions About Bluesky OSINT
What is Bluesky OSINT?
Bluesky OSINT is open-source research on Bluesky using the public records of the AT Protocol. Almost everything the app shows is a record that can be fetched directly, including each account's permanent DID, its handle history in the PLC audit log, domain handle proofs, verification records, and public starter packs, lists and custom feeds, often without an account or API key.
What is the difference between a Bluesky handle and a DID?
A Bluesky DID, usually starting did:plc:, is the permanent account identifier, and it resolves to a document listing the current handle, signing key and hosting server. The handle, such as example.bsky.social or a domain like news.example.com, is a changeable label. Researchers should cite the DID, because the same account keeps it after every rename.
How can you see a Bluesky account's creation date and past handles?
The PLC directory publishes a signed audit log for every did:plc account, with no login or API key required. Each entry has a createdAt timestamp, the handles the account used and its hosting server at that time. The first entry is effectively the account's creation date, and later entries show every rename and every move between servers.
How do you verify that a Bluesky account belongs to an organisation?
Check whether the Bluesky account uses a domain handle, then confirm the proof yourself through the _atproto DNS TXT record or the well-known atproto-did file on the domain. Also check for a blue check and read the verification record, which is valid only while the handle and display name still match. Then check who controls the domain itself.
Can you do Bluesky OSINT without an account?
Much Bluesky OSINT works without an account. The public API host returns handle resolutions, author feeds, starter packs, lists and custom feeds unauthenticated, and the PLC directory serves audit logs openly. Post search is the exception: unauthenticated calls to searchPosts returned 403 Forbidden in our September 2026 tests, so searching needs a logged-in account.
Why can the date on a Bluesky post be wrong?
A Bluesky post's createdAt field is written by the posting client, so it can be set to any date, including years in the past. The indexedAt time, added when the AppView first saw the record, is not controlled by the author. A post claiming to be from 2023 but indexed last week shows that its history was manufactured.
Making Bluesky Findings Reproducible with UserSearch
Bluesky gives researchers something rare: a public, verifiable record of an account's creation, renames and hosting. Anchor your work to DIDs, read the PLC audit log, check domain handles and verification records yourself, and treat starter packs, lists and feeds as the map of how communities organise.
Stop guessing. Start researching with UserSearch. With one UserSearch account you get 18 Search types and access to 100+ third-party data sources, so a handle or domain found on Bluesky can be checked against other platforms, domains and images in minutes. OneScan merges results with source attribution, Cases in Forensic Mode keep a reviewable trail, Teams share Cases and a common Credit pool, and SargeBot can help draft a PDF report for you to verify. Start your next Bluesky enquiry with UserSearch.