# Instagram Location Posts Scraper | $0.48/1K Posts + $0.004/Page (`publicsignallabs/instagram-location-posts-scraper`) Actor

Explore what people share from selected Instagram locations. Collect Recent and Top posts and Reels with captions, available engagement figures and media links for local trend, venue and content research. No Instagram login required.

- **URL**: https://apify.com/publicsignallabs/instagram-location-posts-scraper.md
- **Developed by:** [Public Signal Labs](https://apify.com/publicsignallabs) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.48 / 1,000 location medias

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Instagram Location Posts Scraper | $0.48/1K Posts + $0.004/Page

**See what people are sharing from the places that matter to your research.** Collect Recent and Top Instagram posts and Reels from selected locations to explore local trends, compare venues or research location-based content.

Export captions, available engagement figures and image/video links for analysis. Start with an Instagram location link or ID; no Instagram login or technical setup required.

### Quick start

```json
{
  "locations": ["213385402"],
  "streams": ["recent"],
  "maxPagesPerLocation": 1,
  "maxItems": 100,
  "enrichProfiles": false
}
```

For both observed memberships, select both streams and allow at least two pages:

```json
{
  "locations": ["https://www.instagram.com/explore/locations/213385402/"],
  "streams": ["recent", "top"],
  "maxPagesPerLocation": 2,
  "maxItems": 100,
  "enrichProfiles": true
}
```

Run in Apify Console, through an integration, or with the Apify CLI:

```sh
apify actors call publicsignallabs/instagram-location-posts-scraper \
  -i '{"locations":["213385402"],"streams":["recent"],"maxPagesPerLocation":1,"maxItems":100}' \
  --output-dataset
```

For API integrations, submit the same JSON body to the Actor's run endpoint, inspect the resulting run's default dataset, and read `OUTPUT` and `AUDIT` from its default key-value store. Supply your own Apify authorization securely; never put credentials in input. Review access to your run storage before sharing exports. Private review builds are available only to authorized reviewers.

Example HTTP request body, using the standard [Apify Run Actor API](https://docs.apify.com/api/v2/actors-runs-post):

```http
POST https://api.apify.com/v2/actors/publicsignallabs~instagram-location-posts-scraper/runs
Content-Type: application/json

{"locations":["213385402"],"streams":["recent"],"maxPagesPerLocation":1,"maxItems":100}
```

Use your client's secure authorization configuration. The run response is asynchronous; wait for its terminal status before exporting the dataset.

### Input

| Field | Contract |
|---|---|
| `locations` | Required, 1–10 strings. Positive numeric IDs or HTTPS `instagram.com`/`www.instagram.com` `/explore/locations/<id>/` URLs, optionally followed by one location slug. No arbitrary URLs, credentials, query strings or fragments. Equivalent references are merged locally; first input and zero-based index are preserved. No location lookup is performed. |
| `streams` | `['recent']` by default; select `recent`, `top`, or both without duplicates. Order controls first stream and round-robin paging. |
| `maxPagesPerLocation` | Integer 1–100, default 1. **Combined across selected streams per place per run**, not 100 pages per stream. Every attempted page counts toward this work bound. |
| `maxItems` | Integer 1–1,000, default 100. Maximum unique `(place, media_id)` saved rows across the entire run. Same media at two places is two distinct result rows. |
| `enrichProfiles` | Boolean, default false. Optional matching owner-profile lookups, deduplicated including failures within the run. Complete profiles already included in extracted rows are reused. |
| `continuationToken` | Optional opaque token from `OUTPUT`; paying runs only. Valid for 15 minutes, bound to normalized ordered locations, selected stream order and enrichment setting. Result/page limits may change. |

All input is validated before FREE admission or extraction. Unknown fields, booleans used as integer limits, unsupported references and conflicting FREE options are rejected. Unobserved optional facts remain null or absent, never invented zeros or verified empty lists.

#### Ordering and bounds

Locations follow first-input order. Each place is buffered before persistence so Top/Recent overlap has one row with merged **observed** memberships. New media follow first-seen order; ranks are one-based positions in their extraction stream, including unsupported positions and duplicates encountered before them. Only the first observed rank for each stream is retained. Rank reflects an observation, not a stable historical ranking.

Each page is bounded to 1,000 entries and 4 MiB decoded JSON; each place's normalized result buffer is bounded to 1,000 rows and 8 MiB, including added enrichment. Larger responses stop that selected extraction with `page_size_limit`; a full buffer saves its affordable prefix and reports `buffer_limit`. Matching additional profiles are bounded to 256 KiB each and an 8 MiB successful-lookup cache; an oversized lookup does not replace basic media. The finite run request bound includes selected pages and at most one optional lookup per saved owner. Internal validation can clamp that bound further. No automatic fallback route or retry is used.

### Output and exports

The default dataset contains one row per `(source_place.id, media_id)`. Export JSON for nested assets/context or flatten selected fields in CSV/XLSX. Console output links point to the dataset, run summary and reconciliation audit.

**Enrichment required?** “No” means the field comes from the location's posts or is calculated locally; missing optional facts remain empty. `enrichProfiles=true` can add owner details to `owner_profile`. It does not enrich post engagement, media, the source location or a distinct caption author.

| Fields | Meaning and optionality | Enrichment required? |
|---|---|---|
| `media_id`, `id`, `shortcode`, `url`, `media_type` | Canonical matching feed-media identity, Instagram post/Reel URL and `image`/`video`/`carousel` kind. Required identity/kind failures reject the individual row. `id` is the shared canonical media identifier. | No. |
| `product_type`, `published_at`, `fetched_at` | Supplied product kind and publication time; publication may be null. Fetch time uses one fixed UTC observation clock per run. | No. |
| `source_place` | Source ID, canonical URL, first normalized input and input index; not a separately enriched place. Embedded content location remains separate. | No; `enrichProfiles` does not enrich places. |
| `streams`, `ranks` | Observed Recent/Top memberships and first one-based rank in each stream. Unvisited streams are not claimed. | No. |
| `caption`, `context.hashtags`, `context.mentions` | Supplied caption and supported locally parsed/supplied tags and mentions. | No. |
| `owner`, `owner_id`, `owner_username`, `owner_full_name`, `owner_profile_pic_url`, `owner_is_private`, `owner_is_restricted`, `owner_is_verified` | Already supplied owner facts and privacy flags; optional and not an eligibility filter. | No — these base owner fields are not rewritten by enrichment. |
| `owner_profile` | Included owner profile facts; optional matching enrichment can add biography, follower/following/post counts and other available profile details. | Optional — `enrichProfiles` adds details not already supplied; existing profile facts do not require it. |
| `caption_author_profile` | A distinct caption author's profile facts, when supplied with the post. | No; `enrichProfiles` does not look up a distinct caption author. |
| `enrichment_outcome` | `not_requested`, `included`, `succeeded`, `not_available`, or `failed`. `included` means profile facts were already returned or unchanged. | No — reports `not_requested` when enrichment is off. |
| `coauthors`, `user_tags`, `sponsor_tags` | Supplied collaborators, tagged users and sponsor tags, when present. | No. |
| `title`, `accessibility_caption`, `width`, `height`, `duration_seconds`, `audio` | Flat supplied media facts as the matching feed-media contract exposes them; `assets` keeps the richer per-variant breakdown. Optional and absent when unobserved. | No. |
| `engagement` | Nullable likes, comments, plays, views, shares and hidden-count flags. Hidden like/view/play counters remain null. Absence is not zero. | No; enrichment does not recover hidden counts. |
| `assets` | Supplied image/video variants with URL/dimensions/type, nullable width/height/duration and supplied audio facts. `display_url`/`video_url` are convenient shared canonical best variants. | No. |
| `carousel_items`, `children` | Supplied carousel relationships; `carousel_items` retains positional rich assets/context and optional child ID. | No. |
| `context` | Supplied caption, hashtags, mentions, links/domains, embedded location/locations, sponsors/partnership, supported stickers and referenced reshared media. Unsupported/absent optional structures remain null; this is not exhaustive sticker analysis. | No. |
| `is_private`, `is_restricted` | Record-level flags when actually supplied; retained without filtering. | No. |

Illustrative shortened row; values are examples, not a current extraction:

```json
{
  "media_id": "3900000000000000001",
  "id": "3900000000000000001",
  "shortcode": "EXAMPLE1",
  "url": "https://www.instagram.com/p/EXAMPLE1/",
  "media_type": "image",
  "published_at": null,
  "fetched_at": "2026-10-01T12:00:00Z",
  "source_place": {"id": "213385402", "url": "https://www.instagram.com/explore/locations/213385402/", "input": "213385402", "input_index": 0},
  "streams": ["recent", "top"],
  "ranks": {"recent": 3, "top": 1},
  "owner_is_private": true,
  "engagement": {"like_count": null, "comment_count": null, "play_count": null, "view_count": null, "share_count": null, "like_count_hidden": true, "view_count_hidden": true},
  "enrichment_outcome": "not_requested"
}
```

Asset URLs can be signed or temporary and may expire. They are links, not durable downloaded files. Nested references and carousel children are context within one result, not independent results. No Google reviews, date filtering, custom mapping, private-access promise, historical archive, OCR, transcript, viewer/reach/impression data or durable downloads are offered.

#### Summary and expected outcomes

`OUTPUT` contains `status`, `stopReason`, `deliveredCount`, `chargedCount`, `pageChargedCount`, `profileChargedCount`, `eventCounts`, `sources`, `bufferPeakBytes`, and optional `continuationToken`/FREE admission. Each source records location ID, original input index, completed pages, observed/rejected entries, delivered rows, status and a specific stop reason where needed. `AUDIT` contains sanitized extraction attempts, response bytes, duration, confirmed event/delivery counts, buffer size and recovery reconciliation; it does not expose raw request or response records.

Valid empty pages and missing/unavailable extraction have distinct successful outcomes. `duplicate_only` is not a claim that the location is empty. Result/page/spend/request/buffer limits and partial prefixes are successful runs. Mechanical configuration, input, internal invariants and storage/reporting dependency failures retain truthful failure/reconciliation details. A partial accepted write reports only its confirmed prefix; ambiguous writes/charges are not silently retried. Check summary and reconciliation rather than interpreting every successful run as exhaustive collection.

#### Continuation

Continue by resubmitting the same locations, streams and enrichment setting with the returned token. You can change `maxItems` and `maxPagesPerLocation`. A token carries bounded progress, stream cursors, mid-page offsets, an ordered page-identity fingerprint and IDs of **confirmed saved** results. A newly started unrelated run has no shared history.
An unfinished mid-page checkpoint is resumed before another stream page. Previously saved rows are append-only: later observations do not rewrite their memberships.

Mid-page resume performs a new page extraction. The ordered identity fingerprint must match before an offset is used. If the snapshot changed, the run reports successful `snapshot_changed`, does not skip by a stale offset, and does not issue a continuation for that unsafe checkpoint. This is not a valid-empty response or an immutable historical snapshot. Start a fresh run only if you deliberately want a new observation.

Null cursors terminate streams; repeated cursors stop with `repeated_cursor` instead of looping. Empty pages with a genuine next cursor can continue. Tokens are not issued on invalid snapshot/repeated-cursor stops, uncertain mutations, exhausted bounded state or FREE runs. Dedup state is capped at 10,000 IDs and encrypted state at 256 KiB; exhausted state reports its limit rather than dropping IDs and duplicating paid rows. Invalid/tampered/expired/mismatched tokens fail before admission/extraction. Do not edit or publish tokens.

When the bounded cursor history or encrypted continuation size is exhausted, `stopReason` is `page_limit`; a missing continuation token means that checkpoint cannot be resumed safely.

### Pricing

**The headline is the result price, not an all-in invoice.** Saved posts, completed pages, optional profile enrichment and the automatic start event contribute to the total. For example, 100 saved posts across four pages without enrichment cost **$0.06405**.

USD Starter event schedule:

| Event | Price | Billing boundary |
|---|---:|---|
| `location-media` — primary | $0.00048 ($0.48/1K) | Each unique place/media row confirmed saved. Top/Recent overlap at one place is one result; carousel children are included. |
| `location-page` | $0.004 | Structurally valid completed page, including empty, duplicate-only and individually rejected entries. Unavailable, failed or malformed pages are not charged. A completed mid-page re-extraction is new page work, including when its identity snapshot changed. |
| `profile-enrichment` — optional | $0.0055 | Successful matching incremental owner lookup delivered with at least one saved row; once per owner per run. No charge for included copied facts, unavailable/failed lookups or unperformed work. |
| `apify-actor-start` | $0.00005 | Automatic platform start at at most 1 GB; not manually charged. |

There is no additional default-dataset-item event and no customer-paid platform-usage fee in this offer. The full bill depends on observed pages and unique enriched owners, not just saved posts. 100 posts, four pages and ten successful unique owner enrichments cost **$0.11905**. One valid empty page costs **$0.00405**, including start. Page fees are charged after completed valid work and before result storage. Event capacities and the combined spending allowance are checked before paid work; a spending stop saves only its confirmed affordable prefix. A concurrent limit or exceptional save/charge ambiguity can require explicit reconciliation, not fictional delivered or refunded counts.

**Mid-page resume incurs another $0.004 page fee** for the completed re-extraction, including when its identity snapshot changed. Previously confirmed saved rows are not charged again within the continuation's dedup scope; a fresh unrelated run has its own result fees. Complete included profiles and oversized profile lookups do not incur an enrichment fee.

#### FREE demo

Nonpaying accounts may be admitted to **five runs per Actor/user/UTC month** through atomic author-managed quota storage. Each admitted run selects **one location, Recent only, one page, at most ten saved rows, one extraction attempt, no profile enrichment and no continuation**. Missing identity/quota configuration or a quota outage fails closed; resurrected/aborted admitted runs cannot claim another slot or replay work. Paying users bypass this monthly demo quota but still obey workload and spending limits. Demo admission is not a promise of a particular invoice: consult the effective Apify Pricing and run billing for any automatic start/event treatment.

### Responsible use and support

No affiliation with Instagram or Meta is implied. Follow applicable law, Instagram terms and your organization's privacy policy; avoid publishing personal information or private/restricted content without a lawful basis. Availability and supplied fields can change.

For help, use the Actor's **Apify Issues tab** and include the run ID plus sanitized expected/actual details. Do not send credentials, cookies, signed asset links, continuation tokens or private contact data.

# Actor input Schema

## `locations` (type: `array`):

1–10 numeric location IDs or canonical https://www.instagram.com/explore/locations/<id>/ URLs. Equivalent references are merged locally. Place search is not performed.

## `streams` (type: `array`):

Select Recent, Top, or both. Page limits are combined across selected streams, visited in this order with round-robin pagination.

## `maxPagesPerLocation` (type: `integer`):

1–100 attempted pages per place per run, combined across selected streams. Only valid completed pages are charged $0.004 each, including empty and duplicate-only pages.

## `maxItems` (type: `integer`):

1–1,000 unique place/media rows per run. FREE runs save at most ten. Carousel children are included within one paid row.

## `enrichProfiles` (type: `boolean`):

Optional matching profile lookup, $0.0055 per successfully enriched owner delivered once per run. Already returned complete profiles are included without a lookup fee. Unavailable lookups retain basic posts. Not available in FREE runs.

## `continuationToken` (type: `string`):

Optional OUTPUT token valid for 15 minutes; binds locations, streams and enrichment. Limits may change. Mid-page continuation re-extracts the completed page as new $0.004 work and verifies ordered identities before using its offset. No historical snapshot guarantee. Paid runs only.

## Actor input object example

```json
{
  "locations": [
    "213385402"
  ],
  "streams": [
    "recent"
  ],
  "maxPagesPerLocation": 1,
  "maxItems": 100,
  "enrichProfiles": false
}
```

# Actor output Schema

## `posts` (type: `string`):

Unique saved media per place, including observed stream memberships and rich media.

## `summary` (type: `string`):

Delivered and billed counts, per-place outcomes, FREE admission and optional continuation token.

## `audit` (type: `string`):

Extraction counts, response bytes, duration, confirmed event counts and recovery reconciliation.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "locations": [
        "213385402"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("publicsignallabs/instagram-location-posts-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "locations": ["213385402"] }

# Run the Actor and wait for it to finish
run = client.actor("publicsignallabs/instagram-location-posts-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "locations": [
    "213385402"
  ]
}' |
apify call publicsignallabs/instagram-location-posts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,publicsignallabs/instagram-location-posts-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/mFG0yqir5p59CWNqr/builds/OT3itBsNuL1ZJqSWj/openapi.json
