Instagram Profile Posts & Reels Scraper avatar

Instagram Profile Posts & Reels Scraper

Pricing

from $0.60 / 1,000 content results

Go to Apify Store
Instagram Profile Posts & Reels Scraper

Instagram Profile Posts & Reels Scraper

Collect posts and Reels from one or more Instagram profiles, with up to 1,000 items per profile. Use postedAfter to fetch only newly published content and stop paginating early, so scheduled runs pay the lower filter rate for old items instead of the full result rate.

Pricing

from $0.60 / 1,000 content results

Rating

0.0

(0)

Developer

LanceAPI

LanceAPI

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 hours ago

Last modified

Categories

Share

Instagram Posts & Reels Scraper

Fetch posts and Reels from Instagram profiles. Use postedAfter to retrieve only newly published content, so your Dataset and your result fees stay focused on what is new.

This Actor collects public posts and Reels from one or more Instagram profiles and writes one clean, structured row per item. Paste usernames, profile URLs or numeric user IDs, choose what you want, and — when you only care about what is new — set a cutoff date so pagination stops as soon as the feed moves past it. It is built for content collection and new-content monitoring, not for profile analytics.

  • Posts and Reels in one pass — photos, carousels, feed videos and Reels come back from the profile feed, or ask for posts only / Reels only.
  • postedAfter incremental monitoring — only content published strictly after your cutoff is returned, and pagination stops early once the feed is older than that moment, so a scheduled run does not re-collect and re-pay full result fees for content you already have.
  • Zero new posts is a normal, successful result — not an error, and not a reason to retry the same profile against every data source.
  • Up to 1,000 items per profile, 200 profiles per run — with input normalization and de-duplication built in.
  • Pay per delivered item, plus a small per-item fee when the date filter runs — result fees follow the unique posts and Reels actually written to your Dataset, never the pages or requests behind them; when postedAfter is set, the items it examines and removes are charged at a lower filter rate.

✨ Key features

1. One profile, many content rows

Every unique post or Reel is delivered as its own Dataset row, linked back to the profile it came from through sourceUsername, sourceProfileUrl and sourceProfileId. Photos, carousels, feed videos and Reels are all first-class rows, with type telling them apart (photo, carousel, video, reel).

Because each item is its own row, filtering, joining against your own tables, and exporting stay simple — you never have to unpack a nested list to get at a single post.

2. postedAfter: real incremental scraping, not a local filter

Set postedAfter to a calendar date, an ISO-8601 moment, or a relative value such as 7 days, and only content published strictly after it is returned. The filter is applied inside the pagination pipeline, page by page:

  • each page is normalized and filtered as it arrives;
  • once the feed has moved past your cutoff, pagination stops instead of continuing to pull older pages you would throw away;
  • pinned posts are excluded from the stop decision, so a pinned old item at the top of a feed can never hide newer content;
  • an item with no usable timestamp is not delivered and not guessed — it cannot be proven to be newer than your cutoff.

For scheduled monitoring this is the difference between "collect what is new" and "download the whole feed again": old items are examined, removed and charged at the lower filter rate, while only genuinely new items reach your Dataset at the full result rate. A run that finds nothing new still succeeds — no content rows, no result fees, just the filter fee for the items it checked.

3. Content-type control that matches how you will use the data

  • All content returns the profile's mixed feed: photos, carousels, feed videos and Reels in one pass.
  • Posts only returns the same feed with explicit Reels removed.
  • Reels only uses the dedicated Reels feed rather than filtering the first page of a mixed one, so Reel-only runs are not limited by what happens to sit on top of the general feed.

4. Batch-friendly with de-duplication at two levels

Process up to 200 profiles in one run. Inputs are normalized before any work starts, so nasa, @nasa, https://www.instagram.com/nasa/ and a numeric user ID for the same account are recognized as the same profile and processed once — no repeated work, no duplicate rows, no duplicate charges. At the result level, the same media ID is delivered only once even across pagination and recovery.

If one profile in a batch fails, the rest of the batch continues. Failures are reported per profile in the run summary, so one bad input does not waste a 200-profile run.

5. Limits that control both Dataset size and cost

resultsLimit caps how many unique items are delivered per profile (1–1000, default 100). It is the main lever over both your Dataset size and your result fees: set it to what you actually need rather than leaving it high. How far back a profile can be read also depends on what the data source returns — this Actor does not claim to deliver an account's entire history.

Every row carries the Instagram media id and shortcode plus the canonical url, so you can de-duplicate against previous runs, join to your own tables, and trace any row back to the profile and input value that produced it. scrapedAt records when the row was collected.

🚀 Quick start

  1. Open the Actor's Input tab.
  2. Add one or more public Instagram profiles — usernames, @usernames, profile URLs, or numeric user IDs.
  3. Keep the defaults for a first run: contentType: all, resultsLimit: 100.
  4. Click Start. When the run finishes, open Output → Content.

For monitoring, set Only content published after to the last moment you already have (for example 2026-10-11T18:30:00Z). The run then returns only newer items and stops paginating once the feed is past that moment.

Minimal input:

{
"profiles": ["nasa", "@natgeo", "https://www.instagram.com/lego/"],
"contentType": "all",
"resultsLimit": 100
}

Incremental input — only what is new since yesterday evening:

{
"profiles": ["nasa"],
"contentType": "all",
"resultsLimit": 100,
"postedAfter": "2026-10-11T18:30:00Z"
}

Short output example

Each unique post or Reel is written as its own Dataset row. The example below is an illustrative example showing structure and field names — values are redacted, not from a live run.

{
"sourceUsername": "nasa",
"sourceProfileUrl": "https://www.instagram.com/nasa/",
"sourceProfileId": "528817151",
"type": "reel",
"url": "https://www.instagram.com/reel/XXXXXXXXXXX/",
"timestamp": "2026-10-12T15:04:00.000Z",
"caption": "Example caption text #hashtag",
"likesCount": 123456,
"commentsCount": 2345,
"viewsCount": 987654,
"videoUrl": "https://…example-video-url…",
"thumbnailUrl": "https://…example-thumbnail-url…",
"id": "3000000000000000000",
"shortcode": "XXXXXXXXXXX",
"contentType": "all",
"input": "nasa",
"scrapedAt": "2026-10-13T06:00:00.000Z"
}

Input

FieldTypeRequiredDefaultLimits / notes
profilesarray of stringsYesprefill: ["instagram"]1–200 values. Accepts usernames (nasa), @usernames, profile URLs (https://www.instagram.com/nasa/) and numeric Instagram user IDs. Normalized and de-duplicated before processing: the same profile is processed once, whatever form it arrived in.
contentTypestringNoallall (mixed feed: photos, carousels, feed videos, Reels), posts (same feed with explicit Reels removed), reels (dedicated Reels feed).
resultsLimitintegerNo1001–1000 unique items per profile. The main control over Dataset size and result fees.
postedAfterstringNoemptyCutoff for incremental runs. In the form, Absolute provides a YYYY-MM-DD calendar picker and Relative accepts a number of days, weeks, months, or years (e.g. 1 days, 2 months, 3 years). JSON also accepts ISO-8601 date-times such as 2026-10-11T18:30:00Z or 2026-10-11T08:00:00+08:00. Dates start at midnight UTC; relative values are resolved once at run start in UTC. Only items published strictly after that cutoff are returned. Invalid values fail with INVALID_POSTED_AFTER before processing.

How the fields interact:

  • postedAfter and resultsLimit work together: the cutoff decides which items qualify, the limit decides how many are delivered. When both are set, the run stops at whichever comes first.
  • postedAfter with zero new items is a successful run: the profile is reported as checked, and no content rows are written.
  • contentType: reels measures Reels directly from the Reels feed; it is not "the first page of the general feed, filtered".

Output

One row per unique post or Reel. The Dataset Views change only the column order and presentation, never the underlying rows:

  • All Content — the balanced overview: source, type, link, timestamp, caption, likes, comments, views, video and thumbnail.
  • Posts — photo and carousel oriented columns.
  • Reels — Reel oriented columns: views, duration, video URL, music.
  • Downloads — media URLs and identifiers for downloading or archiving.

Field reference

Core fields:

FieldTypeMeaning
sourceUsernamestring | nullUsername the item was collected from. Null when the profile was supplied as a numeric ID and nothing proved the username.
sourceProfileUrlstring | nullProfile URL the item was collected from.
sourceProfileIdstring | nullNumeric Instagram user ID of the source profile, when known. Stable across username changes.
typestringreel, photo, carousel, video, or unknown when the payload did not establish one. Never folded into another bucket.
urlstring | nullCanonical Instagram URL of the item.
timestampstring | nullPublication time, ISO-8601 UTC. Null when the payload carried no usable timestamp.
captionstring | nullCaption text, when present.
idstring | nullInstagram media ID — stable identifier for de-duplication and joins.
shortcodestring | nullInstagram shortcode; the slug used in the content URL.

Engagement and media fields:

FieldTypeMeaning
likesCountinteger | nullLike count, when reported.
commentsCountinteger | nullComment count, when reported.
viewsCountinteger | nullPlay/view count for video content, when reported. Null for content that reports none.
playsCountinteger | nullPlay count, when separately reported.
sharesCountinteger | nullShare count, when reported.
videoUrlstring | nullDirect video URL, when the payload returned one. Provider media URLs can expire — download promptly if you need the file.
thumbnailUrlstring | nullThumbnail or first-frame image.
imageUrlstring | nullDisplay image for photos and carousels.
durationnumber | nullVideo duration in seconds, when reported.

Context fields:

FieldTypeMeaning
hashtagsstring[]Hashtags parsed from the caption.
mentionsstring[]Usernames mentioned in the caption.
musicobject | nullAttached audio (title, artist) when the payload carried it.
locationobject | nullTagged location (id, name, city, address) when the payload carried one.
contentTypestringThe contentType setting this run used.
inputstringThe exact profile value you supplied that produced this row.
scrapedAtstringWhen the row was collected, ISO-8601 UTC.

Missing values are delivered as null, never as zero or placeholder text: a null likesCount means the source did not report one, which is different from a real count of zero.

Status and errors

Every run writes a RUN_SUMMARY record to the key-value store with per-run totals: profiles requested / processed / succeeded / failed, how many items the date filter removed, how many content rows were delivered (split into posts and Reels), how many pages and upstream calls were used, how many times the date filter stopped pagination early, and which inputs were rejected.

Run-level input errors fail the whole run before any profile is processed:

CodeMeaning
INVALID_REQUESTThe input could not be read.
BATCH_LIMIT_EXCEEDEDMore than 200 profiles in one run.
INVALID_POSTED_AFTERpostedAfter could not be parsed as an absolute date, an ISO-8601 instant, or a relative UTC duration.

Per-profile outcomes are reported in the summary; a failed profile does not stop the rest of the batch:

CodeMeaningRetry?
PROFILE_NOT_FOUNDThe profile could not be found.Check the username; no retry needed.
CONTENT_UNAVAILABLEPublic content is not available right now (for example a private or restricted account).Retry later may help.
UPSTREAM_RATE_LIMITED / UPSTREAM_QUOTA_EXHAUSTED / UPSTREAM_TIMEOUTA temporary data-source issue.Retry later.
MALFORMED_RESPONSE / UPSTREAM_ERRORA temporary data-source issue prevented this profile from being resolved.Retry later.
SERVICE_CONFIGURATION_ERRORNo data source was available because of a routing configuration issue. Nothing was requested upstream and nothing was charged.Do not retry: the Actor's routing configuration has to be fixed first.
INVALID_PROFILEThe value is not a usable Instagram profile.Fix the input.
FREE_USAGE_LIMIT_EXCEEDEDThe free usage allowance has been reached.See Pricing.
INTERNAL_ERRORThe profile could not be processed right now.Retry later.

Important, non-error outcomes:

  • Zero new items with postedAfter set — a successful check. The profile is counted as checked, no rows are written, and no result fee applies.
  • Reaching the natural end of a feed — a successful result, even when fewer items than resultsLimit are available.
  • Items older than your cutoff — filtered out by design; the summary reports how many were seen and how many were filtered.

💰 Pricing

This Actor uses pay-per-event pricing, so what you pay follows what the run actually delivered.

Result pricing (per 1,000 delivered posts or Reels)

Plancontent-result
Free$1.10
Bronze$1.00
Silver$0.80
Gold$0.60

That is $0.0011 per delivered item on the Free plan, down to $0.0006 on Gold. See the Actor's Pricing tab for the rates that apply to your account.

Date-filter processing fee

When you set postedAfter, every item the filter examines and removes is charged at $0.60 per 1,000 filtered items ($0.0006 per item) — the same on every plan. Content older than your cutoff counts, and so does content with no usable timestamp: both were fetched and judged on your behalf. A run where everything returned is new pays no filter fee at all.

Actor start fee

$0.001 per run, whatever the batch size.

How the billing works:

  • One result fee per unique post or Reel actually delivered. The unit is the row written to your Dataset — never a page, a request, or an attempt. resultsLimit is the main lever over this fee: lower it and you collect — and pay for — less.
  • One filter fee per item the date filter removed. Charged only when postedAfter is set, because that is the only mode in which items are filtered by date. A monitoring run that examined 100 old items and found 3 new ones pays 3 result fees plus 100 filter fees — roughly half of what delivering all 103 items would have cost.
  • One start fee per run, independent of how many profiles the run handles.

What you are never charged for:

  • Invalid input rejected before processing. A value that is not a usable profile produces no fee.
  • Duplicates. A profile listed twice — or listed once as a username and once as its numeric ID — is checked once and charged once.
  • Retries and recoveries. A temporary failure that is retried, or a profile resolved through a second attempt, does not create another fee for the same profile or the same item.
  • Items removed by content type. A Reel skipped in Posts-only mode is not date-filtered, so it never creates a filter fee.
  • Items beyond your limit. Anything past resultsLimit is never fetched, filtered or charged.
  • Pagination. How many pages a profile needed is never billed directly.

Cost example (Free-plan rates): a daily monitoring run over 5 profiles starts at $0.001. On a day where the run examined 300 items, removed 288 older ones and delivered 12 new posts, the total is 12 × $0.0011 + 288 × $0.0006 + $0.001 ≈ $0.19. On a quiet day where the same run examines 60 items and delivers nothing, it is 60 × $0.0006 + $0.001 ≈ $0.04. A plain archive run with no postedAfter — 100 items from one profile — is 100 × $0.0011 + $0.001 ≈ $0.11 with no filter fee.

Free-plan users

Free-plan users are subject to the current free usage allowance configured for this Actor. Paid users are not subject to that allowance. When a run reaches the allowance, the remaining profiles continue to be processed and the ones that were not served are reported explicitly in RUN_SUMMARY.

API usage

Run the Actor programmatically and retrieve the default Dataset when it finishes. Replace the sample profiles with your own.

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('lance_api/instagram-profile-posts-reels-scraper').call({
profiles: ['nasa', '@natgeo'],
contentType: 'all',
resultsLimit: 100,
postedAfter: '2026-10-11T18:30:00Z',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Python

from apify_client import ApifyClient
client = ApifyClient(token=os.environ['APIFY_TOKEN'])
run = client.actor('lance_api/instagram-profile-posts-reels-scraper').call(run_input={
'profiles': ['nasa', '@natgeo'],
'contentType': 'all',
'resultsLimit': 100,
'postedAfter': '2026-10-11T18:30:00Z',
})
for item in client.dataset(run['defaultDatasetId']).iterate_items():
print(item)

cURL

curl -X POST \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"profiles": ["nasa", "@natgeo"],
"contentType": "all",
"resultsLimit": 100,
"postedAfter": "2026-10-11T18:30:00Z"
}' \
"https://api.apify.com/v2/acts/lance_api~instagram-profile-posts-reels-scraper/runs?waitForFinish=120"

Fetch the default Dataset of the finished run:

$curl "https://api.apify.com/v2/datasets/{datasetId}/items?format=json"

Use cases

  • New-content monitoring. Schedule the Actor daily with postedAfter set to your last checkpoint and receive only what was published since — without re-collecting and re-paying for the same posts on every run.
  • Competitor content tracking. Collect the recent posts and Reels of competitor profiles into your own store and compare posting volume, formats and captions over time.
  • Creator content review at scale. Pull the recent output of a shortlist of creators and review formats, cadence and captions in a spreadsheet before outreach.
  • Reels research. Run with contentType: reels to study a profile's Reel output specifically — views, duration and music — rather than a mixed feed.
  • Content archiving. Use resultsLimit and the Downloads view to capture posts, images and video URLs for an internal archive, downloading media before the URLs expire.
  • Feeding analytics pipelines. Every row carries stable IDs, timestamps and engagement counts, so the Dataset drops straight into a database, dashboard or BI tool.
  • UGC and mention sourcing. Use captions, hashtags, mentions and location fields to find brand-relevant public content for outreach or research.

How it works

  1. You submit profiles in any supported form.
  2. The Actor validates, normalizes and de-duplicates them, so the same profile is processed once.
  3. For each profile it collects the requested content type, normalizing every item into a stable row shape.
  4. When postedAfter is set, items are filtered page by page and pagination stops once the feed has moved past your cutoff.
  5. Unique items are written to the Dataset, and the run summary reports totals, checks, filtered counts and failures.
If you need to…Recommended Actor
Evaluate a creator's followers, engagement rate and posting cadenceInstagram Creator & Engagement Scraper
Look up profile metadata, bio and public contact detailsInstagram Profile Scraper API
Collect comments and replies from posts and ReelsInstagram Comments Scraper API
Find who liked a post or ReelInstagram Likers Scraper API
Download Reels and videos as filesInstagram Reels Downloader – Fast Batch API
Collect content by hashtagInstagram Hashtag Scraper API

Explore more Instagram data Actors from lance_api on Apify.

FAQ

Which profile formats are accepted? Usernames (nasa), @usernames (@nasa), profile URLs (https://www.instagram.com/nasa/) and numeric Instagram user IDs. All forms of the same profile are recognized and processed once.

Do I need a login or cookie? No. This Actor works with publicly available data only. Never send tokens, cookies or sessions to support.

Is postedAfter inclusive or exclusive? Exclusive. Only items published strictly after the moment are returned. An item published at exactly 2026-10-11T18:30:00Z is excluded when the cutoff is that same moment.

What date formats does postedAfter accept? Use Absolute to select a date with the calendar (YYYY-MM-DD, interpreted as midnight UTC), or Relative to choose days, weeks, months, or years before run start, for example 1 days, 2 months, or 3 years. JSON can also supply ISO-8601 date-times with a timezone (2026-10-11T18:30:00Z, 2026-10-11T08:00:00+08:00). All time values are taken in UTC timezone. The relative cutoff is resolved once per run, so scheduled runs automatically move the window forward. Days/weeks use elapsed UTC days; months/years use calendar subtraction, keeping the UTC time of day and clamping to the last valid day when needed (March 31 minus one month becomes February 28 or 29). 0 days means the run start time. Invalid values fail with INVALID_POSTED_AFTER before any profile is processed.

What happens when there are no new posts? The run succeeds. The profile is reported as checked, no content rows are written, and no result fees apply — the only charge is the filter fee for the items the cutoff examined and removed. The profile is not retried against other data sources: an empty result is an answer, not a failure.

Can I get an account's entire post history? No guarantee. The Actor delivers up to resultsLimit unique items per profile, and how far back the feed can actually be read depends on what the data source returns. Do not market or plan against "complete history".

How are pinned posts handled with postedAfter? A pinned item is never allowed to trigger the early stop, so a pinned old post at the top of a feed cannot hide newer content below it.

What happens to items with no timestamp when postedAfter is set? They are not delivered. An item without a usable timestamp cannot be proven to be newer than your cutoff, so it is excluded rather than guessed, and the count is reported in the run summary.

Are duplicate profiles charged twice? No. Repeated references to the same profile — in any supported form — are normalized to one profile, processed once, and charged once.

Are duplicate results possible? The same media ID is delivered once per run, even across pagination and recovery. Two different posts with identical captions remain separate rows.

If one profile fails, does the whole run fail? No. Each profile is processed independently; failures are reported per profile in RUN_SUMMARY and the rest of the batch continues.

Why are some counts null? The source did not report them. Null means "not reported", which is different from zero — this keeps your analysis honest.

How long do media URLs stay valid? Video and image URLs come from the source and can expire. Download media promptly if you need the files; the metadata rows remain valid.

How do I control cost? Lower resultsLimit to what you need, use postedAfter for scheduled runs so old items are charged at the lower filter rate instead of the full result rate, and remember that duplicates, type-filtered items, over-limit items and failed profiles never create a result fee.

Limitations

  • Public data only. Private, restricted or deleted profiles and content cannot be collected.
  • Content availability, counts and media URLs depend on what the source returns at run time and can change without notice.
  • History depth is not guaranteed: the Actor delivers up to resultsLimit unique items per profile, and the readable depth of a feed depends on the source.
  • Counts such as likes, comments, views and shares are reported only when the source reports them; missing values are null.
  • Direct media URLs can expire; download promptly when you need the files.
  • The Actor does not log in, does not bypass access controls, and does not guarantee a fixed number of results per profile.

Public data and responsible use

This Actor collects only publicly available data. You are responsible for complying with applicable laws, Instagram's terms of service, and the privacy and copyright expectations that apply to your use case — including how you store, share and republish collected content, and for avoiding spam or automated abuse of the platform.

Support

Open an issue on the Actor page or email lanceapi2026@hotmail.com.

For a bug report, include:

  • Apify Run ID
  • a non-sensitive Instagram profile you used
  • the input fields you set
  • the relevant status or error code from RUN_SUMMARY, if available
  • what you expected and what actually happened

Do not send:

  • Apify Token or APIFY_TOKEN
  • Cookie
  • Session ID
  • Password
  • API Key
  • Proxy credentials
  • Authorization header