100 free credits. No credit card required.Start building
Logo
Prism logo
100 free credits. No credit card required

Prism Profiles API

Returns a profile for each platform and handle pair you send, in the order you sent them, with a status per row and the same shape as the single profile call.

POST /v1/prism/profiles

Last updated November 2026Maintained by the SocialCrawl team

When to use the Prism Profiles API

Use it to vet many handles at once instead of calling the profile endpoint per handle; creator-card is for one handle across several platforms.

Not for one handle across several platforms (prism/creator-card), or a single profile where its own endpoint is simpler (tiktok/profile, instagram/profile).

From the API reference

Batch profile lookup for handle vetting. POST a JSON body with an items array of 1-50 { platform, handle, custom_id? } objects (handle accepts an @handle, a bare handle, or a pasted profile URL); returns one row per item: the canonical Author object (same shape as the single GET profile endpoint), a status of ok / not_found / unsupported / error / deferred, the caller's custom_id echoed, and the credits that row cost: in input order. Per-item isolation: one dead or private handle never fails the batch. Billing is per item at each platform's own credit tier (most platforms 1 credit; LinkedIn 5); only successful rows are charged, everything else is refunded. Supported platforms: instagram, tiktok, youtube, twitter, threads, twitch, snapchat, truthsocial, bluesky, kwai, reddit, telegram, linkedin (a member, or a company page as a linkedin.com/company/… URL), facebook. A LinkedIn lookup that is rate limited is retried once and then answered deferred at no charge: re-request it. Never cached. Optionally streams Server-Sent Events when the client sends Accept: text/event-stream. Send include: "posts" (up to 25 items) to add each handle's first page of posts beside its profile: every ok row gains a posts block with the same post rows, next_cursor and has_more as that handle's own post list endpoint (endpoint names it: instagram profile/posts, tiktok profile/videos, youtube channel/videos, twitter user/tweets, threads user/posts, facebook profile/posts, reddit profile/posts, telegram profile/posts, linkedin profile/posts or company/posts; other platforms answer posts.status: "unsupported"). since on the body and stop_at_id on an item stop each page at a date or at a post you already hold, as on those endpoints, and posts.stopped_at says which. Add posts_limit (1 to 100) to walk each handle's post list until that many posts are held: posts.pages is the pages charged and posts.stopped says why the walk ended (limit, end, window, page_cap). include: "posts,about" also returns activity (last_post_at, posts_30d, posts_90d, media_mix) and stats (avg_likes, avg_comments, engagement_rate) on every row, computed from the posts held. Add comments to include (it implies posts) to read the comments of each handle's top posts: the comments_top_posts posts (default 3) with the most comments among the posts walked (a post without a comment count is ranked by views after them, or rank all by views with comments_select_by: "views") each gain comments with items (the same comment rows as that platform's comment endpoint: instagram, tiktok and facebook post/comments, youtube video/comments, twitter tweet/replies, linkedin post/comments, reddit post/comments, threads post/comments), total (the post's comment count), truncated and next_cursor, up to comments_per_post (default 20) per post; the row's comments block gives status (ok, partial, failed, deferred, empty, unsupported) and the credits. One post that fails never drops the row. The profile in data is unchanged.

Searching 69 platforms in parallel

·TikTok logoTikTok·Instagram logoInstagram·YouTube logoYouTube·Facebook logoFacebook·X logoX·LinkedIn logoLinkedIn·Reddit logoReddit·Threads logoThreads·Pinterest logoPinterest·Twitch logoTwitch·Truth Social logoTruth Social·Snapchat logoSnapchat·Kick logoKick·Bluesky logoBluesky·Kwai logoKwai·Rumble logoRumble·Spotify logoSpotify·Apple Music logoApple Music·TikTok Shop logoTikTok Shop·Amazon Shop logoAmazon Shop·Google Shopping logoGoogle Shopping·Trustpilot logoTrustpilot·TripAdvisor logoTripAdvisor·Yelp logoYelp·Linktree logoLinktree·Komi logoKomi·Pillar logoPillar·lnk.bio logolnk.bio·Facebook Ads logoFacebook Ads·Google Ads logoGoogle Ads·LinkedIn Ads logoLinkedIn Ads·Google Search logoGoogle Search·Google News logoGoogle News·Finance logoFinance·Polymarket logoPolymarket·Tavily logoTavily·Hacker News logoHacker News·GitHub logoGitHub·Perplexity logoPerplexity·Naver logoNaver·Utility logoUtility·Universal Search logoUniversal Search
·TikTok logoTikTok·Instagram logoInstagram·YouTube logoYouTube·Facebook logoFacebook·X logoX·LinkedIn logoLinkedIn·Reddit logoReddit·Threads logoThreads·Pinterest logoPinterest·Twitch logoTwitch·Truth Social logoTruth Social·Snapchat logoSnapchat·Kick logoKick·Bluesky logoBluesky·Kwai logoKwai·Rumble logoRumble·Spotify logoSpotify·Apple Music logoApple Music·TikTok Shop logoTikTok Shop·Amazon Shop logoAmazon Shop·Google Shopping logoGoogle Shopping·Trustpilot logoTrustpilot·TripAdvisor logoTripAdvisor·Yelp logoYelp·Linktree logoLinktree·Komi logoKomi·Pillar logoPillar·lnk.bio logolnk.bio·Facebook Ads logoFacebook Ads·Google Ads logoGoogle Ads·LinkedIn Ads logoLinkedIn Ads·Google Search logoGoogle Search·Google News logoGoogle News·Finance logoFinance·Polymarket logoPolymarket·Tavily logoTavily·Hacker News logoHacker News·GitHub logoGitHub·Perplexity logoPerplexity·Naver logoNaver·Utility logoUtility·Universal Search logoUniversal Search
·TikTok logoTikTok·Instagram logoInstagram·YouTube logoYouTube·Facebook logoFacebook·X logoX·LinkedIn logoLinkedIn·Reddit logoReddit·Threads logoThreads·Pinterest logoPinterest·Twitch logoTwitch·Truth Social logoTruth Social·Snapchat logoSnapchat·Kick logoKick·Bluesky logoBluesky·Kwai logoKwai·Rumble logoRumble·Spotify logoSpotify·Apple Music logoApple Music·TikTok Shop logoTikTok Shop·Amazon Shop logoAmazon Shop·Google Shopping logoGoogle Shopping·Trustpilot logoTrustpilot·TripAdvisor logoTripAdvisor·Yelp logoYelp·Linktree logoLinktree·Komi logoKomi·Pillar logoPillar·lnk.bio logolnk.bio·Facebook Ads logoFacebook Ads·Google Ads logoGoogle Ads·LinkedIn Ads logoLinkedIn Ads·Google Search logoGoogle Search·Google News logoGoogle News·Finance logoFinance·Polymarket logoPolymarket·Tavily logoTavily·Hacker News logoHacker News·GitHub logoGitHub·Perplexity logoPerplexity·Naver logoNaver·Utility logoUtility·Universal Search logoUniversal Search
·TikTok logoTikTok·Instagram logoInstagram·YouTube logoYouTube·Facebook logoFacebook·X logoX·LinkedIn logoLinkedIn·Reddit logoReddit·Threads logoThreads·Pinterest logoPinterest·Twitch logoTwitch·Truth Social logoTruth Social·Snapchat logoSnapchat·Kick logoKick·Bluesky logoBluesky·Kwai logoKwai·Rumble logoRumble·Spotify logoSpotify·Apple Music logoApple Music·TikTok Shop logoTikTok Shop·Amazon Shop logoAmazon Shop·Google Shopping logoGoogle Shopping·Trustpilot logoTrustpilot·TripAdvisor logoTripAdvisor·Yelp logoYelp·Linktree logoLinktree·Komi logoKomi·Pillar logoPillar·lnk.bio logolnk.bio·Facebook Ads logoFacebook Ads·Google Ads logoGoogle Ads·LinkedIn Ads logoLinkedIn Ads·Google Search logoGoogle Search·Google News logoGoogle News·Finance logoFinance·Polymarket logoPolymarket·Tavily logoTavily·Hacker News logoHacker News·GitHub logoGitHub·Perplexity logoPerplexity·Naver logoNaver·Utility logoUtility·Universal Search logoUniversal Search
Prism API

What can you do with the Profiles API?

The Profiles endpoint gives you structured Prism data with computed fields in a single request. No scraping infrastructure to build or maintain.

Example Request

# POST /v1/prism/profiles: Metered: holds 1 credit per call up front and refunds what the call does not use. Cache hits are free and failed calls are refunded.
# Check the price first for 0 credits: add dry_run=1 to the query. Nothing is fetched or charged.
# --max-time 60: the API's own time limit for this endpoint.
# --retry 3: retries timeouts, 429 and 5xx, honoring Retry-After.
# -o response.json keeps only the final attempt's body.
# One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
IDEMPOTENCY_KEY=$(od -An -N16 -tx1 /dev/urandom | tr -d ' \n')
curl -sS --max-time 60 --retry 3 -o response.json -X POST \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"platform":"tiktok","handle":"@scout2015"},{"platform":"linkedin","handle":"williamhgates","custom_id":"vet-1"}]}' \
  "https://www.socialcrawl.dev/v1/prism/profiles" && cat response.json
# POST /v1/prism/profiles: Metered: holds 1 credit per call up front and refunds what the call does not use. Cache hits are free and failed calls are refunded.
# Check the price first for 0 credits: add dry_run=1 to the query. Nothing is fetched or charged.
import os
import random
import time
import uuid

import requests

API_KEY = os.environ.get("SOCIALCRAWL_API_KEY", "YOUR_API_KEY")
TIMEOUT_S = 60  # the API's own time limit for this endpoint.
MAX_RETRIES = 3
URL = "https://www.socialcrawl.dev/v1/prism/profiles"


def backoff(attempt):
    # Exponential backoff with jitter: about 1 s, 2 s, then 4 s.
    return 2 ** attempt * (0.5 + random.random() / 2)


def socialcrawl(payload):
    # One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
    idempotency_key = str(uuid.uuid4())
    for attempt in range(MAX_RETRIES + 1):
        try:
            res = requests.post(
                URL,
                json=payload,
                headers={"x-api-key": API_KEY, "Idempotency-Key": idempotency_key},
                timeout=TIMEOUT_S,
            )
            body = res.json()
        except (requests.RequestException, ValueError):
            # A timeout, a dropped connection or a non-JSON gateway page: retry with the same key.
            if attempt == MAX_RETRIES:
                raise
            time.sleep(backoff(attempt))
            continue
        if body["success"]:
            return body
        error = body["error"]
        # Branch on error["type"], never on the message text.
        if error["type"] == "RESOURCE_NOT_FOUND":
            return None  # refunded: nothing to read
        retry_after = res.headers.get("Retry-After")
        # SERVICE_UNAVAILABLE without Retry-After is a withdrawn endpoint: permanent.
        permanent = error["type"] == "SERVICE_UNAVAILABLE" and retry_after is None
        if not error.get("retryable") or permanent or attempt == MAX_RETRIES:
            raise RuntimeError(f"{error['type']}: {error['message']} (request_id {body['request_id']})")
        # Retry-After (seconds) wins; otherwise back off.
        time.sleep(float(retry_after) if retry_after else backoff(attempt))


payload = {
    "items": [{"platform": "tiktok", "handle": "@scout2015"}, {"platform": "linkedin", "handle": "williamhgates", "custom_id": "vet-1"}],
}
body = socialcrawl(payload)
if body is not None:
    print(body["data"])
// POST /v1/prism/profiles: Metered: holds 1 credit per call up front and refunds what the call does not use. Cache hits are free and failed calls are refunded.
// Check the price first for 0 credits: add dry_run=1 to the query. Nothing is fetched or charged.
const API_KEY = process.env.SOCIALCRAWL_API_KEY ?? "YOUR_API_KEY";
const TIMEOUT_MS = 60_000; // the API's own time limit for this endpoint.
const MAX_RETRIES = 3;

type Page = { next_cursor: string | null; has_more: boolean };
type SocialCrawlResponse =
  | { success: true; data: any; pagination?: Page; credits_used: number; request_id: string }
  | { success: false; error: { type: string; message: string; retryable: boolean }; request_id: string };

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
// Exponential backoff with jitter: about 1 s, 2 s, then 4 s.
const backoffMs = (attempt: number) => 2 ** attempt * 1000 * (0.5 + Math.random() / 2);

async function socialcrawl(url: string, payload: Record<string, unknown>) {
  // One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
  const idempotencyKey = crypto.randomUUID();
  for (let attempt = 0; ; attempt++) {
    let res: Response;
    let body: SocialCrawlResponse;
    try {
      res = await fetch(url, {
        method: "POST",
        headers: {
          "x-api-key": API_KEY,
          "Content-Type": "application/json",
          "Idempotency-Key": idempotencyKey,
        },
        body: JSON.stringify(payload),
        signal: AbortSignal.timeout(TIMEOUT_MS),
      });
      body = (await res.json()) as SocialCrawlResponse;
    } catch (error) {
      // A timeout, a dropped connection or a non-JSON gateway page: retry with the same key.
      if (attempt >= MAX_RETRIES) throw error;
      await sleep(backoffMs(attempt));
      continue;
    }
    if (body.success) return body;
    // Branch on error.type, never on the message text.
    if (body.error.type === "RESOURCE_NOT_FOUND") return null; // refunded: nothing to read
    const retryAfter = res.headers.get("Retry-After");
    // SERVICE_UNAVAILABLE without Retry-After is a withdrawn endpoint: permanent.
    const permanent = body.error.type === "SERVICE_UNAVAILABLE" && retryAfter === null;
    if (!body.error.retryable || permanent || attempt >= MAX_RETRIES) {
      throw new Error(`${body.error.type}: ${body.error.message} (request_id ${body.request_id})`);
    }
    // Retry-After (seconds) wins; otherwise back off.
    await sleep(retryAfter ? Number(retryAfter) * 1000 : backoffMs(attempt));
  }
}

const body = await socialcrawl("https://www.socialcrawl.dev/v1/prism/profiles", {
  items: [{ platform: "tiktok", handle: "@scout2015" }, { platform: "linkedin", handle: "williamhgates", custom_id: "vet-1" }],
});
if (body) console.log(body.data);

Parameters

ParameterRequiredDescription
itemsYesJSON array of 1-50 items (1-25 with include: "posts"). Each item is `{ "platform": "tiktok", "handle": "@scout2015", "custom_id"?: "…", "stop_at_id"?: "…" }`. `handle` accepts an @handle, a bare handle, or a pasted profile URL. `stop_at_id` (only with include: "posts") is the id or URL of the newest post you already hold for that handle: its page stops just before it.
includeNoOptional. A comma-separated set of "posts" and "about". "posts" adds the handle's first page of posts to every ok row (`posts`), for the price of that page (1 credit), charged only when the page came back with posts. Caps the batch at 25 items. "about" reads an Instagram handle through its About panel (same price) and adds `country` to a row when the account declares one (an Instagram country, a Facebook page address, a TikTok account region, or a YouTube channel country), as an ISO code with its `source`; beside "posts" it also adds `activity` and `stats`, computed from the posts held. "comments" implies "posts" and reads the comments of each handle's top posts (see comments_top_posts), priced per page at that platform's comment endpoint price.
sinceNoOptional, with include: "posts". Only posts published on or after this date (YYYY-MM-DD or an ISO 8601 timestamp); each page stops at the first older post and `posts.stopped_at` is `since`.
posts_limitNoOptional, with include: "posts". An integer from 1 to 100: walk each handle's post list until that many posts are held (each page that came back with posts is charged, up to 10 pages per handle). Without it, one page.
comments_top_postsNoOptional, with include: "comments". An integer from 1 to 50 (default 3): how many of each handle's walked posts, those with the most comments, get their comments read.
comments_per_postNoOptional, with include: "comments". An integer from 1 to 200 (default 20): the most comments read per selected post, walked page by page on that platform's comment endpoint.
comments_select_byNoOptional, with include: "comments". "comments" (default) picks the posts with the most comments, then posts without a comment count by views; "views" picks the most viewed posts. (comments | views)
Example Response

What does the Prism Profiles API return?

Every response follows one unified schema. Here is a real, unmodified response body, so you can see the exact fields you get back before spending a credit.

Example response
{
  "success": true,
  "platform": "instagram",
  "endpoint": "/v1/instagram/engagement",
  "data": {
    "engagement_rate_percentages": 38.33,
    "recent_posts": 12,
    "followers": 87608035,
    "comments": 528912,
    "likes": 33049046,
    "recent_posts_explanation": "Statistics based on the last 12 posts",
    "id_user": "2278169415",
    "username": "mrbeast",
    "is_private": false,
    "posts_details": [
      {
        "likes": 5636982,
        "comments": 69484,
        "taken_at": 1781457954,
        "datetime": "2026-06-14 20:25:54",
        "hours_since_post": 461,
        "time_ago": "19 days ago",
        "likes_per_hour": 12228,
        "comments_per_hour": 151
      },
      {
        "likes": 20000768,
        "comments": 223510,
        "taken_at": 1732824650,
        "datetime": "2024-11-28 23:10:50",
        "hours_since_post": 13971,
        "time_ago": "2 years ago",
        "likes_per_hour": 1432,
        "comments_per_hour": 16
      },
      {
        "likes": 929226,
        "comments": 30633,
        "taken_at": 1782232475,
        "datetime": "2026-06-23 19:34:35",
        "hours_since_post": 246,
        "time_ago": "10 days ago",
        "likes_per_hour": 3777,
        "comments_per_hour": 125
      },
      {
        "likes": 487761,
        "comments": 22482,
        "taken_at": 1781799425,
        "datetime": "2026-06-18 19:17:05",
        "hours_since_post": 366,
        "time_ago": "15 days ago",
        "likes_per_hour": 1333,
        "comments_per_hour": 61
      },
      {
        "likes": 712265,
        "comments": 15716,
        "taken_at": 1781366405,
        "datetime": "2026-06-13 19:00:05",
        "hours_since_post": 487,
        "time_ago": "20 days ago",
        "likes_per_hour": 1463,
        "comments_per_hour": 32
      },
      {
        "likes": 1475116,
        "comments": 35386,
        "taken_at": 1781277094,
        "datetime": "2026-06-12 18:11:34",
        "hours_since_post": 512,
        "time_ago": "21 days ago",
        "likes_per_hour": 2881,
        "comments_per_hour": 69
      },
      {
        "likes": 1108220,
        "comments": 26632,
        "taken_at": 1780160249,
        "datetime": "2026-05-30 19:57:29",
        "hours_since_post": 822,
        "time_ago": "1 months ago",
        "likes_per_hour": 1348,
        "comments_per_hour": 32
      },
      {
        "likes": 542948,
        "comments": 28476,
        "taken_at": 1779375582,
        "datetime": "2026-05-21 17:59:42",
        "hours_since_post": 1040,
        "time_ago": "1 months ago",
        "likes_per_hour": 522,
        "comments_per_hour": 27
      },
      {
        "likes": 698514,
        "comments": 24401,
        "taken_at": 1779120014,
        "datetime": "2026-05-18 19:00:14",
        "hours_since_post": 1111,
        "time_ago": "2 months ago",
        "likes_per_hour": 629,
        "comments_per_hour": 22
      },
      {
        "likes": 468000,
        "comments": 13548,
        "taken_at": 1778947209,
        "datetime": "2026-05-16 19:00:09",
        "hours_since_post": 1159,
        "time_ago": "2 months ago",
        "likes_per_hour": 404,
        "comments_per_hour": 12
      },
      {
        "likes": 526594,
        "comments": 24411,
        "taken_at": 1777737719,
        "datetime": "2026-05-02 19:01:59",
        "hours_since_post": 1495,
        "time_ago": "2 months ago",
        "likes_per_hour": 352,
        "comments_per_hour": 16
      },
      {
        "likes": 462652,
        "comments": 14233,
        "taken_at": 1777580305,
        "datetime": "2026-04-30 23:18:25",
        "hours_since_post": 1538,
        "time_ago": "2 months ago",
        "likes_per_hour": 301,
        "comments_per_hour": 9
      }
    ]
  },
  "credits_used": 5,
  "credits_remaining": 9999,
  "request_id": "req-8Kq2ZmR4vT9xLb3P",
  "cached": false,
  "redacted": true
}

Example captured from the Instagram API. Every SocialCrawl endpoint returns this same unified schema, so your Prism Profiles response has the same fields.

API Details

How does the Prism Profiles API work?

Send a GET request with your API key and get back clean, structured JSON in our unified schema. Supported computed fields are populated when the source provides the required inputs.

Method

POST

Response

JSON

Why SocialCrawl

Why use SocialCrawl for Prism Profiles data?

We handle the complexity of Prism data extraction so you can focus on building. Unified schema, AI enrichment, and zero platform logic in your code.

Developer First

How do you scrape social media data in seconds?

The fastest social media scraping API for developers. Scrape profiles, posts, comments, and analytics from 69 platforms covering 10B+ monthly active users.

One schema, every platform

Query 69 platforms with identical response structures. Write your integration once.

Computed fields, not just scraped

When an endpoint supports these metrics and the source provides the required inputs, the normalized record includes engagement_rate, estimated_reach, content_category, and language. Ready to use.

See your data before you code

Visual Data Explorer. Paste any URL, get rich result cards, sortable tables, CSV export.

import requests

response = requests.get(
    'https://www.socialcrawl.dev/v1/tiktok/profile',
    params={'handle': 'charlidamelio'},
    headers={'x-api-key': 'sc_YOUR_API_KEY'}
)
data = response.json()
[ .JSON ]
{
  "success": true,
  "platform": "tiktok",
  "data": {
    "author": {
      "username": "charlidamelio",
      "followers": 152400000
    },
    "engagement": {
      "likes": 12400000000,
      "engagement_rate": 0.087
    },
    "metadata": {
      "language": "en",
      "content_category": "lifestyle"
    }
  }
}
+ 69 platforms
FAQ

Have a question? We got answers

Find answers to frequently asked questions about SocialCrawl's API, pricing, and capabilities.

Contact us
What does the Prism Profiles API return?
Returns a profile for each platform and handle pair you send, in the order you sent them, with a status per row and the same shape as the single profile call. The response uses the same JSON envelope as every SocialCrawl endpoint, with the data, credits_used and request_id fields.
When should I use the Prism Profiles endpoint?
Use it to vet many handles at once instead of calling the profile endpoint per handle; creator-card is for one handle across several platforms. Not for one handle across several platforms (prism/creator-card), or a single profile where its own endpoint is simpler (tiktok/profile, instagram/profile).
How much does the Prism Profiles API cost?
The price depends on the request, from 1 to 126375 credits per call. Every new account gets 100 free credits. Credits for failed or empty calls are refunded automatically, and there is no subscription.
What parameters does the Prism Profiles API need?
The one required parameter is items (jSON array of 1-50 items). It also accepts 6 optional parameters, all listed on this page.
How do I call the Prism Profiles API?
Send a POST request to https://www.socialcrawl.dev/v1/prism/profiles with a JSON body and your API key in the x-api-key header. An Authorization: Bearer header works too.

Ask AI about SocialCrawl

Ready to scrape Prism Profiles data?

Get your API key and start pulling Prism data in under 60 seconds.

Start for free

🤖 AI agent or LLM? Read this page as markdown