{"id":28557765,"url":"https://github.com/ryanhefner/use-bluesky","last_synced_at":"2026-05-09T02:11:24.674Z","repository":{"id":296327091,"uuid":"982855795","full_name":"ryanhefner/use-bluesky","owner":"ryanhefner","description":"🦋 React hooks to interact with the Bluesky API","archived":false,"fork":false,"pushed_at":"2025-05-30T03:18:43.000Z","size":22,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-30T04:25:12.523Z","etag":null,"topics":["bluesky","bluesky-api","context-provider","react","react-hooks"],"latest_commit_sha":null,"homepage":"https://www.pkgstats.com/pkg:use-bluesky","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ryanhefner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["replace-me"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2025-05-13T14:01:45.000Z","updated_at":"2025-05-30T03:18:45.000Z","dependencies_parsed_at":"2025-05-30T04:42:48.136Z","dependency_job_id":null,"html_url":"https://github.com/ryanhefner/use-bluesky","commit_stats":null,"previous_names":["ryanhefner/use-bluesky"],"tags_count":1,"template":false,"template_full_name":"ryanhefner/package-template-rollup-react","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryanhefner%2Fuse-bluesky","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryanhefner%2Fuse-bluesky/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryanhefner%2Fuse-bluesky/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryanhefner%2Fuse-bluesky/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ryanhefner","download_url":"https://codeload.github.com/ryanhefner/use-bluesky/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryanhefner%2Fuse-bluesky/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259033677,"owners_count":22795759,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bluesky","bluesky-api","context-provider","react","react-hooks"],"created_at":"2025-06-10T08:00:26.724Z","updated_at":"2026-05-09T02:11:19.654Z","avatar_url":"https://github.com/ryanhefner.png","language":"TypeScript","funding_links":["https://github.com/sponsors/replace-me"],"categories":[],"sub_categories":[],"readme":"# 🦋 use-bluesky\n\nReact hooks to interact with the Bluesky API.\n\n[![npm](https://img.shields.io/npm/v/use-bluesky?style=flat-square)](https://www.pkgstats.com/pkg:use-bluesky)\n[![NPM](https://img.shields.io/npm/l/use-bluesky?style=flat-square)](LICENSE)\n[![npm](https://img.shields.io/npm/dt/use-bluesky?style=flat-square)](https://www.pkgstats.com/pkg:use-bluesky)\n[![Coveralls github](https://img.shields.io/coveralls/github/ryanhefner/use-bluesky?style=flat-square)](https://coveralls.io/github/ryanhefner/use-bluesky)\n[![codecov](https://codecov.io/gh/ryanhefner/use-bluesky/branch/main/graph/badge.svg)](https://codecov.io/gh/ryanhefner/use-bluesky)\n[![CircleCI](https://img.shields.io/circleci/build/github/ryanhefner/use-bluesky?style=flat-square)](https://circleci.com/gh/ryanhefner/use-bluesky)\n![Known Vulnerabilities](https://snyk.io/test/github/ryanhefner/use-bluesky/badge.svg)\n![Twitter Follow](https://img.shields.io/twitter/follow/ryanhefner)\n\n## Install\n\nVia [npm](https://npmjs.com/package/use-bluesky)\n\n```sh\nnpm install use-bluesky\n```\n\nVia [Yarn](https://yarn.pm/use-bluesky)\n\n```sh\nyarn add use-bluesky\n```\n\n## Requirements\n\nThis library requires the following peer dependencies to be installed in your project:\n\n```sh\nnpm install @atproto/api@\u003e=0.10 @atproto/oauth-client-node@\u003e=0.2 @tanstack/react-query@\u003e=5.0 react@\u003e=16.8 react-dom@\u003e=16.8\n```\n\nOr if you're using Yarn:\n\n```sh\nyarn add @atproto/api@\u003e=0.10 @atproto/oauth-client-node@\u003e=0.2 @tanstack/react-query@\u003e=5.0 react@\u003e=16.8 react-dom@\u003e=16.8\n```\n\n## How to use\n\n### Setup\n\n#### App Router\n\nFirst, wrap your app with the `BlueskyProvider` and configure it with your Bluesky credentials:\n\n```tsx\n// app/providers.tsx\n'use client'\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport { BlueskyProvider } from 'use-bluesky'\n\n// Create a client\nconst queryClient = new QueryClient()\n\nexport function Providers({ children }: { children: React.ReactNode }) {\n  return (\n    \u003cQueryClientProvider client={queryClient}\u003e\n      \u003cBlueskyProvider\n        baseUrl=\"https://public.api.bsky.app\" // Optional: defaults to this URL\n        token=\"your-bluesky-token\" // Optional: for authenticated requests\n        queryClient={queryClient} // Optional: pass your own QueryClient instance\n      \u003e\n        {children}\n      \u003c/BlueskyProvider\u003e\n    \u003c/QueryClintProvider\u003e\n  )\n}\n```\n\nThen, add the provider to your root layout:\n\n```tsx\n// app/layout.tsx\nimport { Providers } from './providers'\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode\n}) {\n  return (\n    \u003chtml lang=\"en\"\u003e\n      \u003cbody\u003e\n        \u003cProviders\u003e{children}\u003c/Providers\u003e\n      \u003c/body\u003e\n    \u003c/html\u003e\n  )\n}\n```\n\n#### Pages Router\n\nFor Next.js Pages Router, you can set up the providers in your `_app.tsx`:\n\n```tsx\n// pages/_app.tsx\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport type { AppProps } from 'next/app'\nimport { BlueskyProvider } from 'use-bluesky'\n\n// Create a client\nconst queryClient = new QueryClient()\n\nexport default function App({ Component, pageProps }: AppProps) {\n  return (\n    \u003cQueryClientProvider client={queryClient}\u003e\n      \u003cBlueskyProvider\n        baseUrl=\"https://public.api.bsky.app\" // Optional: defaults to this URL\n        queryClient={queryClient} // Optional: pass your own QueryClient instance\n        token=\"your-bluesky-token\" // Optional: for authenticated requests\n      \u003e\n        \u003cComponent {...pageProps} /\u003e\n      \u003c/BlueskyProvider\u003e\n    \u003c/QueryClientProvider\u003e\n  )\n}\n```\n\n### Available Hooks\n\n#### useProfile\n\nFetch a user's profile information:\n\n```tsx\n'use client'\n\nimport { useProfile } from 'use-bluesky'\n\nexport default function ProfilePage({ handle }: { handle: string }) {\n  const { data, isLoading, error } = useProfile({\n    actor: handle,\n  })\n\n  if (isLoading) return \u003cdiv\u003eLoading...\u003c/div\u003e\n  if (error) return \u003cdiv\u003eError loading profile\u003c/div\u003e\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003e{data.displayName}\u003c/h1\u003e\n      \u003cp\u003e{data.description}\u003c/p\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n#### useFollow\n\n\u003e _Note:_ In order to use this hook you need to have an authenticated Bluesky account that triggers the action. In order to support that, you need to proxy the request through your own API (`baseUrl` on `BlueskyProvider`) that applies the appropriate credentials to the request to the Bluesky API.\n\nFollow or unfollow a user:\n\n```tsx\n'use client'\n\nimport { useFollow } from 'use-bluesky'\n\nexport default function FollowButton({\n  did,\n  followUri,\n}: {\n  did: string\n  followUri: string\n}) {\n  const { follow, unfollow, isPending } = useFollow({\n    did,\n    followUri,\n    onSuccess: () =\u003e {\n      // Handle successful follow/unfollow\n    },\n  })\n\n  return (\n    \u003cbutton onClick={() =\u003e follow()} disabled={isPending}\u003e\n      Follow\n    \u003c/button\u003e\n  )\n}\n```\n\n#### useFollowers\n\nGet a user's followers:\n\n```tsx\n'use client'\n\nimport { useFollowers } from 'use-bluesky'\n\nexport default function FollowersList({ handle }: { handle: string }) {\n  const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useFollowers(\n    {\n      actor: handle,\n      limit: 50,\n    },\n  )\n\n  return (\n    \u003cdiv\u003e\n      {data?.pages.map((page, i) =\u003e (\n        \u003cdiv key={i}\u003e\n          {page.followers.map((follower) =\u003e (\n            \u003cdiv key={follower.did}\u003e{follower.displayName}\u003c/div\u003e\n          ))}\n        \u003c/div\u003e\n      ))}\n      {hasNextPage \u0026\u0026 (\n        \u003cbutton onClick={() =\u003e fetchNextPage()} disabled={isFetchingNextPage}\u003e\n          Load More\n        \u003c/button\u003e\n      )}\n    \u003c/div\u003e\n  )\n}\n```\n\n#### useSearchActors\n\nSearch for users:\n\n```tsx\n'use client'\n\nimport { useSearchActors } from 'use-bluesky'\n\nexport default function SearchPage() {\n  const [searchTerm, setSearchTerm] = useState('')\n  const { data, isLoading } = useSearchActors({\n    search: searchTerm,\n    limit: 20,\n  })\n\n  return (\n    \u003cdiv\u003e\n      \u003cinput\n        type=\"text\"\n        value={searchTerm}\n        onChange={(e) =\u003e setSearchTerm(e.target.value)}\n        placeholder=\"Search users...\"\n      /\u003e\n      {isLoading ? (\n        \u003cdiv\u003eLoading...\u003c/div\u003e\n      ) : (\n        \u003cdiv\u003e\n          {data?.actors.map((actor) =\u003e (\n            \u003cdiv key={actor.did}\u003e{actor.displayName}\u003c/div\u003e\n          ))}\n        \u003c/div\u003e\n      )}\n    \u003c/div\u003e\n  )\n}\n```\n\n### Additional Hooks\n\nThe library also provides these additional hooks:\n\n- `useFollows`: Get users that a profile follows\n- `useList`: Get a list of users\n- `useStarterPack`: Get a starter pack\n- `useActorStarterPacks`: Get starter packs for an actor\n\nEach hook is fully typed and integrates with React Query for efficient data fetching and caching.\n\n## License\n\n[MIT](LICENSE) © [Ryan Hefner](https://www.ryanhefner.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryanhefner%2Fuse-bluesky","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fryanhefner%2Fuse-bluesky","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryanhefner%2Fuse-bluesky/lists"}