Scripts

Bluesky Embed

Bluesky is a decentralized social media platform built on the AT Protocol.

Nuxt Scripts provides a <ScriptBlueskyEmbed> component that fetches post data server-side and exposes it via slots for complete styling control. All data is proxied through your server - no client-side API calls to Bluesky.

Bluesky Embed

View source

Nuxt Config Setup

To use the Bluesky Embed component, add this to your nuxt.config.ts:

export default defineNuxtConfig({
  scripts: {
    registry: {
      blueskyEmbed: {
        trigger: 'onNuxtReady',
      }
    }
  }
})

Example

Using Bluesky Embed in a component.

<script setup lang="ts">
const { proxy } = false()

// noop in development, ssr
// just works in production, client
function handleAction() {
  // renders server-side Bluesky embed
}
</script>

<template>
  <div>
    <button @click="handleAction">
      Send Event
    </button>
  </div>
</template>

This registers the required server API routes (/_scripts/embed/bluesky and /_scripts/embed/bluesky-image) that handle fetching post data and proxying images.

<ScriptBlueskyEmbed>

The <ScriptBlueskyEmbed> component is a headless component that:

  • Fetches post data server-side via the Bluesky public API (AT Protocol)
  • Proxies all images through your server for privacy
  • Converts rich text facets (links, mentions, hashtags) to HTML
  • Exposes post data via scoped slots for custom rendering
  • Caches responses for 10 minutes
  • Respects author opt-out (!no-unauthenticated label)

Demo

Blueskyの新たな章が始まります。創業者ジェイ・グレイバーがCEOを退任し、チーフ・イノベーションオフィサーに就任。元Automattic(WordPress.com)のトニ・シュナイダーが暫定CEOを務めます。 新CEOのオープンソース経営の経験と、創業者がイノベーションに集中する体制の両輪で、分散型ソーシャルの未来をさらに加速させていきます。 bsky.social/about/blog/0...
10:50 PM · Mar 9, 20262.1K likes703 reposts

Slot Props

The default slot receives the following props:

interface SlotProps {
  // Raw data
  post: BlueskyEmbedPostData
  // Author info
  displayName: string
  handle: string
  avatar: string // Proxied URL
  avatarOriginal: string // Original Bluesky CDN URL
  isVerified: boolean
  // Post content
  text: string // Plain text
  richText: string // HTML with links, mentions, and hashtags
  langs?: string[] // Language codes
  // Formatted values
  datetime: string // "12:47 PM · Feb 5, 2024"
  createdAt: Date
  likes: number
  likesFormatted: string // "1.2K"
  reposts: number
  repostsFormatted: string // "234"
  replies: number
  repliesFormatted: string // "42"
  quotes: number
  quotesFormatted: string // "12"
  // Media
  images?: Array<{
    thumb: string // Proxied thumbnail URL
    fullsize: string // Proxied full-size URL
    alt: string
    aspectRatio?: { width: number, height: number }
  }>
  externalEmbed?: {
    uri: string
    title: string
    description: string
    thumb?: string // Proxied URL
  }
  // Links
  postUrl: string
  authorUrl: string
  // Helpers
  proxyImage: (url: string) => string
}

Named Slots

SlotDescription
defaultMain content with slot props
loadingShown while fetching post data
errorShown if post fetch fails, receives { error }

How It Works

  1. Server-side fetch: The server fetches post data from public.api.bsky.app (AT Protocol) during SSR
  2. Handle resolution: The server resolves handles to DIDs for reliable post lookup
  3. Image proxying: The server rewrites all images to proxy through /_scripts/embed/bluesky-image
  4. Rich text: The component converts Bluesky facets (links, mentions, hashtags) to HTML
  5. Caching: The server caches responses for 10 minutes
  6. No client-side API calls: The user's browser never contacts Bluesky directly

Privacy Benefits

  • No third-party JavaScript loaded
  • No cookies set by Bluesky
  • No direct browser-to-Bluesky communication
  • User IP addresses not shared with Bluesky
  • All content served from your domain

Author Opt-Out

The component respects Bluesky's !no-unauthenticated label. If a post author has opted out of external embedding, the API returns a 403 error and the component shows the error slot.

postUrlstring required

The Bluesky post URL to embed.

apiEndpointstring = '/_scripts/embed/bluesky'

Custom API endpoint for fetching post data.

imageProxyEndpointstring = '/_scripts/embed/bluesky-image'

Custom image proxy endpoint.