Back to Blog
General

Instagram Posts Scraper API: Pull Any Profile's Posts in 2026

June 18, 2026
4 min read
S
By SociaVault Team
instagramposts scraperapicontent analysis

Instagram Posts Scraper API: Pull Any Profile's Posts in 2026

If you've tried to get another account's posts out of Instagram's official Graph API, you already know it's a no-go: Graph API only hands you your own posts, after a Business account link and app review. For competitor analysis, influencer vetting, or content research, that's a wall.

This endpoint is the way around it. Give it a public handle, get that profile's posts back as JSON, with captions, likes, comments, views, and media URLs. No OAuth, no review queue.

A quick honesty check before you build: this works on public profiles only (private accounts are off-limits, by design), and if you want stories you'll want the highlights endpoint instead. If those fit, here's everything you can pull.

What you get per post

FieldWhat it is
pk / idUnique post ID
codeShortcode for the URL (instagram.com/p/{code})
caption.textFull caption
like_countLikes
comment_countComments
play_countViews (video/reel posts)
media_type1 = photo, 2 = video, 8 = carousel
video_versionsVideo URLs at various qualities
image_versions2Image URLs at various sizes
taken_atUnix timestamp
usertagsTagged users

One thing worth knowing in 2026: Instagram removed view counts from the single Post/Reel Info endpoint. This posts endpoint is now the reliable place to get a reel's play_count, so if you were leaning on post-info for views, switch your lookups here.

The call

const res = await fetch(
  "https://api.sociavault.com/v1/scrape/instagram/posts?handle=opi",
  { headers: { "x-api-key": process.env.SOCIAVAULT_API_KEY } },
);
const result = await res.json();
const posts = Object.values(result.data.items);

Add trim=true if you want a lighter response without the embedded media CDN payloads.

{
  "success": true,
  "data": {
    "more_available": true,
    "next_max_id": "3822431353875645727_270598518",
    "items": {
      "0": {
        "code": "DUTZgACiaFr",
        "media_type": 2,
        "caption": { "text": "The next generation of icons has arrived. 馃拝" },
        "like_count": 2531,
        "comment_count": 62,
        "play_count": 100404,
        "taken_at": 1770137534
      }
    }
  },
  "credits_used": 1,
  "endpoint": "instagram/posts"
}

Note the items object uses numeric string keys, not an array, so Object.values(result.data.items) is your friend.

What people actually build with it

Competitor content audits. Pull a rival's last few dozen posts, average the engagement, and surface the top performers, the single most common request we see:

const posts = Object.values((await getPosts("competitor")).data.items);
const avgLikes = posts.reduce((s, p) => s + p.like_count, 0) / posts.length;
const top = [...posts].sort((a, b) => b.like_count - a.like_count).slice(0, 10);
console.log(
  "Avg likes:",
  Math.round(avgLikes),
  "Top posts:",
  top.map((p) => p.code),
);

Posting-time analysis. Bucket taken_at by hour to find when an account actually posts:

const byHour = {};
posts.forEach((p) => {
  const h = new Date(p.taken_at * 1000).getHours();
  byHour[h] = (byHour[h] || 0) + 1;
});

Content-mix breakdown. Photos vs videos vs carousels, straight from media_type:

const TYPES = { 1: "photo", 2: "video", 8: "carousel" };
const mix = posts.reduce((a, p) => {
  const t = TYPES[p.media_type] || "other";
  a[t] = (a[t] || 0) + 1;
  return a;
}, {});

Influencer vetting. Engagement rate from real posts beats a follower count every time. Pull the last 30 posts, compute likes-plus-comments over followers, and you have a defensible number to judge a creator on.

Getting a full post history

Each call returns ~12 posts. Page with next_max_id:

async function getAllPosts(handle) {
  let all = [],
    nextMaxId = null;
  do {
    const url = new URL("https://api.sociavault.com/v1/scrape/instagram/posts");
    url.searchParams.set("handle", handle);
    if (nextMaxId) url.searchParams.set("next_max_id", nextMaxId);
    const result = await (
      await fetch(url, {
        headers: { "x-api-key": process.env.SOCIAVAULT_API_KEY },
      })
    ).json();
    all.push(...Object.values(result.data.items));
    nextMaxId = result.data.more_available ? result.data.next_max_id : null;
  } while (nextMaxId);
  return all;
}

Each page costs 1 credit, so deep histories on big accounts add up, cache what you pull.

FAQ

Private accounts? No. Public only. Do I get the actual files? You get URLs to the media; download them if you need the bytes. How far back? A profile's full public history. Stories? Not here, those are ephemeral. Use highlights for saved story content.

Start pulling posts

Create an account for 50 free credits (no card), grab your sk_live_... key, and run the snippet above. Full reference in the Instagram Posts API docs.


Related: Instagram Profile Scraper 路 Instagram Reels API 路 Post/Reel Info 路 Scrape Instagram comments

Found this helpful?

Share it with others who might benefit

Ready to Try SociaVault?

Start extracting social media data with our powerful API. No credit card required.