Embed a live, interactive Bluesky profile card anywhere in a MyST Markdown document or Curvenote article. The widget fetches directly from the AT Protocol public API in the browser at render time — no bundler, no API key, no server required.
Installation¶
Download bluesky-profile-card.js and host it anywhere that can serve static files (a MyST site’s public/ folder, a CDN, GitHub Pages). Then reference it by URL in the any:bundle directive.
Usage¶
Add a profile card to any MyST document with the any:bundle directive:
:::{any:bundle} https://example.com/bluesky-profile-card.js
{ "actor": "your-handle.bsky.social" }
:::The directive body is a JSON object. Only actor is required:
| Field | Type | Default | Description |
|---|---|---|---|
actor | string | — | Bluesky handle (e.g. "opensci.dev") or DID (required) |
show_stats | boolean | true | Display followers / following / post counts |
theme | "light" | "dark" | "light" | Card colour scheme |
link_target | boolean | true | Make the entire card a clickable link to the Bluesky profile |
Minimal example¶
:::{any:bundle} https://example.com/bluesky-profile-card.js
{ "actor": "mystmd.org" }
:::Dark theme, stats hidden¶
:::{any:bundle} https://example.com/bluesky-profile-card.js
{ "actor": "opensci.dev", "theme": "dark", "show_stats": false }
:::Non-clickable card (embed only)¶
:::{any:bundle} https://example.com/bluesky-profile-card.js
{ "actor": "opensci.dev", "link_target": false }
:::How it works¶
The widget is a plain ESM module (type: module). When rendered, it:
Shows an animated skeleton placeholder immediately.
Calls
https://api.bsky.app/xrpc/app.bsky.actor.getProfile— a fully public endpoint, no authentication needed.Replaces the skeleton with the rendered card, or an error state if the handle could not be resolved.
All network calls happen in the reader’s browser. There is no proxy, no backend, and no credentials involved.
Accessibility¶
When link_target is true the card element receives role="link" and tabindex="0" and responds to the Enter key, making it keyboard-navigable. The “View on Bluesky” footer link is always present and independently focusable regardless of the link_target setting.
Browser support¶
Any browser with native ES module support (all modern browsers). No polyfills are required.
Source¶
The widget source lives in dist/bluesky-profile-card.js and has no runtime dependencies. It uses the browser-native fetch API and plain DOM manipulation.
Further reading¶
Copyright © 2026 Purves. This article is distributed under the terms of the MIT License license.