# Bluesky User Posts API. Posts and reposts, page by page.

Posts and reposts with exact counts. We handle the proxies, blocks and platform changes.

[Get API key](https://socialtap.dev/signup/?next=%2Fplayground%2F%3Fendpoint%3Dbluesky.posts)

## Bluesky User Posts API at a glance

Returns a public Bluesky account's posts and reposts from its handle, DID or profile link, as the tabs of its profile list them. Ask for its replies too, or only posts with media or video. Each post has its link, publish time, full text with hashtags, mentions and full link URLs, images and video, link card, quote and reply, the pin, and exact like, reply, repost, quote and bookmark counts. A repost also says who reposted it and when.

GET `/v1/bluesky/posts`

[Read the API reference](https://socialtap.dev/docs/reference/bluesky/posts/index.md)

- **1 credit** per page, $0.75–$1.97 per 1,000 pages
- **22 typed fields** null when unknown
- **100** posts and reposts per page, most recent activity first: a post by when it was posted, a repost by when it was reposted
- **`handle`** is all it needs, e.g. `espn.com`

## Send one request. Get up to 100 posts and reposts back.

Copy the request in your language, or hand it to your agent. Sign up for an API key and your first 100 credits are free.

`$ npm install socialtap`

`handle = espn.com`

[Open in playground](https://socialtap.dev/playground/?endpoint=bluesky.posts)

cURL:

```shell
curl 'https://socialtap.dev/v1/bluesky/posts?handle=espn.com' \
  -H "x-api-key: $SOCIALTAP_API_KEY"
```

TypeScript SDK:

```typescript
import { SocialTap } from "socialtap";

const client = new SocialTap(); // apiKey defaults to process.env.SOCIALTAP_API_KEY

const res = await client.bluesky.posts.list({ handle: "espn.com" });
console.log(res.data);
console.log(res.credits.charged, res.meta.request_id);
```

Node.js (fetch):

```javascript
const params = new URLSearchParams({
  handle: "espn.com",
});
const res = await fetch(`https://socialtap.dev/v1/bluesky/posts?${params}`, {
  headers: { "x-api-key": process.env.SOCIALTAP_API_KEY ?? "" },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const { data, page, meta } = body;
console.log(data, meta.credits_charged);
```

Python (requests):

```python
import os

import requests

res = requests.get(
    "https://socialtap.dev/v1/bluesky/posts",
    params={"handle": "espn.com"},
    headers={"x-api-key": os.environ["SOCIALTAP_API_KEY"]},
)
body = res.json()
if not res.ok:
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
data, page, meta = body["data"], body["page"], body["meta"]
print(data, meta["credits_charged"])
```

Go (net/http):

```go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
)

func main() {
	q := url.Values{}
	q.Set("handle", "espn.com")
	req, err := http.NewRequest("GET", "https://socialtap.dev/v1/bluesky/posts?"+q.Encode(), nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("x-api-key", os.Getenv("SOCIALTAP_API_KEY"))
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	var body struct {
		Data  json.RawMessage `json:"data"`
		Page  json.RawMessage `json:"page"`
		Meta  map[string]any  `json:"meta"`
		Error *struct {
			Code    string `json:"code"`
			Message string `json:"message"`
		} `json:"error"`
	}
	if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
		log.Fatal(err)
	}
	if body.Error != nil {
		log.Fatalf("%s: %s", body.Error.Code, body.Error.Message)
	}
	fmt.Println(string(body.Data), body.Meta["credits_charged"])
}
```

200 OK:

```json
{
  "data": [
    {
      "approximate_fields": [],
      "author": {
        "avatar_url": "https://cdn.bsky.app/img/avatar/plain/did:plc:x7d6j54pm22ufehkes6jo4jf/bafkreie4oxawqqsfzvk47ysr3unsnmviedzpylxmwxnpa534to2bzas4ie",
        "display_name": "ESPN",
        "id": "did:plc:x7d6j54pm22ufehkes6jo4jf",
        "is_verified": true,
        "url": "https://bsky.app/profile/espn.com",
        "username": "espn.com"
      },
      "coauthors": [],
      "duration_ms": null,
      "hashtags": [],
      "id": "at://did:plc:x7d6j54pm22ufehkes6jo4jf/app.bsky.feed.post/3muznlkmspz2x",
      "is_nsfw": false,
      "is_pinned": false,
      "is_sponsored": null,
      "language": null,
      "media": [
        {
          "alt_text": null,
          "duration_ms": null,
          "expires_at": null,
          "height": null,
          "thumbnail_url": "https://video.bsky.app/watch/did%3Aplc%3Ax7d6j54pm22ufehkes6jo4jf/bafkreiflqivgi6afl5jv4qnmwzo3ks7jwe2dfurohsjfgafbtd5crw4gaq/thumbnail.jpg",
          "type": "video",
          "url": "https://video.bsky.app/watch/did%3Aplc%3Ax7d6j54pm22ufehkes6jo4jf/bafkreiflqivgi6afl5jv4qnmwzo3ks7jwe2dfurohsjfgafbtd5crw4gaq/playlist.m3u8",
          "width": null
        }
      ],
      "mentions": [],
      "metrics": {
        "comment_count": 15,
        "like_count": 103,
        "quote_count": 7,
        "repost_count": 11,
        "save_count": 0,
        "share_count": null,
        "view_count": null
      },
      "platform": "bluesky",
      "platform_specific": {
        "bluesky": {
          "bridged_from_url": null,
          "cid": "bafyreiceaay7jrgqznvxhttsmizofewx3mj6bwebjtz76nd2wh4hix4fty",
          "created_at": "2026-09-08T18:27:24Z",
          "embedded_record_uri": null,
          "indexed_at": "2026-09-08T18:27:30Z",
          "labels": [],
          "languages": [],
          "link_card": null,
          "links": [],
          "quoted_post": null,
          "quoted_post_id": null,
          "reply_root_post_id": null,
          "reply_to_post_id": null,
          "reposted_at": null,
          "reposted_by": null
        }
      },
      "platform_type": null,
      "published_at": "2026-09-08T18:27:24Z",
      "text": "One more sleep until NFL football is BACK. 🏈",
      "thumbnail_url": "https://video.bsky.app/watch/did%3Aplc%3Ax7d6j54pm22ufehkes6jo4jf/bafkreiflqivgi6afl5jv4qnmwzo3ks7jwe2dfurohsjfgafbtd5crw4gaq/thumbnail.jpg",
      "title": null,
      "type": "video",
      "unknown_fields": [],
      "url": "https://bsky.app/profile/espn.com/post/3muznlkmspz2x"
    },
    {
      "approximate_fields": [],
      "author": {
        "avatar_url": "https://cdn.bsky.app/img/avatar/plain/did:plc:x7d6j54pm22ufehkes6jo4jf/bafkreie4oxawqqsfzvk47ysr3unsnmviedzpylxmwxnpa534to2bzas4ie",
        "display_name": "ESPN",
        "id": "did:plc:x7d6j54pm22ufehkes6jo4jf",
        "is_verified": true,
        "url": "https://bsky.app/profile/espn.com",
        "username": "espn.com"
      },
      "coauthors": [],
      "duration_ms": null,
      "hashtags": [],
      "id": "at://did:plc:x7d6j54pm22ufehkes6jo4jf/app.bsky.feed.post/3mpglmolczz2w",
      "is_nsfw": false,
      "is_pinned": false,
      "is_sponsored": null,
      "language": null,
      "media": [],
      "mentions": [],
      "metrics": {
        "comment_count": 17,
        "like_count": 139,
        "quote_count": 16,
        "repost_count": 34,
        "save_count": 1,
        "share_count": null,
        "view_count": null
      },
      "platform": "bluesky",
      "platform_specific": {
        "bluesky": {
          "bridged_from_url": null,
          "cid": "bafyreid2eoctnshw7unb5ozrjqsy63kpqmwwvhj2xuxsfo4z5zucfazqum",
          "created_at": "2026-06-29T13:25:44Z",
          "embedded_record_uri": null,
          "indexed_at": "2026-06-29T13:25:45Z",
          "labels": [],
          "languages": [],
          "link_card": {
            "description": "Former Titans and Cardinals running back Chris Johnson told \"Good Morning America\" that he was diagnosed with ALS in 2025.",
            "thumbnail_url": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:x7d6j54pm22ufehkes6jo4jf/bafkreicgzhnme4wgvolagtic3dki5icwfkmlxz23cmakg2mj2h4xkwvg2q",
            "title": "Former NFL RB Chris Johnson discusses ALS diagnosis",
            "url": "http://spr.ly/63329BDvG6W"
          },
          "links": [],
          "quoted_post": null,
          "quoted_post_id": null,
          "reply_root_post_id": null,
          "reply_to_post_id": null,
          "reposted_at": null,
          "reposted_by": null
        }
      },
      "platform_type": null,
      "published_at": "2026-06-29T13:25:44Z",
      "text": "Former Tennessee Titans and Arizona Cardinals running back Chris Johnson revealed that he has been diagnosed with ALS in an interview with ABC's \"Good Morning America\".\n\nJohnson, 39, told GMA co-anchor Michael Strahan that he was diagnosed with the disease in 2025.",
      "thumbnail_url": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:x7d6j54pm22ufehkes6jo4jf/bafkreicgzhnme4wgvolagtic3dki5icwfkmlxz23cmakg2mj2h4xkwvg2q",
      "title": null,
      "type": "link",
      "unknown_fields": [],
      "url": "https://bsky.app/profile/espn.com/post/3mpglmolczz2w"
    }
  ],
  "page": {
    "has_more": true,
    "next_cursor": "c1.EXAMPLE_CURSOR",
    "next_cursor_expires_at": "2026-10-26T12:00:00Z",
    "end_reason": null
  },
  "meta": {
    "request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
    "platform": "bluesky",
    "source": "api",
    "is_cached": false,
    "credits_charged": 1,
    "latency_ms": 449,
    "fetched_at": "2026-10-25T12:00:00Z",
    "input": {
      "kind": "profile",
      "id": "did:plc:x7d6j54pm22ufehkes6jo4jf",
      "url": "https://bsky.app/profile/espn.com"
    },
    "credits_remaining": 9999,
    "client_request_id": null,
    "warnings": []
  }
}
```

## One schema on 21 platforms.

The [response reference](https://socialtap.dev/docs/reference/bluesky/posts/index.md#response) lists every field, its type and when it is `null`. [See the full schema](https://socialtap.dev/resources/post/index.md).

- ### Null means unknown

  A field Bluesky doesn't show is null, never zero or an empty string, so a real zero always means zero.
- ### What it accepts

  The Bluesky account: its handle, with or without the @ (alice.bsky.social, espn.com), its DID (did:plc:z72i7hdynmk6r22z27h6tvur, did:web:didweb.watch), which is the id every answer gives, or a link to its profile.
- ### Write one parser

  Bluesky, TikTok, Instagram and 18 more platforms answer in these fields, so the code that reads one reads them all.

- **`platform`string**: Platform ID (tiktok, youtube, …).
- **`id`string**: Platform-native post ID (string; Instagram shortcode, Reddit with its t3_ prefix).
- **`url`string**: Canonical post URL.
- **`type`string**: Normalized content shape. New values may be added; treat unknown values as other.
- **`platform_type`string**: The platform's own product label, lowercase (reel, short, story, live, tweet, …).
- **`title`string**: Headline (YouTube title, Reddit title); null on caption-only platforms.
- **`text`string**: Caption, description or body as plain text.
- **`language`string**: BCP-47 language of text, when the platform states it.

Live data from 33 platforms.

[TikTok](https://socialtap.dev/apis/tiktok/index.md) · [Instagram](https://socialtap.dev/apis/instagram/index.md) · [Facebook](https://socialtap.dev/apis/facebook/index.md) · [YouTube](https://socialtap.dev/apis/youtube/index.md) · [Reddit](https://socialtap.dev/apis/reddit/index.md) · [Threads](https://socialtap.dev/apis/threads/index.md) · [Spotify](https://socialtap.dev/apis/spotify/index.md) · [Amazon](https://socialtap.dev/apis/amazon/index.md) · [Apple Music](https://socialtap.dev/apis/applemusic/index.md) · [Pinterest](https://socialtap.dev/apis/pinterest/index.md) · [Rumble](https://socialtap.dev/apis/rumble/index.md) · [X](https://socialtap.dev/apis/x/index.md) · [Bluesky](https://socialtap.dev/apis/bluesky/index.md) · [Twitch](https://socialtap.dev/apis/twitch/index.md) · [LinkedIn](https://socialtap.dev/apis/linkedin/index.md) · [Telegram](https://socialtap.dev/apis/telegram/index.md) · [TikTok Shop](https://socialtap.dev/apis/tiktokshop/index.md) · [Kwai](https://socialtap.dev/apis/kwai/index.md) · [Snapchat](https://socialtap.dev/apis/snapchat/index.md) · [SoundCloud](https://socialtap.dev/apis/soundcloud/index.md) · [Truth Social](https://socialtap.dev/apis/truthsocial/index.md) · [Kick](https://socialtap.dev/apis/kick/index.md) · [Komi](https://socialtap.dev/apis/komi/index.md) · [Lnk.Bio](https://socialtap.dev/apis/linkbio/index.md) · [Linkme](https://socialtap.dev/apis/linkme/index.md) · [Linktree](https://socialtap.dev/apis/linktree/index.md) · [Pillar](https://socialtap.dev/apis/pillar/index.md) · [TikTok Ad Library](https://socialtap.dev/apis/tiktok-ad-library/index.md) · [Facebook Ad Library](https://socialtap.dev/apis/facebook-ad-library/index.md) · [Facebook Events](https://socialtap.dev/apis/facebook-events/index.md) · [Facebook Marketplace](https://socialtap.dev/apis/facebook-marketplace/index.md) · [Google Ads Transparency Center](https://socialtap.dev/apis/google-ads-transparency/index.md) · [LinkedIn Ad Library](https://socialtap.dev/apis/linkedin-ad-library/index.md)

## What teams build with the Bluesky User Posts API.

- ### Monitor an account for new posts
- ### Export an account's post history
- ### Compare engagement across an account's posts
- ### Collect an account's images and video

## Good to know before you build.

- The default tab shows what the app's Posts tab shows, without replies to other accounts. Set tab=replies for those too.
- The list goes by each item's latest activity: a post by when it was posted, a repost by when it was reposted, so a repost of an older post sits among recent items. published_at stays the post's own, and platform_specific.bluesky.reposted_by and reposted_at say who reposted it and when.
- The pinned post comes first on the posts and replies tabs, and isn't repeated where it was posted. The media and video tabs show it only where it was posted.
- An account that chose to be seen only by signed-in people returns private_or_unavailable, as the app answers a logged-out visitor.
- A post of such an account that this one reposted is left out, so a page can hold fewer posts than its limit, or none, and still have a next_cursor.
- If Bluesky's AppView (its main API) is down, the posts and replies tabs are read from the account's own repository instead. Counts, the author's badge and is_nsfw are then null, url names the author by DID, reposts aren't listed, and a partial_data warning says so. The media and video tabs then fail.

## 1 credit per page. Failed requests are free.

Buy credits once and spend them on any endpoint, on any platform.

[Plans and packs](https://socialtap.dev/pricing/index.md) · [How this endpoint is priced](https://socialtap.dev/docs/reference/bluesky/posts/index.md#pricing) · [How credits work](https://socialtap.dev/docs/credits/index.md)

| Source | Price per successful page | Per 1,000 pages |
| --- | --- | --- |
| Platform API `api` | 1 credit | $0.75–$1.97 |

- Cache hits are free.
- Credits from packs and top-ups never expire.
- A monthly plan's credits are spent first, and what is left of them ends at each renewal.
- Prices exclude tax: sales tax is added at checkout where it applies.
- Outside the US, plans and packs are sold to businesses: checkout asks for your VAT, GST or other business tax ID.

## Questions about the Bluesky User Posts API.

More in the [API reference](https://socialtap.dev/docs/reference/bluesky/posts/index.md).

**How much does the Bluesky User Posts API cost?**

A page of up to 100 posts and reposts costs 1 credit. Every successful page is charged, empty pages included. SocialTap credits cost $0.75–$1.97 per 1,000, depending on the plan or pack.

**How do I get the next page?**

Repeat the same request with cursor set to page.next_cursor from the previous response, keeping the other parameters. When page.has_more is false there are no more pages. Cursors expire after 24 hours.

Other platforms

## Posts on 20 more platforms.

- [TikTok Posts API](https://socialtap.dev/apis/tiktok/posts/index.md) (1 credit / page · `GET /v1/tiktok/posts`)
- [Instagram Posts API](https://socialtap.dev/apis/instagram/posts/index.md) (1 credit / page · `GET /v1/instagram/posts`)
- [Facebook Profile Posts API](https://socialtap.dev/apis/facebook/posts/index.md) (1 credit / page · `GET /v1/facebook/posts`)
- [YouTube Channel Videos API](https://socialtap.dev/apis/youtube/posts/index.md) (1 credit / page · `GET /v1/youtube/posts`)
- [Reddit User Posts API](https://socialtap.dev/apis/reddit/posts/index.md) (1 credit / page · `GET /v1/reddit/posts`)
- [Threads Posts API](https://socialtap.dev/apis/threads/posts/index.md) (1 credit / page · `GET /v1/threads/posts`)
- [Spotify Track API](https://socialtap.dev/apis/spotify/track/index.md) (1 credit · `GET /v1/spotify/track`)
- [Amazon Shop Posts API](https://socialtap.dev/apis/amazon/shop_posts/index.md) (1 credit / page · `GET /v1/amazon/shop_posts`)
- [Apple Music Track API](https://socialtap.dev/apis/applemusic/track/index.md) (1 credit · `GET /v1/applemusic/track`)
- [Pinterest Pin API](https://socialtap.dev/apis/pinterest/pin/index.md) (1 credit · `GET /v1/pinterest/pin`)
- [Rumble Channel Videos API](https://socialtap.dev/apis/rumble/posts/index.md) (1 credit / page · `GET /v1/rumble/posts`)
- [X (Twitter) Post API](https://socialtap.dev/apis/x/post/index.md) (1 credit · `GET /v1/x/post`)
- [Twitch Video and Clip API](https://socialtap.dev/apis/twitch/video/index.md) (1 credit · `GET /v1/twitch/video`)
- [LinkedIn Post API](https://socialtap.dev/apis/linkedin/post/index.md) (1 credit · `GET /v1/linkedin/post`)
- [Telegram Post API](https://socialtap.dev/apis/telegram/post/index.md) (1 credit · `GET /v1/telegram/post`)
- [Kwai User Posts API](https://socialtap.dev/apis/kwai/posts/index.md) (1 credit / page · `GET /v1/kwai/posts`)
- [Snapchat Spotlight API](https://socialtap.dev/apis/snapchat/spotlight/index.md) (1 credit · `GET /v1/snapchat/spotlight`)
- [SoundCloud Track API](https://socialtap.dev/apis/soundcloud/track/index.md) (1 credit · `GET /v1/soundcloud/track`)
- [Truth Social Posts API](https://socialtap.dev/apis/truthsocial/posts/index.md) (1 credit / page · `GET /v1/truthsocial/posts`)
- [Kick Clip API](https://socialtap.dev/apis/kick/post/index.md) (1 credit · `GET /v1/kick/post`)

More Bluesky

## Bluesky API. 5 endpoints, one key.

- [Bluesky Post API](https://socialtap.dev/apis/bluesky/post/index.md) (1 credit · `GET /v1/bluesky/post`)
- [Bluesky Post Search API](https://socialtap.dev/apis/bluesky/search_posts/index.md) (1 credit / page · `GET /v1/bluesky/search_posts`)
- [Bluesky Profile API](https://socialtap.dev/apis/bluesky/profile/index.md) (1 credit · `GET /v1/bluesky/profile`)
- [Bluesky Comments API](https://socialtap.dev/apis/bluesky/comments/index.md) (1 credit / page · `GET /v1/bluesky/comments`)

## Try it on an account you know.

Paste its handle or link in the playground, or copy the request into your code.

100free credits

- No credit card
- Failed requests are free
- Works on all 218 endpoints

[Start for free](https://socialtap.dev/signup/) [Read the docs](https://socialtap.dev/docs/index.md)

---

[HTML version](https://socialtap.dev/apis/bluesky/posts/) · [Docs index for AI agents](https://socialtap.dev/llms.txt) · [All docs in one file](https://socialtap.dev/llms-full.txt)
